2  *****************************************************************************
 
    4  Implementation of functionality for creating and using the two PCD circuits in
 
    5  a multi-predicate PCD construction.
 
    7  See mp_pcd_circuits.hpp .
 
    9  *****************************************************************************
 
   10  * @author     This file is part of libsnark, developed by SCIPR Lab
 
   11  *             and contributors (see AUTHORS).
 
   12  * @copyright  MIT license (see LICENSE file)
 
   13  *****************************************************************************/
 
   15 #ifndef MP_PCD_CIRCUITS_TCC_
 
   16 #define MP_PCD_CIRCUITS_TCC_
 
   19 #include <libff/common/utils.hpp>
 
   20 #include <libsnark/gadgetlib1/constraint_profiling.hpp>
 
   25 template<typename ppT>
 
   26 mp_compliance_step_pcd_circuit_maker<ppT>::mp_compliance_step_pcd_circuit_maker(
 
   27     const r1cs_pcd_compliance_predicate<FieldT> &compliance_predicate,
 
   28     const size_t max_number_of_predicates)
 
   29     : compliance_predicate(compliance_predicate)
 
   31     /* calculate some useful sizes */
 
   32     const size_t digest_size =
 
   33         CRH_with_field_out_gadget<FieldT>::get_digest_len();
 
   34     const size_t outgoing_msg_size_in_bits =
 
   36         (1 + compliance_predicate.outgoing_message_payload_length);
 
   37     assert(compliance_predicate.has_equal_input_lengths());
 
   38     const size_t translation_step_vk_size_in_bits =
 
   39         r1cs_ppzksnark_verification_key_variable<ppT>::size_in_bits(
 
   40             mp_translation_step_pcd_circuit_maker<
 
   41                 other_curve<ppT>>::input_size_in_elts());
 
   42     const size_t padded_verifier_input_size =
 
   43         mp_translation_step_pcd_circuit_maker<
 
   44             other_curve<ppT>>::input_capacity_in_bits();
 
   45     const size_t commitment_size =
 
   46         set_commitment_gadget<FieldT, CRH_with_bit_out_gadget<FieldT>>::
 
   49     const size_t output_block_size =
 
   50         commitment_size + outgoing_msg_size_in_bits;
 
   51     const size_t max_incoming_payload_length = *std::max_element(
 
   52         compliance_predicate.incoming_message_payload_lengths.begin(),
 
   53         compliance_predicate.incoming_message_payload_lengths.end());
 
   54     const size_t max_input_block_size =
 
   55         commitment_size + field_logsize() * (1 + max_incoming_payload_length);
 
   57     CRH_with_bit_out_gadget<FieldT>::sample_randomness(
 
   58         std::max(output_block_size, max_input_block_size));
 
   60     /* allocate input of the compliance MP_PCD circuit */
 
   61     mp_compliance_step_pcd_circuit_input.allocate(
 
   62         pb, input_size_in_elts(), "mp_compliance_step_pcd_circuit_input");
 
   64     /* allocate inputs to the compliance predicate */
 
   65     outgoing_message_type.allocate(pb, "outgoing_message_type");
 
   66     outgoing_message_payload.allocate(
 
   68         compliance_predicate.outgoing_message_payload_length,
 
   69         "outgoing_message_payload");
 
   71     outgoing_message_vars.insert(
 
   72         outgoing_message_vars.end(), outgoing_message_type);
 
   73     outgoing_message_vars.insert(
 
   74         outgoing_message_vars.end(),
 
   75         outgoing_message_payload.begin(),
 
   76         outgoing_message_payload.end());
 
   78     arity.allocate(pb, "arity");
 
   80     incoming_message_types.resize(compliance_predicate.max_arity);
 
   81     incoming_message_payloads.resize(compliance_predicate.max_arity);
 
   82     incoming_message_vars.resize(compliance_predicate.max_arity);
 
   83     for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
   84         incoming_message_types[i].allocate(
 
   85             pb, FMT("", "incoming_message_type_%zu", i));
 
   86         incoming_message_payloads[i].allocate(
 
   88             compliance_predicate.incoming_message_payload_lengths[i],
 
   89             FMT("", "incoming_message_payloads_%zu", i));
 
   91         incoming_message_vars[i].insert(
 
   92             incoming_message_vars[i].end(), incoming_message_types[i]);
 
   93         incoming_message_vars[i].insert(
 
   94             incoming_message_vars[i].end(),
 
   95             incoming_message_payloads[i].begin(),
 
   96             incoming_message_payloads[i].end());
 
  100         pb, compliance_predicate.local_data_length, "local_data");
 
  101     cp_witness.allocate(pb, compliance_predicate.witness_length, "cp_witness");
 
  103     /* convert compliance predicate from a constraint system into a gadget */
 
  104     pb_variable_array<FieldT> incoming_messages_concat;
 
  105     for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  106         incoming_messages_concat.insert(
 
  107             incoming_messages_concat.end(),
 
  108             incoming_message_vars[i].begin(),
 
  109             incoming_message_vars[i].end());
 
  112     compliance_predicate_as_gadget.reset(new gadget_from_r1cs<FieldT>(
 
  114         {outgoing_message_vars,
 
  115          pb_variable_array<FieldT>(1, arity),
 
  116          incoming_messages_concat,
 
  119         compliance_predicate.constraint_system,
 
  120         "compliance_predicate_as_gadget"));
 
  122     /* unpack messages to bits */
 
  123     outgoing_message_bits.allocate(
 
  124         pb, outgoing_msg_size_in_bits, "outgoing_message_bits");
 
  125     unpack_outgoing_message.reset(new multipacking_gadget<FieldT>(
 
  127         outgoing_message_bits,
 
  128         outgoing_message_vars,
 
  130         "unpack_outgoing_message"));
 
  132     incoming_messages_bits.resize(compliance_predicate.max_arity);
 
  133     for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  134         const size_t incoming_msg_size_in_bits =
 
  136             (1 + compliance_predicate.incoming_message_payload_lengths[i]);
 
  138         incoming_messages_bits[i].allocate(
 
  140             incoming_msg_size_in_bits,
 
  141             FMT("", "incoming_messages_bits_%zu", i));
 
  142         unpack_incoming_messages.emplace_back(multipacking_gadget<FieldT>(
 
  144             incoming_messages_bits[i],
 
  145             incoming_message_vars[i],
 
  147             FMT("", "unpack_incoming_messages_%zu", i)));
 
  150     /* allocate digests */
 
  151     commitment_and_incoming_message_digests.resize(
 
  152         compliance_predicate.max_arity);
 
  153     for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  154         commitment_and_incoming_message_digests[i].allocate(
 
  157             FMT("", "commitment_and_incoming_message_digests_%zu", i));
 
  160     /* allocate commitment, verification key(s) and membership
 
  161      * checker(s)/proof(s) */
 
  163         new set_commitment_variable<FieldT, CRH_with_bit_out_gadget<FieldT>>(
 
  164             pb, commitment_size, "commitment"));
 
  166     libff::print_indent();
 
  168         "* %s perform same type optimization for compliance predicate with "
 
  170         (compliance_predicate.relies_on_same_type_inputs ? "Will" : "Will NOT"),
 
  171         compliance_predicate.type);
 
  172     if (compliance_predicate.relies_on_same_type_inputs) {
 
  173         /* only one set_commitment_gadget is needed */
 
  174         common_type.allocate(pb, "common_type");
 
  175         common_type_check_aux.allocate(
 
  177             compliance_predicate.accepted_input_types.size(),
 
  178             "common_type_check_aux");
 
  180         translation_step_vks_bits.resize(1);
 
  181         translation_step_vks_bits[0].allocate(
 
  182             pb, translation_step_vk_size_in_bits, "translation_step_vk_bits");
 
  183         membership_check_results.allocate(pb, 1, "membership_check_results");
 
  185         membership_proofs.emplace_back(set_membership_proof_variable<
 
  187                                        CRH_with_bit_out_gadget<FieldT>>(
 
  188             pb, max_number_of_predicates, "membership_proof"));
 
  189         membership_checkers.emplace_back(
 
  190             set_commitment_gadget<FieldT, CRH_with_bit_out_gadget<FieldT>>(
 
  192                 max_number_of_predicates,
 
  193                 translation_step_vks_bits[0],
 
  195                 membership_proofs[0],
 
  196                 membership_check_results[0],
 
  197                 "membership_checker"));
 
  199         /* check for max_arity possibly different VKs */
 
  200         translation_step_vks_bits.resize(compliance_predicate.max_arity);
 
  201         membership_check_results.allocate(
 
  202             pb, compliance_predicate.max_arity, "membership_check_results");
 
  204         for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  205             translation_step_vks_bits[i].allocate(
 
  207                 translation_step_vk_size_in_bits,
 
  208                 FMT("", "translation_step_vks_bits_%zu", i));
 
  210             membership_proofs.emplace_back(set_membership_proof_variable<
 
  212                                            CRH_with_bit_out_gadget<FieldT>>(
 
  214                 max_number_of_predicates,
 
  215                 FMT("", "membership_proof_%zu", i)));
 
  216             membership_checkers.emplace_back(
 
  217                 set_commitment_gadget<FieldT, CRH_with_bit_out_gadget<FieldT>>(
 
  219                     max_number_of_predicates,
 
  220                     translation_step_vks_bits[i],
 
  222                     membership_proofs[i],
 
  223                     membership_check_results[i],
 
  224                     FMT("", "membership_checkers_%zu", i)));
 
  228     /* allocate blocks */
 
  229     block_for_outgoing_message.reset(new block_variable<FieldT>(
 
  231         {commitment->bits, outgoing_message_bits},
 
  232         "block_for_outgoing_message"));
 
  234     for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  235         block_for_incoming_messages.emplace_back(block_variable<FieldT>(
 
  237             {commitment->bits, incoming_messages_bits[i]},
 
  238             FMT("", "block_for_incoming_messages_%zu", i)));
 
  241     /* allocate hash checkers */
 
  242     hash_outgoing_message.reset(new CRH_with_field_out_gadget<FieldT>(
 
  245         *block_for_outgoing_message,
 
  246         mp_compliance_step_pcd_circuit_input,
 
  247         "hash_outgoing_message"));
 
  249     for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  250         const size_t input_block_size =
 
  251             commitment_size + incoming_messages_bits[i].size();
 
  252         hash_incoming_messages.emplace_back(CRH_with_field_out_gadget<FieldT>(
 
  255             block_for_incoming_messages[i],
 
  256             commitment_and_incoming_message_digests[i],
 
  257             FMT("", "hash_incoming_messages_%zu", i)));
 
  260     /* allocate useful zero variable */
 
  261     zero.allocate(pb, "zero");
 
  263     /* prepare arguments for the verifier */
 
  264     if (compliance_predicate.relies_on_same_type_inputs) {
 
  265         translation_step_vks.emplace_back(
 
  266             r1cs_ppzksnark_verification_key_variable<ppT>(
 
  268                 translation_step_vks_bits[0],
 
  269                 mp_translation_step_pcd_circuit_maker<
 
  270                     other_curve<ppT>>::input_size_in_elts(),
 
  271                 "translation_step_vk"));
 
  273         for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  274             translation_step_vks.emplace_back(
 
  275                 r1cs_ppzksnark_verification_key_variable<ppT>(
 
  277                     translation_step_vks_bits[i],
 
  278                     mp_translation_step_pcd_circuit_maker<
 
  279                         other_curve<ppT>>::input_size_in_elts(),
 
  280                     FMT("", "translation_step_vks_%zu", i)));
 
  284     verification_results.allocate(
 
  285         pb, compliance_predicate.max_arity, "verification_results");
 
  286     commitment_and_incoming_messages_digest_bits.resize(
 
  287         compliance_predicate.max_arity);
 
  289     for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  290         commitment_and_incoming_messages_digest_bits[i].allocate(
 
  292             digest_size * field_logsize(),
 
  293             FMT("", "commitment_and_incoming_messages_digest_bits_%zu", i));
 
  294         unpack_commitment_and_incoming_message_digests.emplace_back(
 
  295             multipacking_gadget<FieldT>(
 
  297                 commitment_and_incoming_messages_digest_bits[i],
 
  298                 commitment_and_incoming_message_digests[i],
 
  301                     "unpack_commitment_and_incoming_message_digests_%zu",
 
  304         verifier_input.emplace_back(
 
  305             commitment_and_incoming_messages_digest_bits[i]);
 
  306         while (verifier_input[i].size() < padded_verifier_input_size) {
 
  307             verifier_input[i].emplace_back(zero);
 
  311             r1cs_ppzksnark_proof_variable<ppT>(pb, FMT("", "proof_%zu", i)));
 
  312         const r1cs_ppzksnark_verification_key_variable<ppT> &vk_to_be_used =
 
  313             (compliance_predicate.relies_on_same_type_inputs
 
  314                  ? translation_step_vks[0]
 
  315                  : translation_step_vks[i]);
 
  316         verifier.emplace_back(r1cs_ppzksnark_verifier_gadget<ppT>(
 
  320             mp_translation_step_pcd_circuit_maker<
 
  321                 other_curve<ppT>>::field_capacity(),
 
  323             verification_results[i],
 
  324             FMT("", "verifier_%zu", i)));
 
  327     pb.set_input_sizes(input_size_in_elts());
 
  330 template<typename ppT>
 
  331 void mp_compliance_step_pcd_circuit_maker<ppT>::generate_r1cs_constraints()
 
  333     const size_t digest_size =
 
  334         CRH_with_bit_out_gadget<FieldT>::get_digest_len();
 
  335     const size_t dimension = knapsack_dimension<FieldT>::dimension;
 
  336     libff::print_indent();
 
  337     printf("* Knapsack dimension: %zu\n", dimension);
 
  339     libff::print_indent();
 
  341         "* Compliance predicate arity: %zu\n", compliance_predicate.max_arity);
 
  342     libff::print_indent();
 
  344         "* Compliance predicate outgoing payload length: %zu\n",
 
  345         compliance_predicate.outgoing_message_payload_length);
 
  346     libff::print_indent();
 
  347     printf("* Compliance predicate incoming payload lengths:");
 
  348     for (auto l : compliance_predicate.incoming_message_payload_lengths) {
 
  352     libff::print_indent();
 
  354         "* Compliance predicate local data length: %zu\n",
 
  355         compliance_predicate.local_data_length);
 
  356     libff::print_indent();
 
  358         "* Compliance predicate witness length: %zu\n",
 
  359         compliance_predicate.witness_length);
 
  361     PROFILE_CONSTRAINTS(pb, "booleanity")
 
  363         PROFILE_CONSTRAINTS(pb, "booleanity: unpack outgoing_message")
 
  365             unpack_outgoing_message->generate_r1cs_constraints(true);
 
  368         PROFILE_CONSTRAINTS(pb, "booleanity: unpack s incoming_messages")
 
  370             for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  371                 unpack_incoming_messages[i].generate_r1cs_constraints(true);
 
  375         PROFILE_CONSTRAINTS(pb, "booleanity: unpack verification key")
 
  377             for (size_t i = 0; i < translation_step_vks.size(); ++i) {
 
  378                 translation_step_vks[i].generate_r1cs_constraints(true);
 
  383     PROFILE_CONSTRAINTS(pb, "(1+s) copies of hash")
 
  385         libff::print_indent();
 
  386         printf("* Digest-size: %zu\n", digest_size);
 
  387         hash_outgoing_message->generate_r1cs_constraints();
 
  389         for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  390             hash_incoming_messages[i].generate_r1cs_constraints();
 
  394     PROFILE_CONSTRAINTS(pb, "s copies of repacking circuit for verifier")
 
  396         for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  397             unpack_commitment_and_incoming_message_digests[i]
 
  398                 .generate_r1cs_constraints(true);
 
  402     PROFILE_CONSTRAINTS(pb, "set membership check")
 
  404         for (auto &membership_proof : membership_proofs) {
 
  405             membership_proof.generate_r1cs_constraints();
 
  408         for (auto &membership_checker : membership_checkers) {
 
  409             membership_checker.generate_r1cs_constraints();
 
  413     PROFILE_CONSTRAINTS(pb, "compliance predicate")
 
  415         compliance_predicate_as_gadget->generate_r1cs_constraints();
 
  418     PROFILE_CONSTRAINTS(pb, "s copies of verifier for translated proofs")
 
  420         PROFILE_CONSTRAINTS(pb, "check that s proofs lie on the curve")
 
  422             for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  423                 proof[i].generate_r1cs_constraints();
 
  427         for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  428             verifier[i].generate_r1cs_constraints();
 
  432     PROFILE_CONSTRAINTS(pb, "miscellaneous")
 
  434         generate_r1cs_equals_const_constraint<FieldT>(
 
  435             pb, zero, FieldT::zero(), "zero");
 
  437         PROFILE_CONSTRAINTS(pb, "check that s proofs lie on the curve")
 
  439             for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  440                 generate_boolean_r1cs_constraint<FieldT>(
 
  442                     verification_results[i],
 
  443                     FMT("", "verification_results_%zu", i));
 
  447         /* either type = 0 or proof verified w.r.t. a valid verification key */
 
  449             pb, "check that s messages have valid proofs (or are base case)")
 
  451             for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  452                 pb.add_r1cs_constraint(
 
  453                     r1cs_constraint<FieldT>(
 
  454                         incoming_message_types[i],
 
  455                         1 - verification_results[i],
 
  457                     FMT("", "not_base_case_implies_valid_proof_%zu", i));
 
  461         if (compliance_predicate.relies_on_same_type_inputs) {
 
  464                 "check that all non-base case messages are of same type and "
 
  465                 "that VK is validly selected")
 
  467                 for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  468                     pb.add_r1cs_constraint(
 
  469                         r1cs_constraint<FieldT>(
 
  470                             incoming_message_types[i],
 
  471                             incoming_message_types[i] - common_type,
 
  473                         FMT("", "non_base_types_equal_%zu", i));
 
  476                 pb.add_r1cs_constraint(
 
  477                     r1cs_constraint<FieldT>(
 
  478                         common_type, 1 - membership_check_results[0], 0),
 
  479                     "valid_vk_for_the_common_type");
 
  481                 auto it = compliance_predicate.accepted_input_types.begin();
 
  483                      i < compliance_predicate.accepted_input_types.size();
 
  485                     pb.add_r1cs_constraint(
 
  486                         r1cs_constraint<FieldT>(
 
  487                             (i == 0 ? common_type
 
  488                                     : common_type_check_aux[i - 1]),
 
  489                             common_type - FieldT(*it),
 
  490                             (i == compliance_predicate.accepted_input_types
 
  494                                  : common_type_check_aux[i])),
 
  496                             "common_type_in_prescribed_set_%zu_must_equal_%zu",
 
  503                 pb, "check that all s messages have validly selected VKs")
 
  505                 for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  506                     pb.add_r1cs_constraint(
 
  507                         r1cs_constraint<FieldT>(
 
  508                             incoming_message_types[i],
 
  509                             1 - membership_check_results[i],
 
  511                         FMT("", "not_base_case_implies_valid_vk_%zu", i));
 
  515         pb.add_r1cs_constraint(
 
  516             r1cs_constraint<FieldT>(
 
  517                 1, outgoing_message_type, FieldT(compliance_predicate.type)),
 
  518             "enforce_outgoing_type");
 
  521     PRINT_CONSTRAINT_PROFILING();
 
  522     libff::print_indent();
 
  524         "* Number of constraints in mp_compliance_step_pcd_circuit: %zu\n",
 
  525         pb.num_constraints());
 
  528 template<typename ppT>
 
  529 r1cs_constraint_system<libff::Fr<ppT>> mp_compliance_step_pcd_circuit_maker<
 
  530     ppT>::get_circuit() const
 
  532     return pb.get_constraint_system();
 
  535 template<typename ppT>
 
  536 r1cs_primary_input<libff::Fr<ppT>> mp_compliance_step_pcd_circuit_maker<
 
  537     ppT>::get_primary_input() const
 
  539     return pb.primary_input();
 
  542 template<typename ppT>
 
  543 r1cs_auxiliary_input<libff::Fr<ppT>> mp_compliance_step_pcd_circuit_maker<
 
  544     ppT>::get_auxiliary_input() const
 
  546     return pb.auxiliary_input();
 
  549 template<typename ppT>
 
  550 void mp_compliance_step_pcd_circuit_maker<ppT>::generate_r1cs_witness(
 
  551     const set_commitment &commitment_to_translation_step_r1cs_vks,
 
  552     const std::vector<r1cs_ppzksnark_verification_key<other_curve<ppT>>>
 
  553         &mp_translation_step_pcd_circuit_vks,
 
  554     const std::vector<set_membership_proof> &vk_membership_proofs,
 
  555     const r1cs_pcd_compliance_predicate_primary_input<FieldT>
 
  556         &compliance_predicate_primary_input,
 
  557     const r1cs_pcd_compliance_predicate_auxiliary_input<FieldT>
 
  558         &compliance_predicate_auxiliary_input,
 
  559     const std::vector<r1cs_ppzksnark_proof<other_curve<ppT>>>
 
  560         &translation_step_proofs)
 
  562     this->pb.clear_values();
 
  563     this->pb.val(zero) = FieldT::zero();
 
  565     compliance_predicate_as_gadget->generate_r1cs_witness(
 
  566         compliance_predicate_primary_input.as_r1cs_primary_input(),
 
  567         compliance_predicate_auxiliary_input.as_r1cs_auxiliary_input(
 
  568             compliance_predicate.incoming_message_payload_lengths));
 
  570     unpack_outgoing_message->generate_r1cs_witness_from_packed();
 
  571     for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  572         unpack_incoming_messages[i].generate_r1cs_witness_from_packed();
 
  575     for (size_t i = 0; i < translation_step_vks.size(); ++i) {
 
  576         translation_step_vks[i].generate_r1cs_witness(
 
  577             mp_translation_step_pcd_circuit_vks[i]);
 
  580     commitment->generate_r1cs_witness(commitment_to_translation_step_r1cs_vks);
 
  582     if (compliance_predicate.relies_on_same_type_inputs) {
 
  583         /* all messages (except base case) must be of the same type */
 
  584         this->pb.val(common_type) = FieldT::zero();
 
  585         size_t nonzero_type_idx = 0;
 
  586         for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  587             if (this->pb.val(incoming_message_types[i]) == 0) {
 
  591             if (this->pb.val(common_type).is_zero()) {
 
  592                 this->pb.val(common_type) =
 
  593                     this->pb.val(incoming_message_types[i]);
 
  594                 nonzero_type_idx = i;
 
  597                     this->pb.val(common_type) ==
 
  598                     this->pb.val(incoming_message_types[i]));
 
  602         this->pb.val(membership_check_results[0]) =
 
  603             (this->pb.val(common_type).is_zero() ? FieldT::zero()
 
  605         membership_proofs[0].generate_r1cs_witness(
 
  606             vk_membership_proofs[nonzero_type_idx]);
 
  607         membership_checkers[0].generate_r1cs_witness();
 
  609         auto it = compliance_predicate.accepted_input_types.begin();
 
  610         for (size_t i = 0; i < compliance_predicate.accepted_input_types.size();
 
  612             pb.val(common_type_check_aux[i]) =
 
  613                 ((i == 0 ? pb.val(common_type)
 
  614                          : pb.val(common_type_check_aux[i - 1])) *
 
  615                  (pb.val(common_type) - FieldT(*it)));
 
  618         for (size_t i = 0; i < membership_checkers.size(); ++i) {
 
  619             this->pb.val(membership_check_results[i]) =
 
  620                 (this->pb.val(incoming_message_types[i]).is_zero()
 
  623             membership_proofs[i].generate_r1cs_witness(vk_membership_proofs[i]);
 
  624             membership_checkers[i].generate_r1cs_witness();
 
  628     hash_outgoing_message->generate_r1cs_witness();
 
  629     for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  630         hash_incoming_messages[i].generate_r1cs_witness();
 
  631         unpack_commitment_and_incoming_message_digests[i]
 
  632             .generate_r1cs_witness_from_packed();
 
  635     for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
 
  636         proof[i].generate_r1cs_witness(translation_step_proofs[i]);
 
  637         verifier[i].generate_r1cs_witness();
 
  641     get_circuit(); // force generating constraints
 
  642     assert(this->pb.is_satisfied());
 
  646 template<typename ppT>
 
  647 size_t mp_compliance_step_pcd_circuit_maker<ppT>::field_logsize()
 
  649     return libff::Fr<ppT>::size_in_bits();
 
  652 template<typename ppT>
 
  653 size_t mp_compliance_step_pcd_circuit_maker<ppT>::field_capacity()
 
  655     return libff::Fr<ppT>::capacity();
 
  658 template<typename ppT>
 
  659 size_t mp_compliance_step_pcd_circuit_maker<ppT>::input_size_in_elts()
 
  661     const size_t digest_size =
 
  662         CRH_with_field_out_gadget<FieldT>::get_digest_len();
 
  666 template<typename ppT>
 
  667 size_t mp_compliance_step_pcd_circuit_maker<ppT>::input_capacity_in_bits()
 
  669     return input_size_in_elts() * field_capacity();
 
  672 template<typename ppT>
 
  673 size_t mp_compliance_step_pcd_circuit_maker<ppT>::input_size_in_bits()
 
  675     return input_size_in_elts() * field_logsize();
 
  678 template<typename ppT>
 
  679 mp_translation_step_pcd_circuit_maker<ppT>::
 
  680     mp_translation_step_pcd_circuit_maker(
 
  681         const r1cs_ppzksnark_verification_key<other_curve<ppT>>
 
  684     /* allocate input of the translation MP_PCD circuit */
 
  685     mp_translation_step_pcd_circuit_input.allocate(
 
  686         pb, input_size_in_elts(), "mp_translation_step_pcd_circuit_input");
 
  688     /* unpack translation step MP_PCD circuit input */
 
  689     unpacked_mp_translation_step_pcd_circuit_input.allocate(
 
  691         mp_compliance_step_pcd_circuit_maker<
 
  692             other_curve<ppT>>::input_size_in_bits(),
 
  693         "unpacked_mp_translation_step_pcd_circuit_input");
 
  694     unpack_mp_translation_step_pcd_circuit_input.reset(
 
  695         new multipacking_gadget<FieldT>(
 
  697             unpacked_mp_translation_step_pcd_circuit_input,
 
  698             mp_translation_step_pcd_circuit_input,
 
  700             "unpack_mp_translation_step_pcd_circuit_input"));
 
  702     /* prepare arguments for the verifier */
 
  703     hardcoded_compliance_step_vk.reset(
 
  704         new r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable<
 
  705             ppT>(pb, compliance_step_vk, "hardcoded_compliance_step_vk"));
 
  706     proof.reset(new r1cs_ppzksnark_proof_variable<ppT>(pb, "proof"));
 
  708     /* verify previous proof */
 
  709     online_verifier.reset(new r1cs_ppzksnark_online_verifier_gadget<ppT>(
 
  711         *hardcoded_compliance_step_vk,
 
  712         unpacked_mp_translation_step_pcd_circuit_input,
 
  713         mp_compliance_step_pcd_circuit_maker<other_curve<ppT>>::field_logsize(),
 
  715         ONE, // must always accept
 
  718     pb.set_input_sizes(input_size_in_elts());
 
  721 template<typename ppT>
 
  722 void mp_translation_step_pcd_circuit_maker<ppT>::generate_r1cs_constraints()
 
  724     PROFILE_CONSTRAINTS(pb, "repacking: unpack circuit input")
 
  726         unpack_mp_translation_step_pcd_circuit_input->generate_r1cs_constraints(
 
  730     PROFILE_CONSTRAINTS(pb, "verifier for compliance proofs")
 
  732         PROFILE_CONSTRAINTS(pb, "check that proof lies on the curve")
 
  734             proof->generate_r1cs_constraints();
 
  737         online_verifier->generate_r1cs_constraints();
 
  740     PRINT_CONSTRAINT_PROFILING();
 
  741     libff::print_indent();
 
  743         "* Number of constraints in mp_translation_step_pcd_circuit: %zu\n",
 
  744         pb.num_constraints());
 
  747 template<typename ppT>
 
  748 r1cs_constraint_system<libff::Fr<ppT>> mp_translation_step_pcd_circuit_maker<
 
  749     ppT>::get_circuit() const
 
  751     return pb.get_constraint_system();
 
  754 template<typename ppT>
 
  755 void mp_translation_step_pcd_circuit_maker<ppT>::generate_r1cs_witness(
 
  756     const r1cs_primary_input<libff::Fr<ppT>> translation_step_input,
 
  757     const r1cs_ppzksnark_proof<other_curve<ppT>> &prev_proof)
 
  759     this->pb.clear_values();
 
  760     mp_translation_step_pcd_circuit_input.fill_with_field_elements(
 
  761         pb, translation_step_input);
 
  762     unpack_mp_translation_step_pcd_circuit_input
 
  763         ->generate_r1cs_witness_from_packed();
 
  765     proof->generate_r1cs_witness(prev_proof);
 
  766     online_verifier->generate_r1cs_witness();
 
  769     get_circuit(); // force generating constraints
 
  770     assert(this->pb.is_satisfied());
 
  774 template<typename ppT>
 
  775 r1cs_primary_input<libff::Fr<ppT>> mp_translation_step_pcd_circuit_maker<
 
  776     ppT>::get_primary_input() const
 
  778     return pb.primary_input();
 
  781 template<typename ppT>
 
  782 r1cs_auxiliary_input<libff::Fr<ppT>> mp_translation_step_pcd_circuit_maker<
 
  783     ppT>::get_auxiliary_input() const
 
  785     return pb.auxiliary_input();
 
  788 template<typename ppT>
 
  789 size_t mp_translation_step_pcd_circuit_maker<ppT>::field_logsize()
 
  791     return libff::Fr<ppT>::size_in_bits();
 
  794 template<typename ppT>
 
  795 size_t mp_translation_step_pcd_circuit_maker<ppT>::field_capacity()
 
  797     return libff::Fr<ppT>::capacity();
 
  800 template<typename ppT>
 
  801 size_t mp_translation_step_pcd_circuit_maker<ppT>::input_size_in_elts()
 
  803     return libff::div_ceil(
 
  804         mp_compliance_step_pcd_circuit_maker<
 
  805             other_curve<ppT>>::input_size_in_bits(),
 
  806         mp_translation_step_pcd_circuit_maker<ppT>::field_capacity());
 
  809 template<typename ppT>
 
  810 size_t mp_translation_step_pcd_circuit_maker<ppT>::input_capacity_in_bits()
 
  812     return input_size_in_elts() * field_capacity();
 
  815 template<typename ppT>
 
  816 size_t mp_translation_step_pcd_circuit_maker<ppT>::input_size_in_bits()
 
  818     return input_size_in_elts() * field_logsize();
 
  821 template<typename ppT>
 
  822 r1cs_primary_input<libff::Fr<ppT>> get_mp_compliance_step_pcd_circuit_input(
 
  823     const set_commitment &commitment_to_translation_step_r1cs_vks,
 
  824     const r1cs_pcd_compliance_predicate_primary_input<libff::Fr<ppT>>
 
  827     libff::enter_block("Call to get_mp_compliance_step_pcd_circuit_input");
 
  828     typedef libff::Fr<ppT> FieldT;
 
  830     const r1cs_variable_assignment<FieldT> outgoing_message_as_va =
 
  831         primary_input.outgoing_message->as_r1cs_variable_assignment();
 
  832     libff::bit_vector msg_bits;
 
  833     for (const FieldT &elt : outgoing_message_as_va) {
 
  834         const libff::bit_vector elt_bits =
 
  835             libff::convert_field_element_to_bit_vector(elt);
 
  836         msg_bits.insert(msg_bits.end(), elt_bits.begin(), elt_bits.end());
 
  839     libff::bit_vector block;
 
  842         commitment_to_translation_step_r1cs_vks.begin(),
 
  843         commitment_to_translation_step_r1cs_vks.end());
 
  844     block.insert(block.end(), msg_bits.begin(), msg_bits.end());
 
  846     libff::enter_block("Sample CRH randomness");
 
  847     CRH_with_field_out_gadget<FieldT>::sample_randomness(block.size());
 
  848     libff::leave_block("Sample CRH randomness");
 
  850     const std::vector<FieldT> digest =
 
  851         CRH_with_field_out_gadget<FieldT>::get_hash(block);
 
  852     libff::leave_block("Call to get_mp_compliance_step_pcd_circuit_input");
 
  857 template<typename ppT>
 
  858 r1cs_primary_input<libff::Fr<ppT>> get_mp_translation_step_pcd_circuit_input(
 
  859     const set_commitment &commitment_to_translation_step_r1cs_vks,
 
  860     const r1cs_pcd_compliance_predicate_primary_input<
 
  861         libff::Fr<other_curve<ppT>>> &primary_input)
 
  863     libff::enter_block("Call to get_mp_translation_step_pcd_circuit_input");
 
  864     typedef libff::Fr<ppT> FieldT;
 
  866     const std::vector<libff::Fr<other_curve<ppT>>>
 
  867         mp_compliance_step_pcd_circuit_input =
 
  868             get_mp_compliance_step_pcd_circuit_input<other_curve<ppT>>(
 
  869                 commitment_to_translation_step_r1cs_vks, primary_input);
 
  870     libff::bit_vector mp_compliance_step_pcd_circuit_input_bits;
 
  871     for (const libff::Fr<other_curve<ppT>> &elt :
 
  872          mp_compliance_step_pcd_circuit_input) {
 
  873         const libff::bit_vector elt_bits =
 
  874             libff::convert_field_element_to_bit_vector<
 
  875                 libff::Fr<other_curve<ppT>>>(elt);
 
  876         mp_compliance_step_pcd_circuit_input_bits.insert(
 
  877             mp_compliance_step_pcd_circuit_input_bits.end(),
 
  882     mp_compliance_step_pcd_circuit_input_bits.resize(
 
  883         mp_translation_step_pcd_circuit_maker<ppT>::input_capacity_in_bits(),
 
  886     const r1cs_primary_input<FieldT> result =
 
  887         libff::pack_bit_vector_into_field_element_vector<FieldT>(
 
  888             mp_compliance_step_pcd_circuit_input_bits,
 
  889             mp_translation_step_pcd_circuit_maker<ppT>::field_capacity());
 
  890     libff::leave_block("Call to get_mp_translation_step_pcd_circuit_input");
 
  895 } // namespace libsnark
 
  897 #endif // MP_PCD_CIRCUITS_TCC_