Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
argument_decoder_gadget.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3 
4  Implementation of interfaces for the TinyRAM argument decoder gadget.
5 
6  See argument_decoder_gadget.hpp .
7 
8  *****************************************************************************
9  * @author This file is part of libsnark, developed by SCIPR Lab
10  * and contributors (see AUTHORS).
11  * @copyright MIT license (see LICENSE file)
12  *****************************************************************************/
13 
14 #ifndef ARGUMENT_DECODER_GADGET_TCC_
15 #define ARGUMENT_DECODER_GADGET_TCC_
16 
17 namespace libsnark
18 {
19 
20 template<typename FieldT>
21 argument_decoder_gadget<FieldT>::argument_decoder_gadget(
22  tinyram_protoboard<FieldT> &pb,
23  const pb_variable<FieldT> &arg2_is_imm,
24  const pb_variable_array<FieldT> &desidx,
25  const pb_variable_array<FieldT> &arg1idx,
26  const pb_variable_array<FieldT> &arg2idx,
27  const pb_variable_array<FieldT> &packed_registers,
28  const pb_variable<FieldT> &packed_desval,
29  const pb_variable<FieldT> &packed_arg1val,
30  const pb_variable<FieldT> &packed_arg2val,
31  const std::string &annotation_prefix)
32  : tinyram_standard_gadget<FieldT>(pb, annotation_prefix)
33  , arg2_is_imm(arg2_is_imm)
34  , desidx(desidx)
35  , arg1idx(arg1idx)
36  , arg2idx(arg2idx)
37  , packed_registers(packed_registers)
38  , packed_desval(packed_desval)
39  , packed_arg1val(packed_arg1val)
40  , packed_arg2val(packed_arg2val)
41 {
42  assert(desidx.size() == pb.ap.reg_arg_width());
43  assert(arg1idx.size() == pb.ap.reg_arg_width());
44  assert(arg2idx.size() == pb.ap.reg_arg_or_imm_width());
45 
46  /* decode accordingly */
47  packed_desidx.allocate(pb, FMT(this->annotation_prefix, " packed_desidx"));
48  packed_arg1idx.allocate(
49  pb, FMT(this->annotation_prefix, " packed_arg1idx"));
50  packed_arg2idx.allocate(
51  pb, FMT(this->annotation_prefix, " packed_arg2idx"));
52 
53  pack_desidx.reset(new packing_gadget<FieldT>(
54  pb,
55  desidx,
56  packed_desidx,
57  FMT(this->annotation_prefix, "pack_desidx")));
58  pack_arg1idx.reset(new packing_gadget<FieldT>(
59  pb,
60  arg1idx,
61  packed_arg1idx,
62  FMT(this->annotation_prefix, "pack_arg1idx")));
63  pack_arg2idx.reset(new packing_gadget<FieldT>(
64  pb,
65  arg2idx,
66  packed_arg2idx,
67  FMT(this->annotation_prefix, "pack_arg2idx")));
68 
69  arg2_demux_result.allocate(
70  pb, FMT(this->annotation_prefix, " arg2_demux_result"));
71  arg2_demux_success.allocate(
72  pb, FMT(this->annotation_prefix, " arg2_demux_success"));
73 
74  demux_des.reset(new loose_multiplexing_gadget<FieldT>(
75  pb,
76  packed_registers,
77  packed_desidx,
78  packed_desval,
79  ONE,
80  FMT(this->annotation_prefix, " demux_des")));
81  demux_arg1.reset(new loose_multiplexing_gadget<FieldT>(
82  pb,
83  packed_registers,
84  packed_arg1idx,
85  packed_arg1val,
86  ONE,
87  FMT(this->annotation_prefix, " demux_arg1")));
88  demux_arg2.reset(new loose_multiplexing_gadget<FieldT>(
89  pb,
90  packed_registers,
91  packed_arg2idx,
92  arg2_demux_result,
93  arg2_demux_success,
94  FMT(this->annotation_prefix, " demux_arg2")));
95 }
96 
97 template<typename FieldT>
98 void argument_decoder_gadget<FieldT>::generate_r1cs_constraints()
99 {
100  /* pack */
101  pack_desidx->generate_r1cs_constraints(true);
102  pack_arg1idx->generate_r1cs_constraints(true);
103  pack_arg2idx->generate_r1cs_constraints(true);
104 
105  /* demux */
106  demux_des->generate_r1cs_constraints();
107  demux_arg1->generate_r1cs_constraints();
108  demux_arg2->generate_r1cs_constraints();
109 
110  /* enforce correct handling of arg2val */
111 
112  /* it is false that arg2 is reg and demux failed:
113  (1 - arg2_is_imm) * (1 - arg2_demux_success) = 0 */
114  this->pb.add_r1cs_constraint(
115  r1cs_constraint<FieldT>(
116  {ONE, arg2_is_imm * (-1)},
117  {ONE, arg2_demux_success * (-1)},
118  {ONE * 0}),
119  FMT(this->annotation_prefix, " ensure_correc_demux"));
120 
121  /*
122  arg2val = arg2_is_imm * packed_arg2idx +
123  (1 - arg2_is_imm) * arg2_demux_result
124 
125  arg2val - arg2_demux_result = arg2_is_imm * (packed_arg2idx -
126  arg2_demux_result)
127  */
128  this->pb.add_r1cs_constraint(
129  r1cs_constraint<FieldT>(
130  {arg2_is_imm},
131  {packed_arg2idx, arg2_demux_result * (-1)},
132  {packed_arg2val, arg2_demux_result * (-1)}),
133  FMT(this->annotation_prefix, " compute_arg2val"));
134 }
135 
136 template<typename FieldT>
137 void argument_decoder_gadget<FieldT>::generate_r1cs_witness()
138 {
139  /* pack */
140  pack_desidx->generate_r1cs_witness_from_bits();
141  pack_arg1idx->generate_r1cs_witness_from_bits();
142  pack_arg2idx->generate_r1cs_witness_from_bits();
143 
144  /* demux */
145  demux_des->generate_r1cs_witness();
146  demux_arg1->generate_r1cs_witness();
147  demux_arg2->generate_r1cs_witness();
148 
149  /* handle arg2val */
150  this->pb.val(packed_arg2val) =
151  (this->pb.val(arg2_is_imm) == FieldT::one()
152  ? this->pb.val(packed_arg2idx)
153  : this->pb.val(arg2_demux_result));
154 }
155 
156 template<typename FieldT> void test_argument_decoder_gadget()
157 {
158  libff::print_time("starting argument_decoder_gadget test");
159 
160  tinyram_architecture_params ap(16, 16);
161  tinyram_program P;
162  P.instructions = generate_tinyram_prelude(ap);
163  tinyram_protoboard<FieldT> pb(ap, P.size(), 0, 10);
164 
165  pb_variable_array<FieldT> packed_registers;
166  packed_registers.allocate(pb, ap.k, "packed_registers");
167 
168  pb_variable<FieldT> arg2_is_imm;
169  arg2_is_imm.allocate(pb, "arg_is_imm");
170 
171  dual_variable_gadget<FieldT> desidx(pb, ap.reg_arg_width(), "desidx");
172  dual_variable_gadget<FieldT> arg1idx(pb, ap.reg_arg_width(), "arg1idx");
173  dual_variable_gadget<FieldT> arg2idx(
174  pb, ap.reg_arg_or_imm_width(), "arg2idx");
175 
176  pb_variable<FieldT> packed_desval, packed_arg1val, packed_arg2val;
177  packed_desval.allocate(pb, "packed_desval");
178  packed_arg1val.allocate(pb, "packed_arg1val");
179  packed_arg2val.allocate(pb, "packed_arg2val");
180 
181  argument_decoder_gadget<FieldT> g(
182  pb,
183  packed_registers,
184  arg2_is_imm,
185  desidx.bits,
186  arg1idx.bits,
187  arg2idx.bits,
188  packed_desval,
189  packed_arg1val,
190  packed_arg2val,
191  "g");
192 
193  g.generate_r1cs_constraints();
194  for (size_t i = 0; i < ap.k; ++i) {
195  pb.val(packed_registers[i]) = FieldT(1000 + i);
196  }
197 
198  pb.val(desidx.packed) = FieldT(2);
199  pb.val(arg1idx.packed) = FieldT(5);
200  pb.val(arg2idx.packed) = FieldT(7);
201  pb.val(arg2_is_imm) = FieldT::zero();
202 
203  desidx.generate_r1cs_witness_from_packed();
204  arg1idx.generate_r1cs_witness_from_packed();
205  arg2idx.generate_r1cs_witness_from_packed();
206 
207  g.generate_r1cs_witness();
208 
209  assert(pb.val(packed_desval) == FieldT(1002));
210  assert(pb.val(packed_arg1val) == FieldT(1005));
211  assert(pb.val(packed_arg2val) == FieldT(1007));
212  assert(pb.is_satisfied());
213  printf("positive test (get reg) successful\n");
214 
215  pb.val(arg2_is_imm) = FieldT::one();
216  g.generate_r1cs_witness();
217 
218  assert(pb.val(packed_desval) == FieldT(1002));
219  assert(pb.val(packed_arg1val) == FieldT(1005));
220  assert(pb.val(packed_arg2val) == FieldT(7));
221  assert(pb.is_satisfied());
222  printf("positive test (get imm) successful\n");
223 
224  libff::print_time("argument_decoder_gadget tests successful");
225 }
226 
227 } // namespace libsnark
228 
229 #endif // ARGUMENT_DECODER_GADGET_TCC_