arkworks_circuits/setup/
anchor.rs

1use super::common::*;
2use crate::circuit::anchor::AnchorCircuit;
3use ark_crypto_primitives::Error;
4use ark_ec::PairingEngine;
5use ark_ff::{BigInteger, PrimeField};
6use ark_std::{
7	rand::{CryptoRng, Rng, RngCore},
8	rc::Rc,
9	vec::Vec,
10};
11use arkworks_gadgets::{
12	arbitrary::anchor_data::Input as AnchorDataInput,
13	leaf::anchor::{
14		constraints::AnchorLeafGadget, AnchorLeaf, Private as LeafPrivate, Public as LeafPublic,
15	},
16	merkle_tree::Path,
17};
18use arkworks_utils::{
19	poseidon::PoseidonParameters,
20	utils::common::{setup_params_x5_3, setup_params_x5_4, Curve},
21};
22
23pub type AnchorConstraintDataInput<F> = AnchorDataInput<F>;
24
25pub type Leaf_x5<F> = AnchorLeaf<F, PoseidonCRH_x5_4<F>>;
26
27pub type LeafGadget_x5<F> = AnchorLeafGadget<F, PoseidonCRH_x5_4<F>, PoseidonCRH_x5_4Gadget<F>>;
28
29pub type Circuit_x5<F, const N: usize, const M: usize> = AnchorCircuit<
30	F,
31	PoseidonCRH_x5_4<F>,
32	PoseidonCRH_x5_4Gadget<F>,
33	TreeConfig_x5<F>,
34	LeafCRHGadget<F>,
35	PoseidonCRH_x5_3Gadget<F>,
36	N,
37	M,
38>;
39
40pub type Leaf_x17<F> = AnchorLeaf<F, PoseidonCRH_x17_5<F>>;
41pub type LeafGadget_x17<F> = AnchorLeafGadget<F, PoseidonCRH_x17_5<F>, PoseidonCRH_x17_5Gadget<F>>;
42
43pub type Circuit_x17<F, const N: usize, const M: usize> = AnchorCircuit<
44	F,
45	PoseidonCRH_x17_5<F>,
46	PoseidonCRH_x17_5Gadget<F>,
47	TreeConfig_x17<F>,
48	LeafCRHGadget<F>,
49	PoseidonCRH_x17_3Gadget<F>,
50	N,
51	M,
52>;
53
54pub fn setup_leaf_x5_4<F: PrimeField, R: RngCore>(
55	curve: Curve,
56	chain_id: u128,
57	rng: &mut R,
58) -> Result<Leaf, Error> {
59	let params5 = setup_params_x5_4::<F>(curve);
60	// Secret inputs for the leaf
61	let leaf_private = LeafPrivate::generate(rng);
62
63	let chain_id_f = F::from(chain_id);
64	let leaf_public = LeafPublic::new(chain_id_f);
65
66	let leaf_hash = Leaf_x5::create_leaf(&leaf_private, &leaf_public, &params5)?;
67	let nullifier_hash = Leaf_x5::create_nullifier(&leaf_private, &params5)?;
68
69	let secret_bytes = leaf_private.secret().into_repr().to_bytes_le();
70	let nullifier_bytes = leaf_private.nullifier().into_repr().to_bytes_le();
71
72	let leaf_bytes = leaf_hash.into_repr().to_bytes_le();
73	let nullifier_hash_bytes = nullifier_hash.into_repr().to_bytes_le();
74
75	Ok(Leaf {
76		secret_bytes,
77		nullifier_bytes,
78		leaf_bytes,
79		nullifier_hash_bytes,
80	})
81}
82
83pub fn setup_leaf_with_privates_raw_x5_4<F: PrimeField>(
84	curve: Curve,
85	secret_bytes: Vec<u8>,
86	nullifier_bytes: Vec<u8>,
87	chain_id: u128,
88) -> Result<Leaf, Error> {
89	let params5 = setup_params_x5_4::<F>(curve);
90
91	let secret = F::from_le_bytes_mod_order(&secret_bytes);
92	let nullifier = F::from_le_bytes_mod_order(&nullifier_bytes);
93	// Secret inputs for the leaf
94	let leaf_private = LeafPrivate::new(secret, nullifier);
95
96	let chain_id_f = F::from(chain_id);
97	let leaf_public = LeafPublic::new(chain_id_f);
98
99	let leaf_hash = Leaf_x5::create_leaf(&leaf_private, &leaf_public, &params5)?;
100	let nullifier_hash = Leaf_x5::create_nullifier(&leaf_private, &params5)?;
101
102	let leaf_bytes = leaf_hash.into_repr().to_bytes_le();
103	let nullifier_hash_bytes = nullifier_hash.into_repr().to_bytes_le();
104
105	Ok(Leaf {
106		secret_bytes,
107		nullifier_bytes,
108		leaf_bytes,
109		nullifier_hash_bytes,
110	})
111}
112
113pub const N: usize = 30;
114pub const M: usize = 2;
115pub type AnchorProverSetupBn254_30<F> = AnchorProverSetup<F, M, N>;
116
117pub fn setup_proof_x5_4<E: PairingEngine, R: RngCore + CryptoRng>(
118	curve: Curve,
119	chain_id: u128,
120	secret_raw: Vec<u8>,
121	nullifier_raw: Vec<u8>,
122	leaves_raw: Vec<Vec<u8>>,
123	index: u64,
124	roots: [Vec<u8>; M],
125	recipient_raw: Vec<u8>,
126	relayer_raw: Vec<u8>,
127	commitment_raw: Vec<u8>,
128	fee: u128,
129	refund: u128,
130	pk: Vec<u8>,
131	rng: &mut R,
132) -> Result<AnchorProof, Error> {
133	let params3 = setup_params_x5_3::<E::Fr>(curve);
134	let params4 = setup_params_x5_4::<E::Fr>(curve);
135	let prover = AnchorProverSetupBn254_30::new(params3, params4);
136
137	let (circuit, leaf_raw, nullifier_hash_raw, roots_raw, public_inputs_raw) = prover
138		.setup_circuit_with_privates_raw(
139			chain_id,
140			secret_raw,
141			nullifier_raw,
142			leaves_raw,
143			index,
144			roots,
145			recipient_raw,
146			relayer_raw,
147			commitment_raw,
148			fee,
149			refund,
150		)?;
151
152	let proof = prove_unchecked::<E, _, _>(circuit, &pk, rng)?;
153
154	Ok(AnchorProof {
155		proof,
156		leaf_raw,
157		nullifier_hash_raw,
158		roots_raw,
159		public_inputs_raw,
160	})
161}
162
163pub fn setup_keys_x5_4<E: PairingEngine, R: RngCore + CryptoRng>(
164	curve: Curve,
165	rng: &mut R,
166) -> Result<Keys, Error> {
167	let params3 = setup_params_x5_3::<E::Fr>(curve);
168	let params5 = setup_params_x5_4::<E::Fr>(curve);
169	let prover = AnchorProverSetupBn254_30::new(params3, params5);
170
171	let (circuit, ..) = prover.setup_random_circuit(rng)?;
172
173	let (pk, vk) = setup_keys_unchecked::<E, _, _>(circuit, rng)?;
174
175	Ok(Keys { pk, vk })
176}
177
178#[derive(Clone)]
179pub struct AnchorProverSetup<F: PrimeField, const M: usize, const N: usize> {
180	params3: PoseidonParameters<F>,
181	params4: PoseidonParameters<F>,
182}
183
184impl<F: PrimeField, const M: usize, const N: usize> AnchorProverSetup<F, M, N> {
185	pub fn new(params3: PoseidonParameters<F>, params4: PoseidonParameters<F>) -> Self {
186		Self { params3, params4 }
187	}
188
189	pub fn setup_arbitrary_data(
190		recipient: F,
191		relayer: F,
192		fee: F,
193		refund: F,
194		commitment: F,
195	) -> AnchorConstraintDataInput<F> {
196		AnchorConstraintDataInput::new(recipient, relayer, fee, refund, commitment)
197	}
198
199	#[allow(clippy::too_many_arguments)]
200	pub fn construct_public_inputs(
201		chain_id: F,
202		nullifier_hash: F,
203		roots: [F; M],
204		recipient: F,
205		relayer: F,
206		fee: F,
207		refund: F,
208		commitment: F,
209	) -> Vec<F> {
210		let mut pub_ins = vec![chain_id, nullifier_hash];
211		pub_ins.extend(roots.to_vec());
212		pub_ins.extend(vec![recipient, relayer, fee, refund, commitment]);
213
214		pub_ins
215	}
216
217	#[allow(clippy::too_many_arguments)]
218	pub fn deconstruct_public_inputs(
219		public_inputs: &[F],
220	) -> (
221		F,      // Chain id
222		F,      // Nullifier Hash
223		Vec<F>, // Roots
224		F,      // Recipient
225		F,      // Relayer
226		F,      // Fee
227		F,      // Refund
228		F,      // Commitment
229	) {
230		let chain_id: F = public_inputs[0];
231		let nullifier_hash = public_inputs[1];
232		let offset = 2 + M;
233		let roots = public_inputs[2..offset].to_vec();
234		let recipient = public_inputs[offset + 1];
235		let relayer = public_inputs[offset + 2];
236		let fee = public_inputs[offset + 3];
237		let refund = public_inputs[offset + 4];
238		let commitments = public_inputs[offset + 5];
239		(
240			chain_id,
241			nullifier_hash,
242			roots,
243			recipient,
244			relayer,
245			fee,
246			refund,
247			commitments,
248		)
249	}
250
251	pub fn setup_leaf<R: Rng>(
252		&self,
253		chain_id: F,
254		rng: &mut R,
255	) -> Result<(LeafPrivate<F>, LeafPublic<F>, F, F), Error> {
256		// Secret inputs for the leaf
257		let leaf_private = LeafPrivate::generate(rng);
258		// Public inputs for the leaf
259		let leaf_public = LeafPublic::new(chain_id);
260
261		// Creating the leaf
262		let leaf_hash = AnchorLeaf::<F, PoseidonCRH_x5_4<F>>::create_leaf(
263			&leaf_private,
264			&leaf_public,
265			&self.params4,
266		)?;
267		let nullifier_hash =
268			AnchorLeaf::<F, PoseidonCRH_x5_4<F>>::create_nullifier(&leaf_private, &self.params4)?;
269
270		Ok((leaf_private, leaf_public, leaf_hash, nullifier_hash))
271	}
272
273	pub fn setup_leaf_with_privates(
274		&self,
275		chain_id: F,
276		secret: F,
277		nullfier: F,
278	) -> Result<(LeafPrivate<F>, LeafPublic<F>, F, F), Error> {
279		// Secret inputs for the leaf
280		let leaf_private = LeafPrivate::new(secret, nullfier);
281		let leaf_public = LeafPublic::new(chain_id);
282
283		// Creating the leaf
284		let leaf_hash = Leaf_x5::create_leaf(&leaf_private, &leaf_public, &self.params4)?;
285		let nullifier_hash = Leaf_x5::create_nullifier(&leaf_private, &self.params4)?;
286
287		Ok((leaf_private, leaf_public, leaf_hash, nullifier_hash))
288	}
289
290	#[allow(clippy::too_many_arguments)]
291	pub fn setup_circuit<R: Rng>(
292		self,
293		chain_id: F,
294		leaves: &[F],
295		index: u64,
296		roots: [F; M], // only first M - 1 member will be used
297		recipient: F,
298		relayer: F,
299		fee: F,
300		refund: F,
301		commitment: F,
302		rng: &mut R,
303	) -> Result<(Circuit_x5<F, N, M>, F, F, Vec<F>, Vec<F>), Error> {
304		let arbitrary_input =
305			Self::setup_arbitrary_data(recipient, relayer, fee, refund, commitment);
306		let (leaf_private, leaf_public, leaf, nullifier_hash) = self.setup_leaf(chain_id, rng)?;
307		let (_, path) = self.setup_tree_and_path(&leaves, index)?;
308
309		let mc = Circuit_x5::new(
310			arbitrary_input.clone(),
311			leaf_private,
312			leaf_public,
313			roots,
314			self.params4,
315			path,
316			nullifier_hash,
317		);
318
319		let public_inputs = Self::construct_public_inputs(
320			chain_id,
321			nullifier_hash,
322			roots,
323			recipient,
324			relayer,
325			fee,
326			refund,
327			commitment,
328		);
329
330		Ok((mc, leaf, nullifier_hash, roots.to_vec(), public_inputs))
331	}
332
333	#[allow(clippy::too_many_arguments)]
334	pub fn setup_circuit_with_privates(
335		self,
336		chain_id: F,
337		secret: F,
338		nullifier: F,
339		leaves: &[F],
340		index: u64,
341		roots: [F; M],
342		recipient: F,
343		relayer: F,
344		fee: F,
345		refund: F,
346		commitment: F,
347	) -> Result<(Circuit_x5<F, N, M>, F, F, Vec<F>, Vec<F>), Error> {
348		let arbitrary_input =
349			Self::setup_arbitrary_data(recipient, relayer, fee, refund, commitment);
350		let (leaf_private, leaf_public, leaf, nullifier_hash) =
351			self.setup_leaf_with_privates(chain_id, secret, nullifier)?;
352		let (_, path) = self.setup_tree_and_path(&leaves, index)?;
353
354		let mc = Circuit_x5::new(
355			arbitrary_input.clone(),
356			leaf_private,
357			leaf_public,
358			roots,
359			self.params4,
360			path,
361			nullifier_hash,
362		);
363
364		let public_inputs = Self::construct_public_inputs(
365			chain_id,
366			nullifier_hash,
367			roots,
368			recipient,
369			relayer,
370			fee,
371			refund,
372			commitment,
373		);
374
375		Ok((mc, leaf, nullifier_hash, roots.to_vec(), public_inputs))
376	}
377
378	pub fn setup_random_circuit<R: Rng>(
379		self,
380		rng: &mut R,
381	) -> Result<(Circuit_x5<F, N, M>, F, F, Vec<F>, Vec<F>), Error> {
382		let chain_id = F::rand(rng);
383
384		let roots = [F::rand(rng); M];
385		let recipient = F::rand(rng);
386		let relayer = F::rand(rng);
387		let fee = F::rand(rng);
388		let refund = F::rand(rng);
389		let commitment = F::rand(rng);
390
391		let (leaf_privates, _leaf_public, leaf_hash, ..) = self.setup_leaf(chain_id, rng).unwrap();
392		let secret = leaf_privates.secret();
393		let nullifier = leaf_privates.nullifier();
394		let leaves = vec![leaf_hash];
395		let index = 0;
396
397		self.setup_circuit_with_privates(
398			chain_id, secret, nullifier, &leaves, index, roots, recipient, relayer, fee, refund,
399			commitment,
400		)
401	}
402
403	pub fn setup_circuit_with_privates_raw(
404		self,
405		chain_id: u128,
406		secret: Vec<u8>,
407		nullifier: Vec<u8>,
408		leaves: Vec<Vec<u8>>,
409		index: u64,
410		roots: [Vec<u8>; M],
411		recipient: Vec<u8>,
412		relayer: Vec<u8>,
413		commitment: Vec<u8>,
414		fee: u128,
415		refund: u128,
416	) -> Result<
417		(
418			Circuit_x5<F, N, M>,
419			Vec<u8>,
420			Vec<u8>,
421			Vec<Vec<u8>>,
422			Vec<Vec<u8>>,
423		),
424		Error,
425	> {
426		let chain_id_f = F::from(chain_id);
427		let secret_f = F::from_le_bytes_mod_order(&secret);
428		let nullifier_f = F::from_le_bytes_mod_order(&nullifier);
429		let leaves_f: Vec<F> = leaves
430			.iter()
431			.map(|x| F::from_le_bytes_mod_order(x))
432			.collect();
433		let mut roots_f: [F; M] = [F::default(); M];
434		for i in 0..M {
435			roots_f[i] = F::from_le_bytes_mod_order(&roots[i]);
436		}
437		let recipient_f = F::from_le_bytes_mod_order(&recipient);
438		let relayer_f = F::from_le_bytes_mod_order(&relayer);
439		let commitment_f = F::from_le_bytes_mod_order(&commitment);
440		let fee_f = F::from(fee);
441		let refund_f = F::from(refund);
442
443		let (mc, leaf, nullifier_hash, roots, public_inputs) = self.setup_circuit_with_privates(
444			chain_id_f,
445			secret_f,
446			nullifier_f,
447			&leaves_f,
448			index,
449			roots_f,
450			recipient_f,
451			relayer_f,
452			fee_f,
453			refund_f,
454			commitment_f,
455		)?;
456
457		let leaf_raw = leaf.into_repr().to_bytes_le();
458		let nullifier_hash_raw = nullifier_hash.into_repr().to_bytes_le();
459		let roots_raw = roots.iter().map(|x| x.into_repr().to_bytes_le()).collect();
460		let public_inputs_raw: Vec<Vec<u8>> = public_inputs
461			.iter()
462			.map(|x| x.into_repr().to_bytes_le())
463			.collect();
464
465		Ok((
466			mc,
467			leaf_raw,
468			nullifier_hash_raw,
469			roots_raw,
470			public_inputs_raw,
471		))
472	}
473
474	pub fn setup_tree(&self, leaves: &[F]) -> Result<Tree_x5<F>, Error> {
475		let inner_params = Rc::new(self.params3.clone());
476		let mt = Tree_x5::new_sequential(inner_params, Rc::new(()), leaves)?;
477		Ok(mt)
478	}
479
480	pub fn setup_tree_and_path(
481		&self,
482		leaves: &[F],
483		index: u64,
484	) -> Result<(Tree_x5<F>, Path<TreeConfig_x5<F>, N>), Error> {
485		// Making the merkle tree
486		let mt = self.setup_tree(leaves)?;
487		// Getting the proof path
488		let path = mt.generate_membership_proof(index);
489
490		Ok((mt, path))
491	}
492}