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_