1use crate::Vec;
2
3use ark_crypto_primitives::{crh::CRHGadget, CRH};
4use ark_ff::fields::PrimeField;
5use ark_r1cs_std::{eq::EqGadget, fields::fp::FpVar, prelude::*};
6use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError};
7use ark_std::{cmp::Ordering::Less, marker::PhantomData};
8use arkworks_gadgets::{
9 arbitrary::vanchor_data::{
10 constraints::VAnchorArbitraryDataVar as ArbitraryInputVar,
11 VAnchorArbitraryData as ArbitraryInput,
12 },
13 keypair::vanchor::{constraints::KeypairVar, Keypair},
14 leaf::vanchor::{
15 constraints::{
16 PrivateVar as LeafPrivateInputsVar, PublicVar as LeafPublicInputsVar, VAnchorLeafGadget,
17 },
18 Private as LeafPrivateInputs, Public as LeafPublicInputs,
19 },
20 merkle_tree::{constraints::PathVar, Config as MerkleConfig, Path},
21 set::constraints::SetGadget,
22};
23
24pub struct VAnchorCircuit<
25 F: PrimeField,
26 H: CRH,
28 HG: CRHGadget<H, F>,
29 C: MerkleConfig,
31 LHGT: CRHGadget<C::LeafH, F>,
32 HGT: CRHGadget<C::H, F>,
33 const K: usize,
34 const N_INS: usize,
35 const N_OUTS: usize,
36 const M: usize,
37> {
38 public_amount: F,
39 ext_data_hash: ArbitraryInput<F>,
40
41 leaf_private_inputs: Vec<LeafPrivateInputs<F>>, keypair_inputs: Vec<Keypair<F, H>>,
43 leaf_public_input: LeafPublicInputs<F>, root_set: [F; M],
45 hasher_params_w2: H::Parameters,
46 hasher_params_w4: H::Parameters,
47 hasher_params_w5: H::Parameters,
48 paths: Vec<Path<C, K>>,
49 indices: Vec<F>,
50 nullifier_hash: Vec<H::Output>,
51
52 output_commitment: Vec<H::Output>,
53 out_leaf_private: Vec<LeafPrivateInputs<F>>,
54 out_leaf_public: Vec<LeafPublicInputs<F>>,
55 out_pubkey: Vec<F>,
56
57 _hasher: PhantomData<H>,
58 _hasher_gadget: PhantomData<HG>,
59 _leaf_hasher_gadget: PhantomData<LHGT>,
60 _tree_hasher_gadget: PhantomData<HGT>,
61 _merkle_config: PhantomData<C>,
62}
63
64impl<
65 F,
66 H,
67 HG,
68 C,
69 LHGT,
70 HGT,
71 const K: usize,
72 const N_INS: usize,
73 const N_OUTS: usize,
74 const M: usize,
75 > VAnchorCircuit<F, H, HG, C, LHGT, HGT, K, N_INS, N_OUTS, M>
76where
77 F: PrimeField,
78 H: CRH,
79 HG: CRHGadget<H, F>,
80 C: MerkleConfig,
81 LHGT: CRHGadget<C::LeafH, F>,
82 HGT: CRHGadget<C::H, F>,
83{
84 #[allow(clippy::too_many_arguments)]
85 pub fn new(
86 public_amount: F,
87 ext_data_hash: ArbitraryInput<F>,
88 leaf_private_inputs: Vec<LeafPrivateInputs<F>>,
89 keypair_inputs: Vec<Keypair<F, H>>,
90 leaf_public_input: LeafPublicInputs<F>,
91 root_set: [F; M],
92 hasher_params_w2: H::Parameters,
93 hasher_params_w4: H::Parameters,
94 hasher_params_w5: H::Parameters,
95 paths: Vec<Path<C, K>>,
96 indices: Vec<F>,
97 nullifier_hash: Vec<H::Output>,
98 output_commitment: Vec<H::Output>,
99 out_leaf_private: Vec<LeafPrivateInputs<F>>,
100 out_leaf_public: Vec<LeafPublicInputs<F>>,
101 out_pubkey: Vec<F>,
102 ) -> Self {
103 Self {
104 public_amount,
105 ext_data_hash,
106 leaf_private_inputs,
107 keypair_inputs,
108 leaf_public_input,
109 root_set,
110 hasher_params_w2,
111 hasher_params_w4,
112 hasher_params_w5,
113 paths,
114 indices,
115 nullifier_hash,
116 output_commitment,
117 out_leaf_private,
118 out_leaf_public,
119 out_pubkey,
120 _hasher: PhantomData,
121 _hasher_gadget: PhantomData,
122 _leaf_hasher_gadget: PhantomData,
123 _tree_hasher_gadget: PhantomData,
124 _merkle_config: PhantomData,
125 }
126 }
127
128 #[allow(clippy::too_many_arguments)]
129 pub fn verify_input_var(
130 hasher_params_w2_var: &HG::ParametersVar,
131 hasher_params_w4_var: &HG::ParametersVar,
132 hasher_params_w5_var: &HG::ParametersVar,
133 leaf_private_var: &[LeafPrivateInputsVar<F>],
134 inkeypair_var: &[KeypairVar<F, H, HG>],
135 leaf_public_input_var: &LeafPublicInputsVar<F>,
136 in_path_indices_var: &[FpVar<F>],
137 in_path_elements_var: &[PathVar<F, C, HGT, LHGT, K>],
138 in_nullifier_var: &[HG::OutputVar],
139 set_gadget: &SetGadget<F>,
140 ) -> Result<FpVar<F>, SynthesisError> {
141 let mut sums_ins_var = FpVar::<F>::zero();
142
143 for tx in 0..N_INS {
144 let pub_key = inkeypair_var[tx].public_key(hasher_params_w2_var)?;
146 let in_utxo_hasher_var = VAnchorLeafGadget::<F, H, HG>::create_leaf(
148 &leaf_private_var[tx],
149 leaf_public_input_var,
150 &pub_key,
151 hasher_params_w5_var,
152 )?;
153 let signature = inkeypair_var[tx].signature(
156 &in_utxo_hasher_var,
157 &in_path_indices_var[tx],
158 hasher_params_w4_var,
159 )?;
160 let nullifier_hash = VAnchorLeafGadget::<F, H, HG>::create_nullifier(
162 &signature,
163 &in_utxo_hasher_var,
164 hasher_params_w4_var,
165 &in_path_indices_var[tx],
166 )?;
167
168 nullifier_hash.enforce_equal(&in_nullifier_var[tx])?;
169
170 let roothash = &in_path_elements_var[tx].root_hash(&in_utxo_hasher_var)?;
172 let in_amount_tx = &leaf_private_var[tx].amount;
173
174 let check = set_gadget.check_membership_enabled(&roothash, in_amount_tx)?;
176 check.enforce_equal(&Boolean::TRUE)?;
177
178 sums_ins_var += in_amount_tx;
179 }
180 Ok(sums_ins_var)
181 }
182
183 pub fn verify_output_var(
185 hasher_params_w5_var: &HG::ParametersVar,
186 output_commitment_var: &[HG::OutputVar],
187 leaf_private_var: &[LeafPrivateInputsVar<F>],
188 leaf_public_var: &[LeafPublicInputsVar<F>],
189 out_pubkey_var: &[FpVar<F>],
190 limit_var: &FpVar<F>,
191 ) -> Result<FpVar<F>, SynthesisError> {
192 let mut sums_outs_var = FpVar::<F>::zero();
193
194 for tx in 0..N_OUTS {
195 let out_utxo_hasher_var = VAnchorLeafGadget::<F, H, HG>::create_leaf(
197 &leaf_private_var[tx],
198 &leaf_public_var[tx],
199 &out_pubkey_var[tx],
200 hasher_params_w5_var,
201 )?;
202 let out_amount_var = &leaf_private_var[tx].amount;
204 out_utxo_hasher_var.enforce_equal(&output_commitment_var[tx])?;
205
206 out_amount_var.enforce_cmp_unchecked(limit_var, Less, false)?;
208
209 sums_outs_var += out_amount_var;
210 }
211 Ok(sums_outs_var)
212 }
213
214 pub fn verify_no_same_nul(in_nullifier_var: &[HG::OutputVar]) -> Result<(), SynthesisError> {
216 for i in 0..N_INS - 1 {
217 for j in (i + 1)..N_INS {
218 in_nullifier_var[i].enforce_not_equal(&in_nullifier_var[j])?;
219 }
220 }
221
222 Ok(())
223 }
224
225 pub fn verify_input_invariant(
227 public_amount_var: &FpVar<F>,
228 sum_ins_var: &FpVar<F>,
229 sum_outs_var: &FpVar<F>,
230 ) -> Result<(), SynthesisError> {
231 let res = sum_ins_var + public_amount_var;
232 res.enforce_equal(sum_outs_var)?;
233 Ok(())
234 }
235}
236
237impl<
238 F,
239 H,
240 HG,
241 C,
242 LHGT,
243 HGT,
244 const K: usize,
245 const N_INS: usize,
246 const N_OUTS: usize,
247 const M: usize,
248 > Clone for VAnchorCircuit<F, H, HG, C, LHGT, HGT, K, N_INS, N_OUTS, M>
249where
250 F: PrimeField,
251 H: CRH,
252 HG: CRHGadget<H, F>,
253 C: MerkleConfig,
254 LHGT: CRHGadget<C::LeafH, F>,
255 HGT: CRHGadget<C::H, F>,
256{
257 fn clone(&self) -> Self {
258 let public_amount = self.public_amount;
259 let ext_data_hash = self.ext_data_hash.clone();
260 let leaf_private_inputs = self.leaf_private_inputs.clone();
261 let leaf_public_input = self.leaf_public_input.clone();
262 let root_set = self.root_set;
263 let hasher_params_w2 = self.hasher_params_w2.clone();
264 let hasher_params_w4 = self.hasher_params_w4.clone();
265 let hasher_params_w5 = self.hasher_params_w5.clone();
266 let paths = self.paths.clone();
267 let indices = self.indices.clone();
268 let nullifier_hash = self.nullifier_hash.clone();
269 let keypair_inputs = self.keypair_inputs.clone();
270 let output_commitment = self.output_commitment.clone();
271 let out_leaf_private = self.out_leaf_private.clone();
272 let out_leaf_public = self.out_leaf_public.clone();
273 let out_pubkey = self.out_pubkey.clone();
274
275 Self::new(
276 public_amount,
277 ext_data_hash,
278 leaf_private_inputs,
279 keypair_inputs,
280 leaf_public_input,
281 root_set,
282 hasher_params_w2,
283 hasher_params_w4,
284 hasher_params_w5,
285 paths,
286 indices,
287 nullifier_hash,
288 output_commitment,
289 out_leaf_private,
290 out_leaf_public,
291 out_pubkey,
292 )
293 }
294}
295
296impl<
297 F,
298 H,
299 HG,
300 C,
301 LHGT,
302 HGT,
303 const K: usize,
304 const N_INS: usize,
305 const N_OUTS: usize,
306 const M: usize,
307 > ConstraintSynthesizer<F> for VAnchorCircuit<F, H, HG, C, LHGT, HGT, K, N_INS, N_OUTS, M>
308where
309 F: PrimeField,
310 H: CRH,
311 HG: CRHGadget<H, F>,
312 C: MerkleConfig,
313 LHGT: CRHGadget<C::LeafH, F>,
314 HGT: CRHGadget<C::H, F>,
315{
316 fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
317 let public_amount = self.public_amount;
318 let ext_data_hash = self.ext_data_hash;
319 let leaf_private = self.leaf_private_inputs; let keypair_inputs = self.keypair_inputs;
321 let leaf_public_input = self.leaf_public_input; let root_set = self.root_set;
323 let hasher_params_w2 = self.hasher_params_w2;
324 let hasher_params_w4 = self.hasher_params_w4;
325 let hasher_params_w5 = self.hasher_params_w5;
326 let paths = self.paths;
327 let indices = self.indices;
328 let nullifier_hash = self.nullifier_hash;
329
330 let output_commitment = self.output_commitment;
331 let out_leaf_private = self.out_leaf_private;
332 let out_leaf_public = self.out_leaf_public;
333 let out_pubkey = self.out_pubkey;
334
335 let limit: F = F::from_str(
338 "452312848583266388373324160190187140051835877600158453279131187530910662656",
339 )
340 .unwrap_or_default();
341 assert_ne!(limit, F::default());
343
344 let public_amount_var = FpVar::<F>::new_input(cs.clone(), || Ok(public_amount))?;
347 let arbitrary_input_var = ArbitraryInputVar::new_input(cs.clone(), || Ok(ext_data_hash))?;
348 let in_nullifier_var = Vec::<HG::OutputVar>::new_input(cs.clone(), || Ok(nullifier_hash))?;
349 let output_commitment_var =
350 Vec::<HG::OutputVar>::new_input(cs.clone(), || Ok(output_commitment))?;
351 let leaf_public_input_var =
352 LeafPublicInputsVar::new_input(cs.clone(), || Ok(leaf_public_input))?;
353 let root_set_var = Vec::<FpVar<F>>::new_input(cs.clone(), || Ok(root_set))?;
354
355 let limit_var: FpVar<F> = FpVar::<F>::new_constant(cs.clone(), limit)?;
357 let hasher_params_w2_var = HG::ParametersVar::new_constant(cs.clone(), hasher_params_w2)?;
358 let hasher_params_w4_var = HG::ParametersVar::new_constant(cs.clone(), hasher_params_w4)?;
359 let hasher_params_w5_var = HG::ParametersVar::new_constant(cs.clone(), hasher_params_w5)?;
360
361 let leaf_private_var =
363 Vec::<LeafPrivateInputsVar<F>>::new_witness(cs.clone(), || Ok(leaf_private))?;
364 let inkeypair_var =
365 Vec::<KeypairVar<F, H, HG>>::new_witness(cs.clone(), || Ok(keypair_inputs))?;
366 let in_path_elements_var =
367 Vec::<PathVar<F, C, HGT, LHGT, K>>::new_witness(cs.clone(), || Ok(paths))?;
368 let in_path_indices_var = Vec::<FpVar<F>>::new_witness(cs.clone(), || Ok(indices))?;
369
370 let out_leaf_private_var =
372 Vec::<LeafPrivateInputsVar<F>>::new_witness(cs.clone(), || Ok(out_leaf_private))?;
373 let out_leaf_public_var =
374 Vec::<LeafPublicInputsVar<F>>::new_witness(cs.clone(), || Ok(out_leaf_public))?;
375 let out_pubkey_var = Vec::<FpVar<F>>::new_witness(cs, || Ok(out_pubkey))?;
376
377 let set_gadget = SetGadget::new(root_set_var);
378 let sum_ins_var = Self::verify_input_var(
380 &hasher_params_w2_var,
381 &hasher_params_w4_var,
382 &hasher_params_w5_var,
383 &leaf_private_var,
384 &inkeypair_var,
385 &leaf_public_input_var,
386 &in_path_indices_var,
387 &in_path_elements_var,
388 &in_nullifier_var,
389 &set_gadget,
390 )?;
391
392 let sum_outs_var = Self::verify_output_var(
394 &hasher_params_w5_var,
395 &output_commitment_var,
396 &out_leaf_private_var,
397 &out_leaf_public_var,
398 &out_pubkey_var,
399 &limit_var,
400 )?;
401
402 Self::verify_no_same_nul(&in_nullifier_var)?;
404
405 Self::verify_input_invariant(&public_amount_var, &sum_ins_var, &sum_outs_var)?;
407
408 arbitrary_input_var.constrain()?;
410
411 Ok(())
412 }
413}
414
415#[cfg(test)]
416mod test {
417 use ark_std::vec;
418
419 use crate::{
420 ark_std::{One, Zero},
421 setup::{common::*, vanchor::VAnchorProverBn2542x2},
422 };
423 use ark_serialize::CanonicalDeserialize;
424 use arkworks_utils::{
425 poseidon::PoseidonParameters,
426 utils::common::{
427 setup_params_x5_2, setup_params_x5_3, setup_params_x5_4, setup_params_x5_5, Curve,
428 },
429 };
430
431 use ark_bn254::{Bn254, Fr as BnFr};
432 use ark_ff::UniformRand;
433 use ark_groth16::{Groth16, Proof, VerifyingKey};
434
435 use crate::prelude::ark_std::str::FromStr;
436 use ark_snark::SNARK;
437 use ark_std::test_rng;
438
439 #[test]
440 fn should_create_proof_for_random_circuit() {
441 let rng = &mut test_rng();
442 let curve = Curve::Bn254;
443 let params2 = setup_params_x5_2::<BnFr>(curve);
444 let params3 = setup_params_x5_3::<BnFr>(curve);
445 let params4 = setup_params_x5_4::<BnFr>(curve);
446 let params5 = setup_params_x5_5::<BnFr>(curve);
447
448 let prover = VAnchorProverBn2542x2::new(params2, params3, params4, params5);
450 let random_circuit = prover.clone().setup_random_circuit(rng).unwrap();
451 let (proving_key, verifying_key) = setup_keys::<Bn254, _, _>(random_circuit, rng).unwrap();
452
453 let public_amount = BnFr::from(10u32);
455 let ext_data_hash = BnFr::rand(rng);
456
457 let in_chain_id = BnFr::from(0u32);
459 let in_amount = BnFr::from(5u32);
460 let index = BnFr::from(0u32);
461 let in_utxo1 = prover
462 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
463 .unwrap();
464 let in_utxo2 = prover
465 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
466 .unwrap();
467 let in_utxos = [in_utxo1, in_utxo2];
468
469 let out_chain_id = BnFr::from(0u32);
471 let out_amount = BnFr::from(10u32);
472 let out_utxo1 = prover
473 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
474 .unwrap();
475 let out_utxo2 = prover
476 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
477 .unwrap();
478 let out_utxos = [out_utxo1, out_utxo2];
479
480 let leaf0 = in_utxo1.commitment;
481 let (in_path0, _) = prover.setup_tree(&vec![leaf0], 0).unwrap();
482 let root0 = in_path0.root_hash(&leaf0).unwrap().inner();
483 let leaf1 = in_utxo2.commitment;
484 let (in_path1, _) = prover.setup_tree(&vec![leaf1], 0).unwrap();
485 let root1 = in_path1.root_hash(&leaf1).unwrap().inner();
486
487 let in_leaves = [vec![leaf0], vec![leaf1]];
488 let in_indices = [0; 2];
489 let in_root_set = [root0, root1];
490
491 let (circuit, .., pub_ins) = prover
492 .setup_circuit_with_utxos(
493 public_amount,
494 ext_data_hash,
495 in_root_set,
496 in_indices,
497 in_leaves,
498 in_utxos,
499 out_utxos,
500 )
501 .unwrap();
502
503 let proof = prove::<Bn254, _, _>(circuit, &proving_key, rng).unwrap();
504 let res = verify::<Bn254>(&pub_ins, &verifying_key, &proof).unwrap();
505
506 assert!(res);
507 }
508
509 #[test]
510 fn should_create_circuit_and_prove_groth16_2_input_2_output() {
511 let rng = &mut test_rng();
512 let curve = Curve::Bn254;
513 let params2: PoseidonParameters<BnFr> = setup_params_x5_2(curve);
514 let params3: PoseidonParameters<BnFr> = setup_params_x5_3(curve);
515 let params4: PoseidonParameters<BnFr> = setup_params_x5_4(curve);
516 let params5: PoseidonParameters<BnFr> = setup_params_x5_5(curve);
517 let prover = VAnchorProverBn2542x2::new(params2, params3, params4, params5);
518
519 let public_amount = BnFr::from(10u32);
520 let ext_data_hash = BnFr::rand(rng);
521
522 let in_chain_id = BnFr::from(0u32);
524 let in_amount = BnFr::from(5u32);
525 let index = BnFr::from(0u32);
526 let in_utxo1 = prover
527 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
528 .unwrap();
529 let in_utxo2 = prover
530 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
531 .unwrap();
532 let in_utxos = [in_utxo1, in_utxo2];
533
534 let out_chain_id = BnFr::from(0u32);
536 let out_amount = BnFr::from(10u32);
537 let out_utxo1 = prover
538 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
539 .unwrap();
540 let out_utxo2 = prover
541 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
542 .unwrap();
543 let out_utxos = [out_utxo1, out_utxo2];
544
545 let leaf0 = in_utxo1.commitment;
546 let (in_path0, _) = prover.setup_tree(&vec![leaf0], 0).unwrap();
547 let root0 = in_path0.root_hash(&leaf0).unwrap().inner();
548 let leaf1 = in_utxo2.commitment;
549 let (in_path1, _) = prover.setup_tree(&vec![leaf1], 0).unwrap();
550 let root1 = in_path1.root_hash(&leaf1).unwrap().inner();
551
552 let in_leaves = [vec![leaf0], vec![leaf1]];
553 let in_indices = [0; 2];
554 let in_root_set = [root0, root1];
555
556 let (circuit, .., pub_ins) = prover
557 .setup_circuit_with_utxos(
558 public_amount,
559 ext_data_hash,
560 in_root_set,
561 in_indices,
562 in_leaves,
563 in_utxos,
564 out_utxos,
565 )
566 .unwrap();
567
568 let (proving_key, verifying_key) = setup_keys::<Bn254, _, _>(circuit.clone(), rng).unwrap();
569 let proof = prove::<Bn254, _, _>(circuit, &proving_key, rng).unwrap();
570 let res = verify::<Bn254>(&pub_ins, &verifying_key, &proof).unwrap();
571
572 assert!(res);
573 }
574
575 #[test]
576 fn should_fail_with_invalid_root() {
577 let rng = &mut test_rng();
578 let curve = Curve::Bn254;
579 let params2: PoseidonParameters<BnFr> = setup_params_x5_2(curve);
580 let params3: PoseidonParameters<BnFr> = setup_params_x5_3(curve);
581 let params4: PoseidonParameters<BnFr> = setup_params_x5_4(curve);
582 let params5: PoseidonParameters<BnFr> = setup_params_x5_5(curve);
583 let prover = VAnchorProverBn2542x2::new(params2, params3, params4, params5);
584
585 let public_amount = BnFr::from(10u32);
586 let ext_data_hash = BnFr::rand(rng);
587
588 let in_chain_id = BnFr::from(0u32);
590 let in_amount = BnFr::from(5u32);
591 let index = BnFr::from(0u32);
592 let in_utxo1 = prover
593 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
594 .unwrap();
595 let in_utxo2 = prover
596 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
597 .unwrap();
598 let in_utxos = [in_utxo1, in_utxo2];
599
600 let out_chain_id = BnFr::from(0u32);
602 let out_amount = BnFr::from(10u32);
603 let out_utxo1 = prover
604 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
605 .unwrap();
606 let out_utxo2 = prover
607 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
608 .unwrap();
609 let out_utxos = [out_utxo1, out_utxo2];
610
611 let leaf0 = in_utxos[0].commitment;
612 let leaf1 = in_utxos[1].commitment;
613
614 let in_leaves = [vec![leaf0], vec![leaf1]];
615 let in_indices = [0; 2];
616
617 let in_root_set = [BnFr::rand(rng); 2];
619
620 let (circuit, .., pub_ins) = prover
621 .setup_circuit_with_utxos(
622 public_amount,
623 ext_data_hash,
624 in_root_set,
625 in_indices,
626 in_leaves,
627 in_utxos,
628 out_utxos,
629 )
630 .unwrap();
631
632 let (proving_key, verifying_key) = setup_keys::<Bn254, _, _>(circuit.clone(), rng).unwrap();
633 let proof = prove::<Bn254, _, _>(circuit, &proving_key, rng).unwrap();
634 let res = verify::<Bn254>(&pub_ins, &verifying_key, &proof).unwrap();
635
636 assert!(!res);
637 }
638
639 #[test]
640 fn should_fail_with_invalid_nullifier() {
641 let rng = &mut test_rng();
642 let curve = Curve::Bn254;
643 let params2: PoseidonParameters<BnFr> = setup_params_x5_2(curve);
644 let params3: PoseidonParameters<BnFr> = setup_params_x5_3(curve);
645 let params4: PoseidonParameters<BnFr> = setup_params_x5_4(curve);
646 let params5: PoseidonParameters<BnFr> = setup_params_x5_5(curve);
647 let prover = VAnchorProverBn2542x2::new(params2, params3, params4, params5);
648
649 let public_amount = BnFr::from(10u32);
650 let ext_data_hash = BnFr::rand(rng);
651
652 let in_chain_id = BnFr::from(0u32);
654 let in_amount = BnFr::from(5u32);
655 let index = BnFr::from(0u32);
656 let mut in_utxo1 = prover
657 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
658 .unwrap();
659 let in_utxo2 = prover
660 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
661 .unwrap();
662
663 in_utxo1.nullifier = Some(BnFr::rand(rng));
665
666 let in_utxos = [in_utxo1, in_utxo2];
667
668 let out_chain_id = BnFr::from(0u32);
670 let out_amount = BnFr::from(10u32);
671 let out_utxo1 = prover
672 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
673 .unwrap();
674 let out_utxo2 = prover
675 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
676 .unwrap();
677 let out_utxos = [out_utxo1, out_utxo2];
678
679 let leaf0 = in_utxos[0].commitment;
680 let (in_path0, _) = prover.setup_tree(&vec![leaf0], 0).unwrap();
681 let root0 = in_path0.root_hash(&leaf0).unwrap().inner();
682 let leaf1 = in_utxos[1].commitment;
683 let (in_path1, _) = prover.setup_tree(&vec![leaf1], 0).unwrap();
684 let root1 = in_path1.root_hash(&leaf1).unwrap().inner();
685
686 let in_leaves = [vec![leaf0], vec![leaf1]];
687 let in_indices = [0; 2];
688 let in_root_set = [root0, root1];
689
690 let (circuit, .., pub_ins) = prover
691 .setup_circuit_with_utxos(
692 public_amount,
693 ext_data_hash,
694 in_root_set,
695 in_indices,
696 in_leaves,
697 in_utxos,
698 out_utxos,
699 )
700 .unwrap();
701
702 let (proving_key, verifying_key) = setup_keys::<Bn254, _, _>(circuit.clone(), rng).unwrap();
703 let proof = prove::<Bn254, _, _>(circuit, &proving_key, rng).unwrap();
704 let res = verify::<Bn254>(&pub_ins, &verifying_key, &proof).unwrap();
705
706 assert!(!res);
707 }
708
709 #[test]
710 #[ignore]
711 fn should_fail_with_same_nullifier() {
712 let rng = &mut test_rng();
713 let curve = Curve::Bn254;
714 let params2: PoseidonParameters<BnFr> = setup_params_x5_2(curve);
715 let params3: PoseidonParameters<BnFr> = setup_params_x5_3(curve);
716 let params4: PoseidonParameters<BnFr> = setup_params_x5_4(curve);
717 let params5: PoseidonParameters<BnFr> = setup_params_x5_5(curve);
718 let prover = VAnchorProverBn2542x2::new(params2, params3, params4, params5);
719
720 let public_amount = BnFr::from(0u32);
721 let ext_data_hash = BnFr::rand(rng);
722
723 let in_chain_id = BnFr::from(0u32);
725 let in_amount = BnFr::from(5u32);
726 let index = BnFr::from(0u32);
727 let in_utxo1 = prover
728 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
729 .unwrap();
730
731 let in_utxos = [in_utxo1, in_utxo1];
733
734 let out_chain_id = BnFr::from(0u32);
736 let out_amount = BnFr::from(10u32);
737 let out_utxo1 = prover
738 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
739 .unwrap();
740 let out_utxo2 = prover
741 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
742 .unwrap();
743 let out_utxos = [out_utxo1, out_utxo2];
744
745 let leaf0 = in_utxos[0].commitment;
746 let (in_path0, _) = prover.setup_tree(&vec![leaf0], 0).unwrap();
747 let root0 = in_path0.root_hash(&leaf0).unwrap().inner();
748 let leaf1 = in_utxos[1].commitment;
749 let (in_path1, _) = prover.setup_tree(&vec![leaf1], 0).unwrap();
750 let root1 = in_path1.root_hash(&leaf1).unwrap().inner();
751
752 let in_leaves = [vec![leaf0], vec![leaf1]];
753 let in_indices = [0; 2];
754 let in_root_set = [root0, root1];
755
756 let (circuit, .., pub_ins) = prover
757 .setup_circuit_with_utxos(
758 public_amount,
759 ext_data_hash,
760 in_root_set,
761 in_indices,
762 in_leaves,
763 in_utxos,
764 out_utxos,
765 )
766 .unwrap();
767
768 let (proving_key, verifying_key) = setup_keys::<Bn254, _, _>(circuit.clone(), rng).unwrap();
769 let proof = prove::<Bn254, _, _>(circuit, &proving_key, rng).unwrap();
770 let res = verify::<Bn254>(&pub_ins, &verifying_key, &proof).unwrap();
771
772 assert!(!res);
773 }
774
775 #[test]
776 fn should_fail_with_inconsistent_input_output_values() {
777 let rng = &mut test_rng();
778 let curve = Curve::Bn254;
779 let params2: PoseidonParameters<BnFr> = setup_params_x5_2(curve);
780 let params3: PoseidonParameters<BnFr> = setup_params_x5_3(curve);
781 let params4: PoseidonParameters<BnFr> = setup_params_x5_4(curve);
782 let params5: PoseidonParameters<BnFr> = setup_params_x5_5(curve);
783 let prover = VAnchorProverBn2542x2::new(params2, params3, params4, params5);
784
785 let public_amount = BnFr::from(10u32);
786 let ext_data_hash = BnFr::rand(rng);
787
788 let in_chain_id = BnFr::from(0u32);
790 let in_amount = BnFr::from(10u32);
792 let index = BnFr::from(0u32);
793 let in_utxo1 = prover
794 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
795 .unwrap();
796 let in_utxo2 = prover
797 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
798 .unwrap();
799 let in_utxos = [in_utxo1, in_utxo2];
800
801 let out_chain_id = BnFr::from(0u32);
803 let out_amount = BnFr::from(10u32);
804 let out_utxo1 = prover
805 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
806 .unwrap();
807 let out_utxo2 = prover
808 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
809 .unwrap();
810 let out_utxos = [out_utxo1, out_utxo2];
811
812 let leaf0 = in_utxos[0].commitment;
813 let (in_path0, _) = prover.setup_tree(&vec![leaf0], 0).unwrap();
814 let root0 = in_path0.root_hash(&leaf0).unwrap().inner();
815 let leaf1 = in_utxos[1].commitment;
816 let (in_path1, _) = prover.setup_tree(&vec![leaf1], 0).unwrap();
817 let root1 = in_path1.root_hash(&leaf1).unwrap().inner();
818
819 let in_leaves = [vec![leaf0], vec![leaf1]];
820 let in_indices = [0; 2];
821 let in_root_set = [root0, root1];
822
823 let (circuit, .., pub_ins) = prover
824 .setup_circuit_with_utxos(
825 public_amount,
826 ext_data_hash,
827 in_root_set,
828 in_indices,
829 in_leaves,
830 in_utxos,
831 out_utxos,
832 )
833 .unwrap();
834
835 let (proving_key, verifying_key) = setup_keys::<Bn254, _, _>(circuit.clone(), rng).unwrap();
836 let proof = prove::<Bn254, _, _>(circuit, &proving_key, rng).unwrap();
837 let res = verify::<Bn254>(&pub_ins, &verifying_key, &proof).unwrap();
838
839 assert!(!res);
840 }
841
842 #[test]
843 fn should_fail_with_big_amount() {
844 let rng = &mut test_rng();
845 let curve = Curve::Bn254;
846 let params2: PoseidonParameters<BnFr> = setup_params_x5_2(curve);
847 let params3: PoseidonParameters<BnFr> = setup_params_x5_3(curve);
848 let params4: PoseidonParameters<BnFr> = setup_params_x5_4(curve);
849 let params5: PoseidonParameters<BnFr> = setup_params_x5_5(curve);
850 let prover = VAnchorProverBn2542x2::new(params2, params3, params4, params5);
851
852 let limit = BnFr::from_str(
854 "452312848583266388373324160190187140051835877600158453279131187530910662656",
855 )
856 .unwrap();
857
858 let public_amount = BnFr::zero();
859 let ext_data_hash = BnFr::rand(rng);
860
861 let in_chain_id = BnFr::from(0u32);
863 let in_amount = BnFr::from(limit + BnFr::one());
864 let index = BnFr::from(0u32);
865 let in_utxo1 = prover
866 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
867 .unwrap();
868 let in_utxo2 = prover
869 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
870 .unwrap();
871 let in_utxos = [in_utxo1, in_utxo2];
872
873 let out_chain_id = BnFr::from(0u32);
875 let out_amount = BnFr::from(10u32);
876 let out_utxo1 = prover
877 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
878 .unwrap();
879 let out_utxo2 = prover
880 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
881 .unwrap();
882 let out_utxos = [out_utxo1, out_utxo2];
883
884 let leaf0 = in_utxos[0].commitment;
885 let (in_path0, _) = prover.setup_tree(&vec![leaf0], 0).unwrap();
886 let root0 = in_path0.root_hash(&leaf0).unwrap().inner();
887 let leaf1 = in_utxos[1].commitment;
888 let (in_path1, _) = prover.setup_tree(&vec![leaf1], 0).unwrap();
889 let root1 = in_path1.root_hash(&leaf1).unwrap().inner();
890
891 let in_leaves = [vec![leaf0], vec![leaf1]];
892 let in_indices = [0; 2];
893 let in_root_set = [root0, root1];
894
895 let (circuit, .., pub_ins) = prover
896 .setup_circuit_with_utxos(
897 public_amount,
898 ext_data_hash,
899 in_root_set,
900 in_indices,
901 in_leaves,
902 in_utxos,
903 out_utxos,
904 )
905 .unwrap();
906
907 let (proving_key, verifying_key) = setup_keys::<Bn254, _, _>(circuit.clone(), rng).unwrap();
908 let proof = prove::<Bn254, _, _>(circuit, &proving_key, rng).unwrap();
909 let res = verify::<Bn254>(&pub_ins, &verifying_key, &proof).unwrap();
910
911 assert!(!res);
912 }
913
914 #[test]
915 fn should_fail_with_invalid_public_input() {
916 let rng = &mut test_rng();
917 let curve = Curve::Bn254;
918 let params2: PoseidonParameters<BnFr> = setup_params_x5_2(curve);
919 let params3: PoseidonParameters<BnFr> = setup_params_x5_3(curve);
920 let params4: PoseidonParameters<BnFr> = setup_params_x5_4(curve);
921 let params5: PoseidonParameters<BnFr> = setup_params_x5_5(curve);
922 let prover = VAnchorProverBn2542x2::new(params2, params3, params4, params5);
923
924 let public_amount = BnFr::from(0u32);
925 let ext_data_hash = BnFr::rand(rng);
926
927 let in_chain_id = BnFr::from(0u32);
929 let in_amount = BnFr::from(5u32);
930 let index = BnFr::from(0u32);
931 let in_utxo1 = prover
932 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
933 .unwrap();
934 let in_utxo2 = prover
935 .new_utxo(in_chain_id, in_amount, Some(index), None, None, rng)
936 .unwrap();
937 let in_utxos = [in_utxo1, in_utxo2];
938
939 let out_chain_id = BnFr::from(0u32);
941 let out_amount = BnFr::from(10u32);
942 let out_utxo1 = prover
943 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
944 .unwrap();
945 let out_utxo2 = prover
946 .new_utxo(out_chain_id, out_amount, None, None, None, rng)
947 .unwrap();
948 let out_utxos = [out_utxo1, out_utxo2];
949
950 let leaf0 = in_utxos[0].commitment;
951 let (in_path0, _) = prover.setup_tree(&vec![leaf0], 0).unwrap();
952 let root0 = in_path0.root_hash(&leaf0).unwrap().inner();
953 let leaf1 = in_utxos[1].commitment;
954 let (in_path1, _) = prover.setup_tree(&vec![leaf1], 0).unwrap();
955 let root1 = in_path1.root_hash(&leaf1).unwrap().inner();
956
957 let in_leaves = [vec![leaf0], vec![leaf1]];
958 let in_indices = [0; 2];
959 let in_root_set = [root0, root1];
960
961 let (circuit, .., pub_ins) = prover
962 .setup_circuit_with_utxos(
963 public_amount,
964 ext_data_hash,
965 in_root_set,
966 in_indices,
967 in_leaves,
968 in_utxos,
969 out_utxos,
970 )
971 .unwrap();
972
973 let truncated_public_inputs = &pub_ins[2..];
974 let (proving_key, verifying_key) = setup_keys::<Bn254, _, _>(circuit.clone(), rng).unwrap();
975 let proof = prove::<Bn254, _, _>(circuit, &proving_key, rng).unwrap();
976
977 let vk = VerifyingKey::<Bn254>::deserialize(&verifying_key[..]).unwrap();
978 let proof = Proof::<Bn254>::deserialize(&proof[..]).unwrap();
979 let res = Groth16::<Bn254>::verify(&vk, truncated_public_inputs, &proof);
980
981 assert!(res.is_err());
982 }
983}