Zecale - Reconciling Privacy and Scalability on Smart-Contract Chains  0.5
Reference implementation of the Zecale protocol by Clearmatics
aggregator_circuit.tcc
Go to the documentation of this file.
1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
2 //
3 // SPDX-License-Identifier: LGPL-3.0+
4 
5 #ifndef __ZECALE_CORE_AGGREGATOR_CIRCUIT_TCC__
6 #define __ZECALE_CORE_AGGREGATOR_CIRCUIT_TCC__
7 
8 #include "libzecale/circuits/aggregator_circuit.hpp"
9 
10 #include <libzeth/zeth_constants.hpp>
11 
12 using namespace libzeth;
13 
14 namespace libzecale
15 {
16 
17 template<typename wppT, typename wsnarkT, typename nverifierT, size_t NumProofs>
18 aggregator_circuit<wppT, wsnarkT, nverifierT, NumProofs>::aggregator_circuit(
19  const size_t inputs_per_nested_proof)
20  : _num_inputs_per_nested_proof(inputs_per_nested_proof), _pb()
21 {
22  // The order of allocation here is important as it determines which inputs
23  // are primary.
24 
25  // Input for hash of nested verification key.
26  _nested_vk_hash.allocate(_pb, FMT("", "_nested_vk_hash"));
27 
28  // Packed results (populated by the packer)
29  _nested_proof_results.allocate(_pb, FMT("", "_nested_proof_results"));
30 
31  // Allocate nested primary inputs (populated by aggregator).
32  for (size_t i = 0; i < NumProofs; i++) {
33  _nested_primary_inputs[i].allocate(
34  _pb,
35  _num_inputs_per_nested_proof,
36  FMT("", "_nested_primary_inputs_bits[%zu]", i));
37  }
38 
39  // Set the number of primary inputs.
40  const size_t total_primary_inputs = num_primary_inputs();
41  _pb.set_input_sizes(total_primary_inputs);
42 
43  // Allocate the unpacked nested proof verification results (populated by
44  // aggregator, consumed by results packer.
45  for (size_t i = 0; i < NumProofs; i++) {
46  _nested_proof_results_unpacked[i].allocate(
47  _pb, FMT("", "_nested_proof_results[%zu]", i));
48  }
49 
50  // Allocate vk and the intermediate bit representation
51  _nested_vk.reset(new verification_key_variable_gadget(
52  _pb, _num_inputs_per_nested_proof, "_nested_vk"));
53 
54  // Allocate proof variables.
55  for (size_t i = 0; i < NumProofs; i++) {
56  _nested_proofs[i].reset(
57  new proof_variable_gadget(_pb, FMT("", "_nested_proofs[%zu]", i)));
58  }
59 
60  // Nested verification key hash gadget
61  _nested_vk_hash_gadget.reset(
62  new verification_key_hash_gadget<wppT, nverifierT>(
63  _pb,
64  *_nested_vk,
65  _nested_vk_hash,
66  FMT("", "_nested_vk_hash_gadget")));
67 
68  // Aggregator gadget
69  _aggregator_gadget.reset(new aggregator_gadget<wppT, nverifierT, NumProofs>(
70  _pb,
71  *_nested_vk,
72  _nested_primary_inputs,
73  _nested_proofs,
74  _nested_proof_results_unpacked,
75  "_aggregator_gadget"));
76 
77  // Results packer gadgets
78  libsnark::pb_linear_combination_array<libff::Fr<wppT>>
79  unpacked_results_array(NumProofs);
80  for (size_t i = 0; i < NumProofs; ++i) {
81  unpacked_results_array[i] = _nested_proof_results_unpacked[i];
82  }
83 
84  _nested_proof_results_packer.reset(
85  new libsnark::packing_gadget<libff::Fr<wppT>>(
86  _pb,
87  unpacked_results_array,
88  _nested_proof_results,
89  "_nested_proof_results_packer"));
90 
91  // Initialize all constraints in the circuit.
92  for (size_t i = 0; i < NumProofs; ++i) {
93  _nested_proofs[i]->generate_r1cs_constraints();
94  }
95  _nested_vk_hash_gadget->generate_r1cs_constraints();
96  _aggregator_gadget->generate_r1cs_constraints();
97  _nested_proof_results_packer->generate_r1cs_constraints(false);
98 }
99 
100 template<typename wppT, typename wsnarkT, typename nverifierT, size_t NumProofs>
101 typename wsnarkT::keypair aggregator_circuit<
102  wppT,
103  wsnarkT,
104  nverifierT,
105  NumProofs>::generate_trusted_setup() const
106 {
107  // Generate a verification and proving key (trusted setup)
108  return wsnarkT::generate_setup(_pb);
109 }
110 
111 template<typename wppT, typename wsnarkT, typename nverifierT, size_t NumProofs>
112 const libsnark::r1cs_constraint_system<libff::Fr<wppT>>
113  &aggregator_circuit<wppT, wsnarkT, nverifierT, NumProofs>::
114  get_constraint_system() const
115 {
116  return _pb.get_constraint_system();
117 }
118 
119 template<typename wppT, typename wsnarkT, typename nverifierT, size_t NumProofs>
120 libzeth::extended_proof<wppT, wsnarkT> aggregator_circuit<
121  wppT,
122  wsnarkT,
123  nverifierT,
124  NumProofs>::
125  prove(
126  const typename nsnark::verification_key &nested_vk,
127  const std::array<
128  const libzeth::extended_proof<npp, nsnark> *,
129  NumProofs> &extended_proofs,
130  const typename wsnarkT::proving_key &aggregator_proving_key)
131 {
132  // Witness the proofs and construct the array of primary inputs (in npp).
133  // These will be used to populate _nested_primary_inputs.
134  std::array<const libsnark::r1cs_primary_input<libff::Fr<npp>> *, NumProofs>
135  nested_inputs{};
136  for (size_t i = 0; i < NumProofs; ++i) {
137  const libzeth::extended_proof<npp, nsnark> &ep = *(extended_proofs[i]);
138  if (ep.get_primary_inputs().size() != _num_inputs_per_nested_proof) {
139  throw std::runtime_error(
140  "attempt to aggregate proof with invalid number of inputs");
141  }
142 
143  nested_inputs[i] = &ep.get_primary_inputs();
144  _nested_proofs[i]->generate_r1cs_witness(ep.get_proof());
145  }
146 
147  // Witness the verification key
148  _nested_vk->generate_r1cs_witness(nested_vk);
149 
150  // Witness hash of verification keypair
151  _nested_vk_hash_gadget->generate_r1cs_witness();
152 
153  // Pass the input values (in npp) to the aggregator gadget.
154  _aggregator_gadget->generate_r1cs_witness(nested_inputs);
155 
156  // Witness the packed results
157  _nested_proof_results_packer->generate_r1cs_witness_from_bits();
158 
159 #ifdef DEBUG
160  // Check the validity of the circuit.
161  bool is_valid_witness = _pb.is_satisfied();
162  std::cout << "*** [DEBUG] Satisfiability result: " << is_valid_witness
163  << " ***" << std::endl;
164 #endif
165 
166  // Return an extended_proof for the given witness.
167  return extended_proof<wppT, wsnarkT>(
168  wsnarkT::generate_proof(aggregator_proving_key, _pb),
169  _pb.primary_input());
170 }
171 
172 template<typename wppT, typename wsnarkT, typename nverifierT, size_t NumProofs>
173 size_t aggregator_circuit<wppT, wsnarkT, nverifierT, NumProofs>::
174  num_primary_inputs() const
175 {
176  // Compute the total number of primary inputs for a circuit of this type,
177  // including leading vk_hash, results and nested primary inputs (see
178  // aggregator_circuit.hpp for full layout).
179  return 1 + 1 + NumProofs * _num_inputs_per_nested_proof;
180 }
181 
182 } // namespace libzecale
183 
184 #endif // __ZECALE_CORE_AGGREGATOR_CIRCUIT_TCC__