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 H: CRH,
22 HG: CRHGadget<H, F>,
23 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 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 let hasher_params_var = HG::ParametersVar::new_constant(cs.clone(), hasher_params)?;
139
140 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 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 let set_gadget = SetGadget::new(roots_var);
155 let is_set_member = set_gadget.check_membership(&root_var)?;
156 arbitrary_input_var.constrain()?;
158
159 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 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 let (random_circuit, ..) = anchor_setup.setup_random_circuit(rng).unwrap();
217 let (pk, vk) = setup_keys::<Bn254, _, _>(random_circuit, rng).unwrap();
218
219 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 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}