2 *****************************************************************************
4 Implementation of interfaces for the TinyRAM argument decoder gadget.
6 See argument_decoder_gadget.hpp .
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 *****************************************************************************/
14 #ifndef ARGUMENT_DECODER_GADGET_TCC_
15 #define ARGUMENT_DECODER_GADGET_TCC_
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)
37 , packed_registers(packed_registers)
38 , packed_desval(packed_desval)
39 , packed_arg1val(packed_arg1val)
40 , packed_arg2val(packed_arg2val)
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());
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"));
53 pack_desidx.reset(new packing_gadget<FieldT>(
57 FMT(this->annotation_prefix, "pack_desidx")));
58 pack_arg1idx.reset(new packing_gadget<FieldT>(
62 FMT(this->annotation_prefix, "pack_arg1idx")));
63 pack_arg2idx.reset(new packing_gadget<FieldT>(
67 FMT(this->annotation_prefix, "pack_arg2idx")));
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"));
74 demux_des.reset(new loose_multiplexing_gadget<FieldT>(
80 FMT(this->annotation_prefix, " demux_des")));
81 demux_arg1.reset(new loose_multiplexing_gadget<FieldT>(
87 FMT(this->annotation_prefix, " demux_arg1")));
88 demux_arg2.reset(new loose_multiplexing_gadget<FieldT>(
94 FMT(this->annotation_prefix, " demux_arg2")));
97 template<typename FieldT>
98 void argument_decoder_gadget<FieldT>::generate_r1cs_constraints()
101 pack_desidx->generate_r1cs_constraints(true);
102 pack_arg1idx->generate_r1cs_constraints(true);
103 pack_arg2idx->generate_r1cs_constraints(true);
106 demux_des->generate_r1cs_constraints();
107 demux_arg1->generate_r1cs_constraints();
108 demux_arg2->generate_r1cs_constraints();
110 /* enforce correct handling of arg2val */
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)},
119 FMT(this->annotation_prefix, " ensure_correc_demux"));
122 arg2val = arg2_is_imm * packed_arg2idx +
123 (1 - arg2_is_imm) * arg2_demux_result
125 arg2val - arg2_demux_result = arg2_is_imm * (packed_arg2idx -
128 this->pb.add_r1cs_constraint(
129 r1cs_constraint<FieldT>(
131 {packed_arg2idx, arg2_demux_result * (-1)},
132 {packed_arg2val, arg2_demux_result * (-1)}),
133 FMT(this->annotation_prefix, " compute_arg2val"));
136 template<typename FieldT>
137 void argument_decoder_gadget<FieldT>::generate_r1cs_witness()
140 pack_desidx->generate_r1cs_witness_from_bits();
141 pack_arg1idx->generate_r1cs_witness_from_bits();
142 pack_arg2idx->generate_r1cs_witness_from_bits();
145 demux_des->generate_r1cs_witness();
146 demux_arg1->generate_r1cs_witness();
147 demux_arg2->generate_r1cs_witness();
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));
156 template<typename FieldT> void test_argument_decoder_gadget()
158 libff::print_time("starting argument_decoder_gadget test");
160 tinyram_architecture_params ap(16, 16);
162 P.instructions = generate_tinyram_prelude(ap);
163 tinyram_protoboard<FieldT> pb(ap, P.size(), 0, 10);
165 pb_variable_array<FieldT> packed_registers;
166 packed_registers.allocate(pb, ap.k, "packed_registers");
168 pb_variable<FieldT> arg2_is_imm;
169 arg2_is_imm.allocate(pb, "arg_is_imm");
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");
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");
181 argument_decoder_gadget<FieldT> g(
193 g.generate_r1cs_constraints();
194 for (size_t i = 0; i < ap.k; ++i) {
195 pb.val(packed_registers[i]) = FieldT(1000 + i);
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();
203 desidx.generate_r1cs_witness_from_packed();
204 arg1idx.generate_r1cs_witness_from_packed();
205 arg2idx.generate_r1cs_witness_from_packed();
207 g.generate_r1cs_witness();
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");
215 pb.val(arg2_is_imm) = FieldT::one();
216 g.generate_r1cs_witness();
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");
224 libff::print_time("argument_decoder_gadget tests successful");
227 } // namespace libsnark
229 #endif // ARGUMENT_DECODER_GADGET_TCC_