2 *****************************************************************************
4 Implementation of interfaces for the TinyRAM consistency enforcer gadget.
6 See consistency_enforcer_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 CONSISTENCY_ENFORCER_GADGET_TCC_
15 #define CONSISTENCY_ENFORCER_GADGET_TCC_
20 template<typename FieldT>
21 consistency_enforcer_gadget<FieldT>::consistency_enforcer_gadget(
22 tinyram_protoboard<FieldT> &pb,
23 const pb_variable_array<FieldT> &opcode_indicators,
24 const pb_variable_array<FieldT> &instruction_results,
25 const pb_variable_array<FieldT> &instruction_flags,
26 const pb_variable_array<FieldT> &desidx,
27 const pb_variable<FieldT> &packed_incoming_pc,
28 const pb_variable_array<FieldT> &packed_incoming_registers,
29 const pb_variable<FieldT> &packed_incoming_desval,
30 const pb_variable<FieldT> &incoming_flag,
31 const pb_variable<FieldT> &packed_outgoing_pc,
32 const pb_variable_array<FieldT> &packed_outgoing_registers,
33 const pb_variable<FieldT> &outgoing_flag,
34 const std::string &annotation_prefix)
35 : tinyram_standard_gadget<FieldT>(pb, annotation_prefix)
36 , opcode_indicators(opcode_indicators)
37 , instruction_results(instruction_results)
38 , instruction_flags(instruction_flags)
40 , packed_incoming_pc(packed_incoming_pc)
41 , packed_incoming_registers(packed_incoming_registers)
42 , packed_incoming_desval(packed_incoming_desval)
43 , incoming_flag(incoming_flag)
44 , packed_outgoing_pc(packed_outgoing_pc)
45 , packed_outgoing_registers(packed_outgoing_registers)
46 , outgoing_flag(outgoing_flag)
48 assert(desidx.size() == pb.ap.reg_arg_width());
50 packed_outgoing_desval.allocate(
51 pb, FMT(this->annotation_prefix, " packed_outgoing_desval"));
52 is_register_instruction.allocate(
53 pb, FMT(this->annotation_prefix, " is_register_instruction"));
54 is_control_flow_instruction.allocate(
55 pb, FMT(this->annotation_prefix, " is_control_flow_instruction"));
56 is_stall_instruction.allocate(
57 pb, FMT(this->annotation_prefix, " is_stall_instruction"));
59 packed_desidx.allocate(pb, FMT(this->annotation_prefix, " packed_desidx"));
60 pack_desidx.reset(new packing_gadget<FieldT>(
64 FMT(this->annotation_prefix, "pack_desidx")));
66 computed_result.allocate(
67 pb, FMT(this->annotation_prefix, " computed_result"));
68 computed_flag.allocate(pb, FMT(this->annotation_prefix, " computed_flag"));
70 compute_computed_result.reset(new inner_product_gadget<FieldT>(
75 FMT(this->annotation_prefix, " compute_computed_result")));
76 compute_computed_flag.reset(new inner_product_gadget<FieldT>(
81 FMT(this->annotation_prefix, " compute_computed_flag")));
83 pc_from_cf_or_zero.allocate(
84 pb, FMT(this->annotation_prefix, " pc_from_cf_or_zero"));
86 demux_packed_outgoing_desval.reset(new loose_multiplexing_gadget<FieldT>(
88 packed_outgoing_registers,
90 packed_outgoing_desval,
92 FMT(this->annotation_prefix, " demux_packed_outgoing_desval")));
95 template<typename FieldT>
96 void consistency_enforcer_gadget<FieldT>::generate_r1cs_constraints()
98 /* pack destination index */
99 pack_desidx->generate_r1cs_constraints(false);
101 /* demux result register */
102 demux_packed_outgoing_desval->generate_r1cs_constraints();
104 /* is_register_instruction */
105 linear_combination<FieldT> reg_a, reg_b, reg_c;
106 reg_a.add_term(ONE, 1);
107 for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_register); ++i) {
108 reg_b.add_term(opcode_indicators[tinyram_opcodes_register[i]], 1);
110 reg_c.add_term(is_register_instruction, 1);
111 this->pb.add_r1cs_constraint(
112 r1cs_constraint<FieldT>(reg_a, reg_b, reg_c),
113 FMT(this->annotation_prefix, " is_register_instruction"));
115 /* is_control_flow_instruction */
116 linear_combination<FieldT> cf_a, cf_b, cf_c;
117 cf_a.add_term(ONE, 1);
118 for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_control_flow); ++i) {
119 cf_b.add_term(opcode_indicators[tinyram_opcodes_control_flow[i]], 1);
121 cf_c.add_term(is_control_flow_instruction, 1);
122 this->pb.add_r1cs_constraint(
123 r1cs_constraint<FieldT>(cf_a, cf_b, cf_c),
124 FMT(this->annotation_prefix, " is_control_flow_instruction"));
126 /* is_stall_instruction */
127 linear_combination<FieldT> stall_a, stall_b, stall_c;
128 stall_a.add_term(ONE, 1);
129 for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_stall); ++i) {
130 stall_b.add_term(opcode_indicators[tinyram_opcodes_stall[i]], 1);
132 stall_c.add_term(is_stall_instruction, 1);
133 this->pb.add_r1cs_constraint(
134 r1cs_constraint<FieldT>(stall_a, stall_b, stall_c),
135 FMT(this->annotation_prefix, " is_stall_instruction"));
137 /* compute actual result/actual flag */
138 compute_computed_result->generate_r1cs_constraints();
139 compute_computed_flag->generate_r1cs_constraints();
142 compute new PC address (in double words, not bytes!):
144 PC' = computed_result * is_control_flow_instruction + PC *
145 is_stall_instruction + (PC+1) * (1-is_control_flow_instruction -
146 is_stall_instruction) PC' - pc_from_cf_or_zero -
147 (1-is_control_flow_instruction - is_stall_instruction) = PC * (1 -
148 is_control_flow_instruction)
150 this->pb.add_r1cs_constraint(
151 r1cs_constraint<FieldT>(
152 computed_result, is_control_flow_instruction, pc_from_cf_or_zero),
153 FMT(this->annotation_prefix, " pc_from_cf_or_zero"));
155 this->pb.add_r1cs_constraint(
156 r1cs_constraint<FieldT>(
158 1 - is_control_flow_instruction,
159 packed_outgoing_pc - pc_from_cf_or_zero -
160 (1 - is_control_flow_instruction - is_stall_instruction)),
161 FMT(this->annotation_prefix, " packed_outgoing_pc"));
166 flag' = computed_flag * is_register_instruction + flag *
167 (1-is_register_instruction) flag' - flag = (computed_flag - flag) *
168 is_register_instruction
170 this->pb.add_r1cs_constraint(
171 r1cs_constraint<FieldT>(
172 {computed_flag, incoming_flag * (-1)},
173 {is_register_instruction},
174 {outgoing_flag, incoming_flag * (-1)}),
175 FMT(this->annotation_prefix, " outgoing_flag"));
178 force carryover of unchanged registers
180 (1-indicator) * (new-old) = 0
182 In order to save constraints we "borrow" indicator variables
183 from loose multiplexing gadget.
185 for (size_t i = 0; i < this->pb.ap.k; ++i) {
186 this->pb.add_r1cs_constraint(
187 r1cs_constraint<FieldT>(
188 {ONE, demux_packed_outgoing_desval->alpha[i] * (-1)},
189 {packed_outgoing_registers[i],
190 packed_incoming_registers[i] * (-1)},
192 FMT(this->annotation_prefix, " register_carryover_%zu", i));
196 enforce correct destination register value:
198 next_desval = computed_result * is_register_instruction +
199 packed_incoming_desval * (1-is_register_instruction) next_desval -
200 packed_incoming_desval = (computed_result - packed_incoming_desval) *
201 is_register_instruction
203 this->pb.add_r1cs_constraint(
204 r1cs_constraint<FieldT>(
205 {computed_result, packed_incoming_desval * (-1)},
206 {is_register_instruction},
207 {packed_outgoing_desval, packed_incoming_desval * (-1)}),
208 FMT(this->annotation_prefix, " packed_outgoing_desval"));
211 template<typename FieldT>
212 void consistency_enforcer_gadget<FieldT>::generate_r1cs_witness()
214 /* pack destination index */
215 pack_desidx->generate_r1cs_witness_from_bits();
217 /* is_register_instruction */
218 this->pb.val(is_register_instruction) = FieldT::zero();
220 for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_register); ++i) {
221 this->pb.val(is_register_instruction) +=
222 this->pb.val(opcode_indicators[tinyram_opcodes_register[i]]);
225 /* is_control_flow_instruction */
226 this->pb.val(is_control_flow_instruction) = FieldT::zero();
228 for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_control_flow); ++i) {
229 this->pb.val(is_control_flow_instruction) +=
230 this->pb.val(opcode_indicators[tinyram_opcodes_control_flow[i]]);
233 /* is_stall_instruction */
234 this->pb.val(is_stall_instruction) = FieldT::zero();
236 for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_stall); ++i) {
237 this->pb.val(is_stall_instruction) +=
238 this->pb.val(opcode_indicators[tinyram_opcodes_stall[i]]);
241 /* compute actual result/actual flag */
242 compute_computed_result->generate_r1cs_witness();
243 compute_computed_flag->generate_r1cs_witness();
246 compute new PC address (in double words, not bytes!):
248 PC' = computed_result * is_control_flow_instruction + PC *
249 is_stall_instruction + (PC+1) * (1-is_control_flow_instruction -
250 is_stall_instruction) PC' - pc_from_cf_or_zero -
251 (1-is_control_flow_instruction - is_stall_instruction) = PC * (1 -
252 is_control_flow_instruction)
254 this->pb.val(pc_from_cf_or_zero) =
255 this->pb.val(computed_result) *
256 this->pb.val(is_control_flow_instruction);
257 this->pb.val(packed_outgoing_pc) =
258 this->pb.val(pc_from_cf_or_zero) +
259 this->pb.val(packed_incoming_pc) * this->pb.val(is_stall_instruction) +
260 (this->pb.val(packed_incoming_pc) + FieldT::one()) *
261 (FieldT::one() - this->pb.val(is_control_flow_instruction) -
262 this->pb.val(is_stall_instruction));
267 flag' = computed_flag * is_register_instruction + flag *
268 (1-is_register_instruction) flag' - flag = (computed_flag - flag) *
269 is_register_instruction
271 this->pb.val(outgoing_flag) =
272 this->pb.val(computed_flag) * this->pb.val(is_register_instruction) +
273 this->pb.val(incoming_flag) *
274 (FieldT::one() - this->pb.val(is_register_instruction));
277 update registers (changed and unchanged)
279 next_desval = computed_result * is_register_instruction +
280 packed_incoming_desval * (1-is_register_instruction)
282 FieldT changed_register_contents =
283 this->pb.val(computed_result) * this->pb.val(is_register_instruction) +
284 this->pb.val(packed_incoming_desval) *
285 (FieldT::one() - this->pb.val(is_register_instruction));
287 for (size_t i = 0; i < this->pb.ap.k; ++i) {
288 this->pb.val(packed_outgoing_registers[i]) =
289 (this->pb.val(packed_desidx).as_ulong() == i)
290 ? changed_register_contents
291 : this->pb.val(packed_incoming_registers[i]);
294 /* demux result register (it is important to do witness generation
295 here after all registers have been set to the correct
297 demux_packed_outgoing_desval->generate_r1cs_witness();
301 template<typename FieldT>
302 void test_arithmetic_consistency_enforcer_gadget()
304 libff::print_time("starting arithmetic_consistency_enforcer test");
306 tinyram_architecture_params ap(16, 16);
307 tinyram_protoboard<FieldT> pb(ap);
309 pb_variable_array<FieldT> opcode_indicators, instruction_results, instruction_flags;
310 opcode_indicators.allocate(pb, 1ul<<ap.opcode_width(), "opcode_indicators");
311 instruction_results.allocate(pb, 1ul<<ap.opcode_width(), "instruction_results");
312 instruction_flags.allocate(pb, 1ul<<ap.opcode_width(), "instruction_flags");
314 dual_variable_gadget<FieldT> desidx(pb, ap.reg_arg_width(), "desidx");
316 pb_variable<FieldT> incoming_pc;
317 incoming_pc.allocate(pb, "incoming_pc");
319 pb_variable_array<FieldT> packed_incoming_registers;
320 packed_incoming_registers.allocate(pb, ap.k, "packed_incoming_registers");
322 pb_variable<FieldT> incoming_load_flag;
323 incoming_load_flag.allocate(pb, "incoming_load_flag");
325 pb_variable<FieldT> outgoing_pc, outgoing_flag;
326 outgoing_pc.allocate(pb, "outgoing_pc");
327 outgoing_flag.allocate(pb, "outgoing_flag");
329 pb_variable_array<FieldT> packed_outgoing_registers;
330 packed_outgoing_registers.allocate(pb, ap.k, "packed_outgoing_registers");
332 arithmetic_consistency_enforcer_gadget g(pb, opcode_indicators, instruction_results, instruction_flags,
333 desidx.bits, incoming_pc, packed_incoming_registers,
334 incoming_load_flag, outgoing_pc, packed_outgoing_registers, outgoing_flag, "g");
335 g.generate_r1cs_constraints();
337 for (size_t i = 0; i < 1ul<<ap.opcode_width(); ++i)
339 this->pb.val(instruction_results[i]) = FieldT(std::rand());
340 this->pb.val(instruction_flags[i]) = FieldT(std::rand() % 2);
343 this->pb.val(incoming_pc) = FieldT(12345);
344 this->pb.val(incoming_load_flag) = FieldT::zero();
346 for (size_t i = 0; i < ap.k; ++i)
348 this->pb.val(packed_incoming_registers[i]) = FieldT(1000+i);
351 for (size_t t = 0; t < 1ul<<ap.opcode_width(); ++t)
353 this->pb.val(opcode_indicators[t]) = FieldT::zero();
356 this->pb.val(opcode_indicators[tinyram_opcode_AND]) = FieldT::one();
358 for (size_t i = 0; i < ap.k; ++i)
360 this->pb.val(desidx.packed) = FieldT(i);
361 desidx.generate_r1cs_witness_from_packed();
363 g.generate_r1cs_witness();
365 assert(this->pb.val(outgoing_pc) == FieldT(12346));
367 for (size_t j = 0; j < ap.k; ++j)
369 assert(this->pb.val(packed_outgoing_registers[j]) ==
370 this->pb.val(i == j ?
371 instruction_results[tinyram_opcode_AND] :
372 packed_incoming_registers[j]));
375 assert(this->pb.val(outgoing_flag) == this->pb.val(instruction_flags[tinyram_opcode_AND]));
376 assert(pb.is_satisfied());
379 printf("arithmetic test successful\n");
380 for (size_t t = 0; t < 1ul<<ap.opcode_width(); ++t)
382 this->pb.val(opcode_indicators[t]) = FieldT::zero();
384 this->pb.val(opcode_indicators[tinyram_opcode_LOAD]) = FieldT::one();
385 this->pb.val(incoming_load_flag) = FieldT::one();
387 g.generate_r1cs_witness();
389 this->pb.val(outgoing_pc) == FieldT(12345);
390 assert(pb.is_satisfied());
392 this->pb.val(incoming_load_flag) = FieldT::zero();
393 printf("test that firstload doesn't increment PC successful\n");
395 for (size_t t = 0; t < 1ul<<ap.opcode_width(); ++t)
397 this->pb.val(opcode_indicators[t]) = FieldT::zero();
400 this->pb.val(opcode_indicators[tinyram_opcode_JMP]) = FieldT::one();
402 for (size_t i = 0; i < ap.k; ++i)
404 this->pb.val(desidx.packed) = FieldT(i);
405 desidx.generate_r1cs_witness_from_packed();
407 g.generate_r1cs_witness();
409 for (size_t j = 0; j < ap.k; ++j)
411 assert(this->pb.val(packed_outgoing_registers[j]) == this->pb.val(packed_incoming_registers[j]));
414 assert(pb.is_satisfied());
417 printf("non-arithmetic test successful\n");
419 libff::print_time("arithmetic_consistency_enforcer tests successful");
422 template<typename FieldT>
423 void test_control_flow_consistency_enforcer_gadget()
425 libff::print_time("starting control_flow_consistency_enforcer test");
427 tinyram_architecture_params ap(16, 16);
428 tinyram_protoboard<FieldT> pb(ap);
430 pb_variable_array<FieldT> opcode_indicators, instruction_results;
431 opcode_indicators.allocate(pb, 1ul<<ap.opcode_width(), "opcode_indicators");
432 instruction_results.allocate(pb, 1ul<<ap.opcode_width(), "instruction_results");
434 pb_variable<FieldT> incoming_pc, incoming_flag;
435 incoming_pc.allocate(pb, "incoming_pc");
436 incoming_flag.allocate(pb, "incoming_flag");
438 pb_variable_array<FieldT> packed_incoming_registers;
439 packed_incoming_registers.allocate(pb, ap.k, "packed_incoming_registers");
441 pb_variable<FieldT> outgoing_pc, outgoing_flag;
442 outgoing_pc.allocate(pb, "outgoing_pc");
443 outgoing_flag.allocate(pb, "outgoing_flag");
445 pb_variable_array<FieldT> packed_outgoing_registers;
446 packed_outgoing_registers.allocate(pb, ap.k, "packed_outgoing_registers");
448 control_flow_consistency_enforcer_gadget g(pb, opcode_indicators, instruction_results,
449 incoming_pc, packed_incoming_registers, incoming_flag,
450 outgoing_pc, packed_outgoing_registers, outgoing_flag, "g");
451 g.generate_r1cs_constraints();
453 for (size_t i = 0; i < 1ul<<ap.opcode_width(); ++i)
455 this->pb.val(instruction_results[i]) = FieldT(std::rand());
458 this->pb.val(incoming_pc) = FieldT(12345);
460 for (size_t i = 0; i < ap.k; ++i)
462 this->pb.val(packed_incoming_registers[i]) = FieldT(1000+i);
465 for (size_t t = 0; t < 1ul<<ap.opcode_width(); ++t)
467 this->pb.val(opcode_indicators[t]) = FieldT::zero();
469 this->pb.val(opcode_indicators[tinyram_opcode_JMP]) = FieldT::one();
471 for (int flag = 0; flag <= 1; ++flag)
473 this->pb.val(incoming_flag) = FieldT(flag);
475 g.generate_r1cs_witness();
477 assert(this->pb.val(outgoing_pc) == this->pb.val(instruction_results[tinyram_opcode_JMP]));
478 assert(this->pb.val(outgoing_flag) == this->pb.val(incoming_flag));
480 for (size_t j = 0; j < ap.k; ++j)
482 assert(this->pb.val(packed_outgoing_registers[j]) == this->pb.val(packed_incoming_registers[j]));
484 assert(pb.is_satisfied());
487 libff::print_time("control_flow_consistency_enforcer tests successful");
490 template<typename FieldT>
491 void test_special_consistency_enforcer_gadget()
493 libff::print_time("starting special_consistency_enforcer_gadget test");
495 tinyram_architecture_params ap(16, 16);
496 tinyram_protoboard<FieldT> pb(ap);
498 pb_variable_array<FieldT> opcode_indicators;
499 opcode_indicators.allocate(pb, 1ul<<ap.opcode_width(), "opcode_indicators");
501 pb_variable<FieldT> incoming_pc, incoming_flag, incoming_load_flag;
502 incoming_pc.allocate(pb, "incoming_pc");
503 incoming_flag.allocate(pb, "incoming_flag");
504 incoming_load_flag.allocate(pb, "incoming_load_flag");
506 pb_variable_array<FieldT> packed_incoming_registers;
507 packed_incoming_registers.allocate(pb, ap.k, "packed_incoming_registers");
509 pb_variable<FieldT> outgoing_pc, outgoing_flag, outgoing_load_flag;
510 outgoing_pc.allocate(pb, "outgoing_pc");
511 outgoing_flag.allocate(pb, "outgoing_flag");
512 outgoing_load_flag.allocate(pb, "outgoing_load_flag");
514 pb_variable_array<FieldT> packed_outgoing_registers;
515 packed_outgoing_registers.allocate(pb, ap.k, "packed_outgoing_registers");
517 special_consistency_enforcer_gadget g(pb, opcode_indicators,
518 incoming_pc, packed_incoming_registers, incoming_flag, incoming_load_flag,
519 outgoing_pc, packed_outgoing_registers, outgoing_flag, outgoing_load_flag, "g");
520 g.generate_r1cs_constraints();
522 this->pb.val(incoming_pc) = FieldT(12345);
523 for (size_t i = 0; i < ap.k; ++i)
525 this->pb.val(packed_incoming_registers[i]) = FieldT(1000+i);
527 this->pb.val(incoming_flag) = FieldT::zero();
528 this->pb.val(incoming_load_flag) = FieldT::zero();
530 /* test that accept stalls */
531 printf("test that ACCEPT stalls\n");
533 for (size_t t = 0; t < 1ul<<ap.opcode_width(); ++t)
535 this->pb.val(opcode_indicators[t]) = FieldT::zero();
537 this->pb.val(opcode_indicators[tinyram_opcode_ACCEPT]) = FieldT::one();
539 g.generate_r1cs_witness();
541 assert(this->pb.val(outgoing_flag) == this->pb.val(incoming_flag));
542 for (size_t j = 0; j < ap.k; ++j)
544 assert(this->pb.val(packed_outgoing_registers[j]) == this->pb.val(packed_incoming_registers[j]));
547 assert(this->pb.val(outgoing_pc) == this->pb.val(incoming_pc));
548 assert(pb.is_satisfied());
550 printf("test that ACCEPT preserves registers\n");
551 this->pb.val(packed_outgoing_registers[0]) = FieldT::zero();
552 assert(!pb.is_satisfied());
554 /* test that other special instructions (e.g. STORE) don't and also preserve registers */
555 printf("test that others (e.g. STORE) don't stall\n");
557 for (size_t t = 0; t < 1ul<<ap.opcode_width(); ++t)
559 this->pb.val(opcode_indicators[t]) = FieldT::zero();
561 this->pb.val(opcode_indicators[tinyram_opcode_STORE]) = FieldT::one();
563 g.generate_r1cs_witness();
565 assert(this->pb.val(outgoing_flag) == this->pb.val(incoming_flag));
566 for (size_t j = 0; j < ap.k; ++j)
568 assert(this->pb.val(packed_outgoing_registers[j]) == this->pb.val(packed_incoming_registers[j]));
571 assert(this->pb.val(outgoing_pc) == this->pb.val(incoming_pc) + FieldT::one());
572 assert(pb.is_satisfied());
574 printf("test that STORE preserves registers\n");
575 this->pb.val(packed_outgoing_registers[0]) = FieldT::zero();
576 assert(!pb.is_satisfied());
578 printf("test that STORE can't have load_flag\n");
579 g.generate_r1cs_witness();
580 this->pb.val(incoming_load_flag) = FieldT::one();
582 assert(!pb.is_satisfied());
584 /* test that load can modify outgoing register and sets load_flag */
585 printf("test that LOAD sets load_flag\n");
587 for (size_t t = 0; t < 1ul<<ap.opcode_width(); ++t)
589 this->pb.val(opcode_indicators[t]) = FieldT::zero();
591 this->pb.val(opcode_indicators[tinyram_opcode_LOAD]) = FieldT::one();
592 this->pb.val(incoming_load_flag) = FieldT::zero();
594 g.generate_r1cs_witness();
596 assert(this->pb.val(outgoing_load_flag) == FieldT::one());
597 assert(pb.is_satisfied());
599 printf("test that LOAD can modify registers\n");
600 this->pb.val(packed_outgoing_registers[0]) = FieldT::zero();
601 assert(pb.is_satisfied());
603 /* test that postload clears load_flag */
604 printf("test that postload clears load_flag\n");
606 for (size_t t = 0; t < 1ul<<ap.opcode_width(); ++t)
608 this->pb.val(opcode_indicators[t]) = FieldT::zero();
610 this->pb.val(opcode_indicators[tinyram_opcode_LOAD]) = FieldT::one();
611 this->pb.val(incoming_load_flag) = FieldT::one();
613 g.generate_r1cs_witness();
615 assert(this->pb.val(outgoing_load_flag) == FieldT::zero());
616 assert(pb.is_satisfied());
618 /* test non-special instructions */
619 printf("test non-special instructions\n");
621 for (size_t t = 0; t < 1ul<<ap.opcode_width(); ++t)
623 this->pb.val(opcode_indicators[t]) = FieldT::zero();
625 this->pb.val(opcode_indicators[tinyram_opcode_JMP]) = FieldT::one();
626 this->pb.val(incoming_load_flag) = FieldT::zero();
627 g.generate_r1cs_witness();
629 assert(pb.is_satisfied());
631 printf("test that non-special can't have load_flag\n");
632 g.generate_r1cs_witness();
633 this->pb.val(incoming_load_flag) = FieldT::one();
635 assert(!pb.is_satisfied());
637 libff::print_time("special_consistency_enforcer_gadget tests successful");
641 } // namespace libsnark
643 #endif // CONSISTENCY_ENFORCER_GADGET_TCC_