1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
3 // SPDX-License-Identifier: LGPL-3.0+
5 #ifndef __ZECALE_CIRCUITS_AGGREGATOR_GADGET_TCC__
6 #define __ZECALE_CIRCUITS_AGGREGATOR_GADGET_TCC__
8 #include "libzecale/circuits/aggregator_gadget.hpp"
13 template<typename wppT, typename nverifierT, size_t NumProofs>
14 aggregator_gadget<wppT, nverifierT, NumProofs>::aggregator_gadget(
15 libsnark::protoboard<libff::Fr<wppT>> &pb,
16 const verification_key_variable_gadget &vk,
17 const std::array<libsnark::pb_variable_array<libff::Fr<wppT>>, NumProofs>
19 const std::array<std::shared_ptr<proof_variable_gadget>, NumProofs> &proofs,
20 const std::array<libsnark::pb_variable<libff::Fr<wppT>>, NumProofs>
22 const std::string &annotation_prefix)
23 : libsnark::gadget<libff::Fr<wppT>>(pb, annotation_prefix)
24 , num_inputs_per_nested_proof(vk.num_primary_inputs())
26 , nested_primary_inputs(inputs)
28 pb, vk, processed_vk, FMT(annotation_prefix, " vk_processor"))
30 // Assert that a single input of a nested proof (element of
31 // libff::Fr<nppT>) can be encoded in a single input of the wrapping proof
32 // (element of libff::Fr<wppT>). This holds for all pairing chains we test,
33 // but if it fails then nested inputs will need to be encoded over multiple
34 // wrapper inputs. Unfortunately this check cannot be made statically.
36 // TODO: if num_bits are equal then also check that `libff::Fr<nppT>::mod`
37 // <= `libff::Fr<wppT>::num_bits`.
38 assert(libff::Fr<npp>::num_bits <= libff::Fr<wppT>::num_bits);
40 // Allocate the bit representation of the public inputs and initialize the
42 const size_t num_bits_per_input = libff::Fr<npp>::size_in_bits();
43 const size_t num_input_bits_per_nested_proof =
44 num_inputs_per_nested_proof * num_bits_per_input;
45 for (size_t i = 0; i < NumProofs; i++) {
46 nested_primary_inputs_bits[i].allocate(
48 num_input_bits_per_nested_proof,
49 FMT(this->annotation_prefix,
50 " nested_primary_inputs_bits[%zu]",
53 nested_primary_input_packers.emplace_back(new input_packing_gadget(
55 nested_primary_inputs_bits[i],
58 FMT(annotation_prefix, " nested_input_packers[%zu]", i)));
61 // Initialize the verifier gadgets
62 for (size_t i = 0; i < NumProofs; i++) {
63 verifiers[i].reset(new online_verifier_gadget(
66 nested_primary_inputs_bits[i],
67 libff::Fr<npp>::size_in_bits(),
70 FMT(this->annotation_prefix, " verifiers[%zu]", i)));
74 template<typename wppT, typename nverifierT, size_t NumProofs>
75 void aggregator_gadget<wppT, nverifierT, NumProofs>::generate_r1cs_constraints()
77 vk_processor.generate_r1cs_constraints();
79 // Generate constraints (including boolean-ness of the bit representations)
80 // for input packers, nested proofs and the proof verifiers.
81 for (size_t i = 0; i < NumProofs; i++) {
82 nested_primary_input_packers[i]->generate_r1cs_constraints(true);
83 verifiers[i]->generate_r1cs_constraints();
87 template<typename wppT, typename nverifierT, size_t NumProofs>
88 void aggregator_gadget<wppT, nverifierT, NumProofs>::generate_r1cs_witness(
90 const libsnark::r1cs_primary_input<libff::Fr<npp>> *,
91 NumProofs> &nested_inputs)
93 vk_processor.generate_r1cs_witness();
95 for (size_t i = 0; i < NumProofs; i++) {
96 // Witness the nested_primary_inputs. This is done by input values are
97 // of type libff::Fr<nppT>. They are converted to bit arrays to
98 // populate `nested_primary_inputs_bits`, and the
99 // `nested_primary_input_packers` are used to convert to variables of
100 // the circuit (elements of libff::Fr<wppT>).
101 const libsnark::r1cs_primary_input<libff::Fr<npp>>
102 &other_curve_primary_inputs = *(nested_inputs[i]);
103 const libff::bit_vector input_bits =
104 libff::convert_field_element_vector_to_bit_vector<libff::Fr<npp>>(
105 other_curve_primary_inputs);
106 nested_primary_inputs_bits[i].fill_with_bits(this->pb, input_bits);
107 nested_primary_input_packers[i]->generate_r1cs_witness_from_bits();
109 // Witness the verifiers
110 verifiers[i]->generate_r1cs_witness();
114 } // namespace libzecale
116 #endif // __ZECALE_CIRCUITS_AGGREGATOR_GADGET_TCC__