arkworks_circuits/circuit/
anchor.rs

1use ark_crypto_primitives::{crh::CRHGadget, CRH};
2use ark_ff::fields::PrimeField;
3use ark_r1cs_std::{eq::EqGadget, fields::fp::FpVar, prelude::*};
4use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError};
5use ark_std::{marker::PhantomData, vec::Vec};
6use arkworks_gadgets::{
7	arbitrary::anchor_data::{constraints::InputVar as ArbitraryInputVar, Input as ArbitraryInput},
8	leaf::anchor::{
9		constraints::{
10			AnchorLeafGadget, PrivateVar as LeafPrivateInputsVar, PublicVar as LeafPublicInputsVar,
11		},
12		Private as LeafPrivateInputs, Public as LeafPublicInputs,
13	},
14	merkle_tree::{constraints::PathVar, Config as MerkleConfig, Path},
15	set::constraints::SetGadget,
16};
17
18pub struct AnchorCircuit<
19	F: PrimeField,
20	// Hasher for the leaf creation
21	H: CRH,
22	HG: CRHGadget<H, F>,
23	// Merkle config and hasher gadget for the tree
24	C: MerkleConfig,
25	LHGT: CRHGadget<C::LeafH, F>,
26	HGT: CRHGadget<C::H, F>,
27	const N: usize,
28	const M: usize,
29> {
30	arbitrary_input: ArbitraryInput<F>,
31	leaf_private_inputs: LeafPrivateInputs<F>,
32	leaf_public_inputs: LeafPublicInputs<F>,
33	root_set: [F; M],
34	hasher_params: H::Parameters,
35	path: Path<C, N>,
36	nullifier_hash: H::Output,
37	_hasher: PhantomData<H>,
38	_hasher_gadget: PhantomData<HG>,
39	_leaf_hasher_gadget: PhantomData<LHGT>,
40	_tree_hasher_gadget: PhantomData<HGT>,
41	_merkle_config: PhantomData<C>,
42}
43
44impl<F, H, HG, C, LHGT, HGT, const N: usize, const M: usize>
45	AnchorCircuit<F, H, HG, C, LHGT, HGT, N, M>
46where
47	F: PrimeField,
48	H: CRH,
49	HG: CRHGadget<H, F>,
50	C: MerkleConfig,
51	LHGT: CRHGadget<C::LeafH, F>,
52	HGT: CRHGadget<C::H, F>,
53{
54	#[allow(clippy::too_many_arguments)]
55	pub fn new(
56		arbitrary_input: ArbitraryInput<F>,
57		leaf_private_inputs: LeafPrivateInputs<F>,
58		leaf_public_inputs: LeafPublicInputs<F>,
59		root_set: [F; M],
60		hasher_params: H::Parameters,
61		path: Path<C, N>,
62		nullifier_hash: H::Output,
63	) -> Self {
64		Self {
65			arbitrary_input,
66			leaf_private_inputs,
67			leaf_public_inputs,
68			root_set,
69			hasher_params,
70			path,
71			nullifier_hash,
72			_hasher: PhantomData,
73			_hasher_gadget: PhantomData,
74			_leaf_hasher_gadget: PhantomData,
75			_tree_hasher_gadget: PhantomData,
76			_merkle_config: PhantomData,
77		}
78	}
79}
80
81impl<F, H, HG, C, LHGT, HGT, const N: usize, const M: usize> Clone
82	for AnchorCircuit<F, H, HG, C, LHGT, HGT, N, M>
83where
84	F: PrimeField,
85	H: CRH,
86	HG: CRHGadget<H, F>,
87	C: MerkleConfig,
88	LHGT: CRHGadget<C::LeafH, F>,
89	HGT: CRHGadget<C::H, F>,
90{
91	fn clone(&self) -> Self {
92		let arbitrary_input = self.arbitrary_input.clone();
93		let leaf_private_inputs = self.leaf_private_inputs.clone();
94		let leaf_public_inputs = self.leaf_public_inputs.clone();
95		let root_set = self.root_set;
96		let hasher_params = self.hasher_params.clone();
97		let path = self.path.clone();
98		let nullifier_hash = self.nullifier_hash.clone();
99		Self::new(
100			arbitrary_input,
101			leaf_private_inputs,
102			leaf_public_inputs,
103			root_set,
104			hasher_params,
105			path,
106			nullifier_hash,
107		)
108	}
109}
110
111impl<F, H, HG, C, LHGT, HGT, const N: usize, const M: usize> ConstraintSynthesizer<F>
112	for AnchorCircuit<F, H, HG, C, LHGT, HGT, N, M>
113where
114	F: PrimeField,
115	H: CRH,
116	HG: CRHGadget<H, F>,
117	C: MerkleConfig,
118	LHGT: CRHGadget<C::LeafH, F>,
119	HGT: CRHGadget<C::H, F>,
120{
121	fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
122		let arbitrary_input = self.arbitrary_input;
123		let leaf_private = self.leaf_private_inputs;
124		let leaf_public = self.leaf_public_inputs;
125		let root_set = self.root_set;
126		let hasher_params = self.hasher_params;
127		let path = self.path;
128		let nullifier_hash = self.nullifier_hash;
129
130		// Generating vars
131		// Public inputs
132		let leaf_public_var = LeafPublicInputsVar::new_input(cs.clone(), || Ok(leaf_public))?;
133		let nullifier_hash_var = HG::OutputVar::new_input(cs.clone(), || Ok(nullifier_hash))?;
134		let roots_var = Vec::<FpVar<F>>::new_input(cs.clone(), || Ok(root_set))?;
135		let arbitrary_input_var = ArbitraryInputVar::new_input(cs.clone(), || Ok(arbitrary_input))?;
136
137		// Constants
138		let hasher_params_var = HG::ParametersVar::new_constant(cs.clone(), hasher_params)?;
139
140		// Private inputs
141		let leaf_private_var = LeafPrivateInputsVar::new_witness(cs.clone(), || Ok(leaf_private))?;
142		let path_var = PathVar::<F, C, HGT, LHGT, N>::new_witness(cs, || Ok(path))?;
143
144		// Creating the leaf and checking the membership inside the tree
145		let anchor_leaf = AnchorLeafGadget::<F, H, HG>::create_leaf(
146			&leaf_private_var,
147			&leaf_public_var,
148			&hasher_params_var,
149		)?;
150		let anchor_nullifier =
151			AnchorLeafGadget::<F, H, HG>::create_nullifier(&leaf_private_var, &hasher_params_var)?;
152		let root_var = path_var.root_hash(&anchor_leaf)?;
153		// Check if target root is in set
154		let set_gadget = SetGadget::new(roots_var);
155		let is_set_member = set_gadget.check_membership(&root_var)?;
156		// Constraining arbitrary inputs
157		arbitrary_input_var.constrain()?;
158
159		// Enforcing constraints
160		is_set_member.enforce_equal(&Boolean::TRUE)?;
161		anchor_nullifier.enforce_equal(&nullifier_hash_var)?;
162
163		Ok(())
164	}
165}
166
167#[cfg(test)]
168mod test {
169	use crate::setup::{anchor::*, common::*};
170	use ark_bn254::{Bn254, Fr as Bn254Fr};
171	use ark_ff::UniformRand;
172	use ark_groth16::Groth16;
173	use ark_snark::SNARK;
174	use ark_std::test_rng;
175	use arkworks_utils::utils::common::{setup_params_x5_3, setup_params_x5_4, Curve};
176
177	// merkle proof path legth
178	// TreeConfig_x5, x7 HEIGHT is hardcoded to 30
179	pub const TEST_N: usize = 30;
180	pub const TEST_M: usize = 2;
181	type AnchorSetup30_2 = AnchorProverSetup<Bn254Fr, TEST_M, TEST_N>;
182
183	#[test]
184	fn setup_random_anchor() {
185		let rng = &mut test_rng();
186		let curve = Curve::Bn254;
187
188		let params3 = setup_params_x5_3::<Bn254Fr>(curve);
189		let params4 = setup_params_x5_4::<Bn254Fr>(curve);
190		let anchor_setup = AnchorSetup30_2::new(params3, params4);
191
192		let chain_id = Bn254Fr::rand(rng);
193		let recipient = Bn254Fr::rand(rng);
194		let relayer = Bn254Fr::rand(rng);
195		let fee = Bn254Fr::rand(rng);
196		let refund = Bn254Fr::rand(rng);
197		let commitment = Bn254Fr::rand(rng);
198
199		let (leaf_private, _, leaf_hash, ..) = anchor_setup.setup_leaf(chain_id, rng).unwrap();
200		let secret = leaf_private.secret();
201		let nullfier = leaf_private.nullifier();
202		let leaves = vec![leaf_hash];
203		let index = 0;
204		let (tree, _) = anchor_setup.setup_tree_and_path(&leaves, index).unwrap();
205		let roots = [tree.root().inner(); M];
206
207		let (circuit, .., public_inputs) = anchor_setup
208			.clone()
209			.setup_circuit_with_privates(
210				chain_id, secret, nullfier, &leaves, index, roots, recipient, relayer, fee, refund,
211				commitment,
212			)
213			.unwrap();
214
215		// Using random circuit to generate pk/vk
216		let (random_circuit, ..) = anchor_setup.setup_random_circuit(rng).unwrap();
217		let (pk, vk) = setup_keys::<Bn254, _, _>(random_circuit, rng).unwrap();
218
219		// Using generated pk/vk to prove and verify the working version of the circuit
220		let proof = prove::<Bn254, _, _>(circuit, &pk, rng).unwrap();
221		let res = verify::<Bn254>(&public_inputs, &vk, &proof).unwrap();
222		assert!(res);
223	}
224
225	#[test]
226	fn setup_and_prove_anchor_groth16() {
227		let rng = &mut test_rng();
228		let curve = Curve::Bn254;
229
230		let params3 = setup_params_x5_3::<Bn254Fr>(curve);
231		let params4 = setup_params_x5_4::<Bn254Fr>(curve);
232		let anchor_setup = AnchorSetup30_2::new(params3, params4);
233
234		let chain_id = Bn254Fr::rand(rng);
235		let recipient = Bn254Fr::rand(rng);
236		let relayer = Bn254Fr::rand(rng);
237		let fee = Bn254Fr::rand(rng);
238		let refund = Bn254Fr::rand(rng);
239		let commitment = Bn254Fr::rand(rng);
240
241		let (leaf_private, _, leaf_hash, ..) = anchor_setup.setup_leaf(chain_id, rng).unwrap();
242		let secret = leaf_private.secret();
243		let nullfier = leaf_private.nullifier();
244		let leaves = vec![leaf_hash];
245		let index = 0;
246		let (tree, _) = anchor_setup.setup_tree_and_path(&leaves, index).unwrap();
247		let roots = [tree.root().inner(); M];
248
249		let (circuit, .., public_inputs) = anchor_setup
250			.setup_circuit_with_privates(
251				chain_id, secret, nullfier, &leaves, index, roots, recipient, relayer, fee, refund,
252				commitment,
253			)
254			.unwrap();
255
256		let (pk, vk) = setup_keys::<Bn254, _, _>(circuit.clone(), rng).unwrap();
257		let proof = prove::<Bn254, _, _>(circuit, &pk, rng).unwrap();
258		let res = verify::<Bn254>(&public_inputs, &vk, &proof).unwrap();
259		assert!(res);
260	}
261
262	#[test]
263	fn should_fail_with_invalid_public_inputs() {
264		let rng = &mut test_rng();
265		let curve = Curve::Bn254;
266
267		let params3 = setup_params_x5_3::<Bn254Fr>(curve);
268		let params4 = setup_params_x5_4::<Bn254Fr>(curve);
269		let anchor_setup = AnchorSetup30_2::new(params3, params4);
270
271		let chain_id = Bn254Fr::rand(rng);
272		let recipient = Bn254Fr::rand(rng);
273		let relayer = Bn254Fr::rand(rng);
274		let fee = Bn254Fr::rand(rng);
275		let refund = Bn254Fr::rand(rng);
276		let commitment = Bn254Fr::rand(rng);
277
278		let (leaf_private, _, leaf_hash, ..) = anchor_setup.setup_leaf(chain_id, rng).unwrap();
279		let secret = leaf_private.secret();
280		let nullfier = leaf_private.nullifier();
281		let leaves = vec![leaf_hash];
282		let index = 0;
283		let (tree, _) = anchor_setup.setup_tree_and_path(&leaves, index).unwrap();
284		let roots = [tree.root().inner(); M];
285
286		let (circuit, .., public_inputs) = anchor_setup
287			.setup_circuit_with_privates(
288				chain_id, secret, nullfier, &leaves, index, roots, recipient, relayer, fee, refund,
289				commitment,
290			)
291			.unwrap();
292
293		type GrothSetup = Groth16<Bn254>;
294
295		let (pk, vk) = GrothSetup::circuit_specific_setup(circuit.clone(), rng).unwrap();
296		let proof = GrothSetup::prove(&pk, circuit, rng).unwrap();
297
298		// Without chain_id and nullifier
299		let pi = public_inputs[2..].to_vec();
300		let res = GrothSetup::verify(&vk, &pi, &proof);
301		assert!(res.is_err());
302	}
303
304	#[test]
305	fn should_fail_with_invalid_set() {
306		let rng = &mut test_rng();
307		let curve = Curve::Bn254;
308
309		let params3 = setup_params_x5_3::<Bn254Fr>(curve);
310		let params4 = setup_params_x5_4::<Bn254Fr>(curve);
311		let anchor_setup = AnchorSetup30_2::new(params3, params4);
312
313		let chain_id = Bn254Fr::rand(rng);
314		let recipient = Bn254Fr::rand(rng);
315		let relayer = Bn254Fr::rand(rng);
316		let fee = Bn254Fr::rand(rng);
317		let refund = Bn254Fr::rand(rng);
318		let commitment = Bn254Fr::rand(rng);
319
320		let (leaf_private, _, leaf_hash, ..) = anchor_setup.setup_leaf(chain_id, rng).unwrap();
321		let secret = leaf_private.secret();
322		let nullfier = leaf_private.nullifier();
323		let leaves = vec![leaf_hash];
324		let index = 0;
325		let roots = [Bn254Fr::rand(rng); M];
326
327		let (mc, .., public_inputs) = anchor_setup
328			.setup_circuit_with_privates(
329				chain_id, secret, nullfier, &leaves, index, roots, recipient, relayer, fee, refund,
330				commitment,
331			)
332			.unwrap();
333
334		let (pk, vk) = setup_keys::<Bn254, _, _>(mc.clone(), rng).unwrap();
335		let proof = prove::<Bn254, _, _>(mc, &pk, rng).unwrap();
336		let res = verify::<Bn254>(&public_inputs, &vk, &proof).unwrap();
337		assert!(!res);
338	}
339
340	#[test]
341	fn should_fail_with_invalid_leaf() {
342		let rng = &mut test_rng();
343		let curve = Curve::Bn254;
344
345		let params3 = setup_params_x5_3::<Bn254Fr>(curve);
346		let params4 = setup_params_x5_4::<Bn254Fr>(curve);
347		let anchor_setup = AnchorSetup30_2::new(params3, params4);
348
349		let chain_id = Bn254Fr::rand(rng);
350		let recipient = Bn254Fr::rand(rng);
351		let relayer = Bn254Fr::rand(rng);
352		let fee = Bn254Fr::rand(rng);
353		let refund = Bn254Fr::rand(rng);
354		let commitment = Bn254Fr::rand(rng);
355
356		let (leaf_private, _, _, ..) = anchor_setup.setup_leaf(chain_id, rng).unwrap();
357		let secret = leaf_private.secret();
358		let nullfier = leaf_private.nullifier();
359		let leaves = vec![Bn254Fr::rand(rng)];
360		let index = 0;
361		let (tree, _) = anchor_setup.setup_tree_and_path(&leaves, index).unwrap();
362		let roots = [tree.root().inner(); M];
363
364		let (mc, .., public_inputs) = anchor_setup
365			.setup_circuit_with_privates(
366				chain_id, secret, nullfier, &leaves, index, roots, recipient, relayer, fee, refund,
367				commitment,
368			)
369			.unwrap();
370
371		let (pk, vk) = setup_keys::<Bn254, _, _>(mc.clone(), rng).unwrap();
372		let proof = prove::<Bn254, _, _>(mc, &pk, rng).unwrap();
373		let res = verify::<Bn254>(&public_inputs, &vk, &proof).unwrap();
374		assert!(!res);
375	}
376
377	#[test]
378	fn should_fail_with_invalid_nullifier_hash() {
379		let rng = &mut test_rng();
380		let curve = Curve::Bn254;
381		let params3 = setup_params_x5_3(curve);
382		let params4 = setup_params_x5_4(curve);
383
384		let chain_id = Bn254Fr::rand(rng);
385		let relayer = Bn254Fr::rand(rng);
386		let recipient = Bn254Fr::rand(rng);
387		let fee = Bn254Fr::rand(rng);
388		let refund = Bn254Fr::rand(rng);
389		let commitment = Bn254Fr::rand(rng);
390
391		let prover = AnchorSetup30_2::new(params3, params4.clone());
392		let arbitrary_input =
393			AnchorSetup30_2::setup_arbitrary_data(recipient, relayer, fee, refund, commitment);
394		let (leaf_private, leaf_public, leaf, _) = prover.setup_leaf(chain_id, rng).unwrap();
395		let nullifier_hash = Bn254Fr::rand(rng);
396		let leaves = vec![leaf];
397		let index = 0;
398		let (tree, path) = prover.setup_tree_and_path(&leaves, index).unwrap();
399
400		let root = tree.root().inner();
401		let roots_new = [root; TEST_M];
402
403		let mc = Circuit_x5::new(
404			arbitrary_input.clone(),
405			leaf_private,
406			leaf_public,
407			roots_new,
408			params4,
409			path,
410			nullifier_hash,
411		);
412		let public_inputs = AnchorSetup30_2::construct_public_inputs(
413			chain_id,
414			nullifier_hash,
415			roots_new,
416			recipient,
417			relayer,
418			fee,
419			refund,
420			commitment,
421		);
422
423		let (pk, vk) = setup_keys::<Bn254, _, _>(mc.clone(), rng).unwrap();
424		let proof = prove::<Bn254, _, _>(mc, &pk, rng).unwrap();
425		let res = verify::<Bn254>(&public_inputs, &vk, &proof).unwrap();
426		assert!(!res);
427	}
428}