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_