-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathaggregator_test.cpp
More file actions
359 lines (314 loc) · 13.3 KB
/
Copy pathaggregator_test.cpp
File metadata and controls
359 lines (314 loc) · 13.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
// Copyright (c) 2015-2022 Clearmatics Technologies Ltd
//
// SPDX-License-Identifier: LGPL-3.0+
#include "libzecale/circuits/aggregator_circuit.hpp"
#include "libzecale/circuits/groth16_verifier/groth16_verifier_parameters.hpp"
#include "libzecale/circuits/null_hash_gadget.hpp"
#include "libzecale/circuits/pghr13_verifier/pghr13_verifier_parameters.hpp"
#include <gtest/gtest.h>
#include <libff/algebra/fields/field_utils.hpp>
#include <libsnark/common/data_structures/merkle_tree.hpp>
#include <libsnark/gadgetlib1/gadgets/pairing/bw6_761_bls12_377/bw6_761_pairing_params.hpp>
#include <libsnark/gadgetlib1/gadgets/pairing/mnt/mnt_pairing_params.hpp>
#include <libzeth/circuits/circuit_types.hpp>
#include <libzeth/circuits/circuit_wrapper.hpp>
#include <libzeth/core/bits.cpp>
using namespace libzeth;
// Instantiation of the templates for the tests
// IMPORTANT:
// Because we now switch the curve over which we generate the Zeth proofs
// we need to be careful. In fact, the fields (base and scalar) of
// the MNT curves are BIGGER than the ones of the alt_bn128.
// As such, we need to modify the Zeth statement to remove the "residual" bits
// because now, a digest can be fully packed into a field element without
// residual bits
namespace libzeth
{
// // Use mimc7 by default
// template<> class tree_hash_selector<libff::mnt4_Fr>
// {
// public:
// using tree_hash = MiMC_mp_gadget<
// libff::mnt4_Fr,
// MiMC_permutation_gadget<libff::mnt4_Fr, 7, 91>>;
// };
// template<> class tree_hash_selector<libff::mnt6_Fr>
// {
// public:
// using tree_hash = MiMC_mp_gadget<
// libff::mnt6_Fr,
// MiMC_permutation_gadget<libff::mnt6_Fr, 7, 91>>;
// };
} // namespace libzeth
// The templates and constants used in the Zeth circuit.
template<typename nppT> using hash = libzeth::BLAKE2s_256<libff::Fr<nppT>>;
template<typename nppT>
using hashTree =
typename libzeth::mimc_compression_function_gadget<libff::Fr<nppT>>;
static const size_t tree_depth = 4;
static const size_t inputs_number = 2;
static const size_t outputs_number = 2;
static const size_t batch_size = 2;
// The single primary input is the hash of public data elements:
// [Root, NullifierS(2), CommitmentS(2), h_sig, h_iS(2), Residual Field,
// Element]
static const size_t num_zeth_inputs = 1;
using namespace libzecale;
namespace
{
/// This function generates one valid zeth proof.
/// It returns the extended proof generated (snark + primary inputs)
template<typename nppT, typename snarkT>
libzeth::extended_proof<nppT, snarkT> generate_valid_zeth_proof(
circuit_wrapper<
hash<nppT>,
hashTree<nppT>,
nppT,
snarkT,
inputs_number,
outputs_number,
tree_depth> &zeth_prover,
const typename snarkT::keypair &zeth_keypair,
std::vector<libff::Fr<nppT>> &public_data)
{
using zethScalarField = libff::Fr<nppT>;
libff::print_header("Entering generate_valid_zeth_proof");
libff::enter_block("Instantiate merkle tree for the tests", true);
std::unique_ptr<merkle_tree_field<zethScalarField, hashTree<nppT>>>
test_merkle_tree =
std::unique_ptr<merkle_tree_field<zethScalarField, hashTree<nppT>>>(
new merkle_tree_field<zethScalarField, hashTree<nppT>>(
tree_depth));
libff::leave_block("Instantiate merkle tree for the tests", true);
// Generate a valid proof for commitment inserted at address 1
libff::enter_block("Create joinsplit_input", true);
// Generate note data
libzeth::bits256 trap_r_bits256 = libzeth::bits256::from_hex(
"0F000000000000FF00000000000000FF00000000000000FF00000000000000FF");
libzeth::bits64 value_bits64 =
libzeth::bits64::from_hex("2F0000000000000F");
libzeth::bits256 a_sk_bits256 = libzeth::bits256::from_hex(
"FF0000000000000000000000000000000000000000000000000000000000000F");
libzeth::bits256 rho_bits256 = libzeth::bits256::from_hex(
"FFFF000000000000000000000000000000000000000000000000000000009009");
libzeth::bits256 a_pk_bits256 = libzeth::bits256::from_hex(
"f172d7299ac8ac974ea59413e4a87691826df038ba24a2b52d5c5d15c2cc8c49");
libzeth::bits256 nf_bits256 = libzeth::bits256::from_hex(
"ff2f41920346251f6e7c67062149f98bc90c915d3d3020927ca01deab5da0fd7");
zethScalarField cm_field =
zethScalarField("1042337073265819561558789652115525918926201435246"
"16864409706009242461667751082");
const size_t address_commitment = 1;
libff::bit_vector address_bits;
for (size_t i = 0; i < tree_depth; ++i) {
address_bits.push_back((address_commitment >> i) & 0x1);
}
libzeth::bits256 h_sig = libzeth::bits256::from_hex(
"6838aac4d8247655715d3dfb9b32573da2b7d3360ba89ccdaaa7923bb24c99f7");
libzeth::bits256 phi = libzeth::bits256::from_hex(
"403794c0e20e3bf36b820d8f7aef5505e5d1c7ac265d5efbcc3030a74a3f701b");
// We insert the commitment to the zeth note in the merkle tree
test_merkle_tree->set_value(address_commitment, cm_field);
zethScalarField updated_root_value = test_merkle_tree->get_root();
std::vector<zethScalarField> path =
test_merkle_tree->get_path(address_commitment);
// JS Inputs: 1 note of value > 0 to spend, and a dummy note
libzeth::zeth_note note_input(
a_pk_bits256, value_bits64, rho_bits256, trap_r_bits256);
libzeth::zeth_note note_dummy_input(
a_pk_bits256,
libzeth::bits64::from_hex("0000000000000000"),
libzeth::bits256::from_hex(
"AAAA00000000000000000000000000000000000000000000000000000000EEEE"),
trap_r_bits256);
libzeth::joinsplit_input<zethScalarField, tree_depth> input(
std::vector<zethScalarField>(path),
libzeth::bits_addr<tree_depth>::from_vector(address_bits),
note_input,
a_sk_bits256,
nf_bits256);
// We keep the same path and address as the previous commitment
// We don't care since this note is zero-valued and the merkle auth path
// check is rendered dummy in such case
libzeth::joinsplit_input<zethScalarField, tree_depth> input_dummy(
std::vector<zethScalarField>(path),
libzeth::bits_addr<tree_depth>::from_vector(address_bits),
note_dummy_input,
a_sk_bits256,
nf_bits256);
std::array<joinsplit_input<zethScalarField, tree_depth>, inputs_number>
inputs;
inputs[0] = input;
inputs[1] = input_dummy;
libff::leave_block("Create joinsplit_input", true);
libff::enter_block("Create JSOutput/zeth_note", true);
libzeth::bits64 value_out_bits64 =
libzeth::bits64::from_hex("1800000000000008");
libzeth::bits256 a_pk_out_bits256 = libzeth::bits256::from_hex(
"7777f753bfe21ba2219ced74875b8dbd8c114c3c79d7e41306dd82118de1895b");
libzeth::bits256 rho_out_bits256;
libzeth::bits256 trap_r_out_bits256 = libzeth::bits256::from_hex(
"11000000000000990000000000000099000000000000007700000000000000FF");
libzeth::zeth_note note_output(
a_pk_out_bits256,
value_out_bits64,
rho_out_bits256,
trap_r_out_bits256);
libzeth::zeth_note note_dummy_output(
a_pk_out_bits256,
libzeth::bits64::from_hex("0000000000000000"),
rho_out_bits256,
trap_r_out_bits256);
bits64 value_pub_out_bits64 = libzeth::bits64::from_hex("1700000000000007");
std::array<zeth_note, outputs_number> outputs;
outputs[0] = note_output;
outputs[1] = note_dummy_output;
libff::leave_block("Create JSOutput/zeth_note", true);
libff::enter_block("Generate Zeth proof", true);
libzeth::extended_proof<nppT, snarkT> ext_proof = zeth_prover.prove(
updated_root_value,
inputs,
outputs,
// vpub_in = 0
libzeth::bits64::from_hex("0000000000000000"),
value_pub_out_bits64,
h_sig,
phi,
zeth_keypair.pk,
public_data);
libff::leave_block("Generate Zeth proof", true);
libff::enter_block("Verify Zeth proof", true);
typename snarkT::verification_key vk = zeth_keypair.vk;
bool res = snarkT::verify(
ext_proof.get_primary_inputs(), ext_proof.get_proof(), vk);
std::cout << "Does the proof verify? " << res << std::endl;
libff::leave_block("Verify Zeth proof", true);
std::cout << "[DEBUG] Displaying the extended proof" << std::endl;
ext_proof.write_json(std::cout);
// Return the extended proof to build the inputs of the aggregator circuit
return ext_proof;
}
/// Test aggregation of a batch of proofs
///
/// Here we use the same proof system to generate the "zeth proofs"
/// and the Zecale proofs, but we could use different proofs systems.
/// We use the same SNARK for simplicity.
template<typename wppT, typename wsnarkT, typename nverifierT>
bool test_valid_aggregation_batch_proofs(
aggregator_circuit<wppT, wsnarkT, nverifierT, batch_size>
&aggregator_prover,
typename wsnarkT::keypair &aggregator_keypair,
typename nverifierT::snark::keypair &zeth_keypair,
const std::array<
const libzeth::extended_proof<
libsnark::other_curve<wppT>,
typename nverifierT::snark> *,
batch_size> &nested_proofs)
{
libff::enter_block("Generate Aggregate proof", true);
libzeth::extended_proof<wppT, wsnarkT> ext_proof = aggregator_prover.prove(
// This should cause a crash because the primary inputs are
// packed in Zeth and are processed as unpacked here.
zeth_keypair.vk,
nested_proofs,
aggregator_keypair.pk);
libff::leave_block("Generate Aggregate proof", true);
libff::enter_block("Verify Aggregate proof", true);
typename wsnarkT::verification_key vk = aggregator_keypair.vk;
bool res = wsnarkT::verify(
ext_proof.get_primary_inputs(), ext_proof.get_proof(), vk);
std::cout << "Does the proof verify? " << res << std::endl;
libff::leave_block("Verify Aggregate proof", true);
std::cout << "[DEBUG] Displaying the extended proof" << std::endl;
ext_proof.write_json(std::cout);
return res;
}
template<typename wppT, typename wsnarkT, typename nverifierT>
void aggregator_test()
{
using npp = libsnark::other_curve<wppT>;
using nsnark = typename nverifierT::snark;
std::cout << "[DEBUG] Entering test for the aggregator" << std::endl;
// Run the trusted setup once for all tests, and keep the keypair in memory
// for the duration of the tests
libzeth::circuit_wrapper<
hash<npp>,
hashTree<npp>,
npp,
nsnark,
inputs_number,
outputs_number,
tree_depth>
zeth_prover;
std::cout << "[DEBUG] Before Zeth trusted setup" << std::endl;
typename nsnark::keypair zeth_keypair =
zeth_prover.generate_trusted_setup();
// Test to aggregate a single proof (i.e. generate a proof for the
// verification of the proof)
std::cout << "[DEBUG] Before gen Zeth proof" << std::endl;
std::vector<libff::Fr<npp>> nested_public_data;
libzeth::extended_proof<npp, nsnark> valid_proof =
generate_valid_zeth_proof(
zeth_prover, zeth_keypair, nested_public_data);
/*
* // Generate an invalid proof
* libzeth::extended_proof<zethProofCurve> invalid_proof = valid_proof;
* invalid_proof.get_primary_input
**/
std::array<const libzeth::extended_proof<npp, nsnark> *, batch_size> batch =
{&valid_proof, &valid_proof};
// Make sure that the number of primary inputs matches the one we set in the
// `aggregator_prover` circuit
std::cout << "[DEBUG] nested_proofs[0].get_primary_inputs().size(): "
<< batch[0]->get_primary_inputs().size() << std::endl;
// Make sure that we have the right amount of primary inputs
ASSERT_EQ(batch[0]->get_primary_inputs().size(), num_zeth_inputs);
std::cout << "[DEBUG] Before creation of the Aggregator prover"
<< std::endl;
aggregator_circuit<wppT, wsnarkT, nverifierT, batch_size> aggregator_prover(
num_zeth_inputs);
std::cout << "[DEBUG] Before gen Aggregator setup" << std::endl;
typename wsnarkT::keypair aggregator_keypair =
aggregator_prover.generate_trusted_setup();
std::cout << "[DEBUG] Before first test" << std::endl;
bool res = false;
res = test_valid_aggregation_batch_proofs(
aggregator_prover, aggregator_keypair, zeth_keypair, batch);
ASSERT_TRUE(res);
}
template<typename nppT, typename wppT> void aggregator_test_groth16()
{
aggregator_test<
wppT,
libzeth::groth16_snark<wppT>,
libzecale::groth16_verifier_parameters<wppT>>();
}
template<typename nppT, typename wppT> void aggregator_test_pghr13()
{
aggregator_test<
wppT,
libzeth::pghr13_snark<wppT>,
libzecale::pghr13_verifier_parameters<wppT>>();
}
TEST(AggregatorTests, AggregatorBls12Bw6Groth16)
{
aggregator_test_groth16<libff::bls12_377_pp, libff::bw6_761_pp>();
}
#if 0 // TODO: Enable and fix this test
TEST(AggregatorTests, AggregatorMnt4Mnt6Pghr13)
{
aggregator_test_pghr13<libff::mnt4_pp, libff::mnt6_pp>();
}
#endif
} // namespace
int main(int argc, char **argv)
{
libff::start_profiling();
// Initialize the curve parameters before running the tests
libff::mnt4_pp::init_public_params();
libff::mnt6_pp::init_public_params();
libff::bls12_377_pp::init_public_params();
libff::bw6_761_pp::init_public_params();
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}