1use crate::{
2 circuit::vanchor::VAnchorCircuit as VACircuit,
3 setup::common::{
4 LeafCRHGadget, PoseidonCRH_x5_2, PoseidonCRH_x5_2Gadget, PoseidonCRH_x5_3Gadget,
5 PoseidonCRH_x5_4, TreeConfig_x5, Tree_x5,
6 },
7};
8use ark_bn254::Fr as Bn254Fr;
9use ark_crypto_primitives::Error;
10use ark_ff::PrimeField;
11use ark_std::{error::Error as ArkError, rand::RngCore, rc::Rc, string::ToString, vec::Vec};
12use arkworks_gadgets::{
13 arbitrary::vanchor_data::VAnchorArbitraryData,
14 keypair::vanchor::Keypair,
15 leaf::vanchor::{Private as LeafPrivateInput, Public as LeafPublicInput, VAnchorLeaf as Leaf},
16 merkle_tree::Path,
17};
18use arkworks_utils::{
19 poseidon::PoseidonParameters,
20 utils::common::{
21 setup_params_x5_2, setup_params_x5_3, setup_params_x5_4, setup_params_x5_5, Curve,
22 },
23};
24
25pub fn get_hash_params<F: PrimeField>(
26 curve: Curve,
27) -> (
28 PoseidonParameters<F>,
29 PoseidonParameters<F>,
30 PoseidonParameters<F>,
31 PoseidonParameters<F>,
32) {
33 (
34 setup_params_x5_2::<F>(curve),
35 setup_params_x5_3::<F>(curve),
36 setup_params_x5_4::<F>(curve),
37 setup_params_x5_5::<F>(curve),
38 )
39}
40
41#[derive(Debug)]
42pub enum UtxoError {
43 NullifierNotCalculated,
44}
45
46impl core::fmt::Display for UtxoError {
47 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48 let msg = match self {
49 UtxoError::NullifierNotCalculated => "Nullifier not calculated".to_string(),
50 };
51 write!(f, "{}", msg)
52 }
53}
54
55impl ArkError for UtxoError {}
56
57#[derive(Clone, Copy)]
58pub struct Utxo<F: PrimeField> {
59 pub chain_id: F,
60 pub amount: F,
61 pub keypair: Keypair<F, PoseidonCRH_x5_2<F>>,
62 pub leaf_private: LeafPrivateInput<F>,
63 pub leaf_public: LeafPublicInput<F>,
64 pub index: Option<F>,
65 pub nullifier: Option<F>,
66 pub commitment: F,
67}
68
69impl<F: PrimeField> Utxo<F> {
70 pub fn new<R: RngCore>(
71 chain_id: F,
72 amount: F,
73 index: Option<F>,
74 private_key: Option<F>,
75 blinding: Option<F>,
76 params2: &PoseidonParameters<F>,
77 params4: &PoseidonParameters<F>,
78 params5: &PoseidonParameters<F>,
79 rng: &mut R,
80 ) -> Result<Self, Error> {
81 let blinding = blinding.unwrap_or(F::rand(rng));
82 let private_input = LeafPrivateInput::<F>::new(amount, blinding);
83 let public_input = LeafPublicInput::<F>::new(chain_id);
84
85 let keypair = Keypair::new(private_key.unwrap_or(F::rand(rng)));
86 let pub_key = keypair.public_key(params2)?;
87
88 let leaf = Leaf::<F, PoseidonCRH_x5_4<F>>::create_leaf(
89 &private_input,
90 &public_input,
91 &pub_key,
92 ¶ms5,
93 )?;
94
95 let nullifier = if index.is_some() {
96 let i = index.unwrap();
97
98 let signature = keypair.signature(&leaf, &i, params4)?;
99
100 let nullifier =
101 Leaf::<_, PoseidonCRH_x5_4<F>>::create_nullifier(&signature, &leaf, ¶ms4, &i)?;
102
103 Some(nullifier)
104 } else {
105 None
106 };
107
108 Ok(Self {
109 chain_id,
110 amount,
111 keypair,
112 leaf_private: private_input,
113 leaf_public: public_input,
114 index,
115 nullifier,
116 commitment: leaf,
117 })
118 }
119
120 pub fn get_nullifier(&self) -> Result<F, Error> {
121 self.nullifier
122 .ok_or(UtxoError::NullifierNotCalculated.into())
123 }
124}
125
126#[derive(Clone)]
127pub struct VAnchorProverSetup<
128 F: PrimeField,
129 const TREE_DEPTH: usize,
130 const M: usize,
131 const INS: usize,
132 const OUTS: usize,
133> {
134 params2: PoseidonParameters<F>,
135 params3: PoseidonParameters<F>,
136 params4: PoseidonParameters<F>,
137 params5: PoseidonParameters<F>,
138}
139
140impl<
141 F: PrimeField,
142 const TREE_DEPTH: usize,
143 const M: usize,
144 const INS: usize,
145 const OUTS: usize,
146 > VAnchorProverSetup<F, TREE_DEPTH, M, INS, OUTS>
147{
148 pub fn new(
149 params2: PoseidonParameters<F>,
150 params3: PoseidonParameters<F>,
151 params4: PoseidonParameters<F>,
152 params5: PoseidonParameters<F>,
153 ) -> Self {
154 Self {
155 params2,
156 params3,
157 params4,
158 params5,
159 }
160 }
161
162 pub fn new_utxo<R: RngCore>(
163 &self,
164 chain_id: F,
165 amount: F,
166 index: Option<F>,
167 secret_key: Option<F>,
168 blinding: Option<F>,
169 rng: &mut R,
170 ) -> Result<Utxo<F>, Error> {
171 Utxo::new(
172 chain_id,
173 amount,
174 index,
175 secret_key,
176 blinding,
177 &self.params2,
178 &self.params4,
179 &self.params5,
180 rng,
181 )
182 }
183
184 pub fn setup_random_circuit<R: RngCore>(
185 self,
186 rng: &mut R,
187 ) -> Result<
188 VACircuit<
189 F,
190 PoseidonCRH_x5_2<F>,
191 PoseidonCRH_x5_2Gadget<F>,
192 TreeConfig_x5<F>,
193 LeafCRHGadget<F>,
194 PoseidonCRH_x5_3Gadget<F>,
195 TREE_DEPTH,
196 INS,
197 OUTS,
198 M,
199 >,
200 Error,
201 > {
202 let public_amount = F::rand(rng);
203 let ext_data_hash = F::rand(rng);
204 let in_root_set = [F::rand(rng); M];
205 let in_leaves = [F::rand(rng); INS].map(|x| vec![x]);
206 let in_indices = [0; INS];
207
208 let chain_id = F::rand(rng);
209 let amount = F::rand(rng);
210 let index = F::rand(rng);
211 let secret_key = F::rand(rng);
212 let blinding = F::rand(rng);
213
214 let in_utxo = self.new_utxo(
215 chain_id,
216 amount,
217 Some(index),
218 Some(secret_key),
219 Some(blinding),
220 rng,
221 )?;
222 let in_utxos = [in_utxo; INS];
223 let out_utxo = self.new_utxo(
224 chain_id,
225 amount,
226 None,
227 Some(secret_key),
228 Some(blinding),
229 rng,
230 )?;
231 let out_utxos = [out_utxo; OUTS];
232
233 let (circuit, ..) = self.setup_circuit_with_utxos(
234 public_amount,
235 ext_data_hash,
236 in_root_set,
237 in_indices,
238 in_leaves,
239 in_utxos,
240 out_utxos,
241 )?;
242
243 Ok(circuit)
244 }
245
246 pub fn setup_circuit_with_utxos(
247 self,
248 public_amount: F,
250 ext_data_hash: F,
251 in_root_set: [F; M],
252 in_indices: [u64; INS],
253 in_leaves: [Vec<F>; INS],
254 in_utxos: [Utxo<F>; INS],
256 out_utxos: [Utxo<F>; OUTS],
258 ) -> Result<
259 (
260 VACircuit<
261 F,
262 PoseidonCRH_x5_2<F>,
263 PoseidonCRH_x5_2Gadget<F>,
264 TreeConfig_x5<F>,
265 LeafCRHGadget<F>,
266 PoseidonCRH_x5_3Gadget<F>,
267 TREE_DEPTH,
268 INS,
269 OUTS,
270 M,
271 >,
272 Vec<F>,
273 ),
274 Error,
275 > {
276 let in_indices_f = in_indices.map(|x| F::from(x));
278 let mut in_paths = Vec::new();
279 for i in 0..INS {
280 let (in_path, _) = self.setup_tree(&in_leaves[i], in_indices[i])?;
281 in_paths.push(in_path)
282 }
283 let arbitrary_data = Self::setup_arbitrary_data(ext_data_hash);
285
286 let circuit = self.setup_circuit(
287 public_amount,
288 arbitrary_data,
289 in_utxos.clone(),
290 in_indices_f,
291 in_paths,
292 in_root_set,
293 out_utxos.clone(),
294 )?;
295
296 let in_nullifiers: Result<Vec<F>, Error> =
297 in_utxos.iter().map(|x| x.get_nullifier()).collect();
298 let out_nullifiers = out_utxos.iter().map(|x| x.commitment).collect::<Vec<F>>();
299 let public_inputs = Self::construct_public_inputs(
300 in_utxos[0].leaf_public.chain_id,
301 public_amount,
302 in_root_set.to_vec(),
303 in_nullifiers?,
304 out_nullifiers,
305 ext_data_hash,
306 );
307
308 Ok((circuit, public_inputs))
309 }
310
311 pub fn setup_circuit(
312 self,
313 public_amount: F,
314 arbitrary_data: VAnchorArbitraryData<F>,
315 in_utxos: [Utxo<F>; INS],
317 in_indicies: [F; INS],
319 in_paths: Vec<Path<TreeConfig_x5<F>, TREE_DEPTH>>,
320 in_root_set: [F; M],
321 out_utxos: [Utxo<F>; OUTS],
323 ) -> Result<
324 VACircuit<
325 F,
326 PoseidonCRH_x5_2<F>,
327 PoseidonCRH_x5_2Gadget<F>,
328 TreeConfig_x5<F>,
329 LeafCRHGadget<F>,
330 PoseidonCRH_x5_3Gadget<F>,
331 TREE_DEPTH,
332 INS,
333 OUTS,
334 M,
335 >,
336 Error,
337 > {
338 let in_leaf_private_inputs = in_utxos
339 .iter()
340 .map(|x| x.leaf_private.clone())
341 .collect::<Vec<LeafPrivateInput<F>>>();
342 let in_keypair_inputs = in_utxos
343 .iter()
344 .map(|x| x.keypair.clone())
345 .collect::<Vec<Keypair<F, PoseidonCRH_x5_2<F>>>>();
346 let in_nullifiers: Result<Vec<F>, Error> =
347 in_utxos.iter().map(|x| x.get_nullifier()).collect();
348
349 let out_pub_keys: Result<Vec<F>, _> = out_utxos
350 .iter()
351 .map(|x| x.keypair.public_key(&self.params2))
352 .collect();
353 let out_commitments = out_utxos.iter().map(|x| x.commitment).collect::<Vec<F>>();
354 let out_leaf_private = out_utxos
355 .iter()
356 .map(|x| x.leaf_private.clone())
357 .collect::<Vec<LeafPrivateInput<F>>>();
358 let out_leaf_public = out_utxos
359 .iter()
360 .map(|x| x.leaf_public.clone())
361 .collect::<Vec<LeafPublicInput<F>>>();
362 let circuit = VACircuit::<
363 F,
364 PoseidonCRH_x5_2<F>,
365 PoseidonCRH_x5_2Gadget<F>,
366 TreeConfig_x5<F>,
367 LeafCRHGadget<F>,
368 PoseidonCRH_x5_3Gadget<F>,
369 TREE_DEPTH,
370 INS,
371 OUTS,
372 M,
373 >::new(
374 public_amount,
375 arbitrary_data,
376 in_leaf_private_inputs,
377 in_keypair_inputs,
378 in_utxos[0].leaf_public.clone(),
379 in_root_set,
380 self.params2,
381 self.params4,
382 self.params5,
383 in_paths,
384 in_indicies.to_vec(),
385 in_nullifiers?,
386 out_commitments,
387 out_leaf_private,
388 out_leaf_public,
389 out_pub_keys?,
390 );
391
392 Ok(circuit)
393 }
394
395 pub fn setup_keypairs<R: RngCore, const N: usize>(
396 rng: &mut R,
397 ) -> [Keypair<F, PoseidonCRH_x5_2<F>>; N] {
398 [(); N].map(|_| Keypair::<_, PoseidonCRH_x5_2<F>>::new(F::rand(rng)))
399 }
400
401 pub fn setup_tree(
402 &self,
403 leaves: &[F],
404 index: u64,
405 ) -> Result<(Path<TreeConfig_x5<F>, TREE_DEPTH>, F), Error> {
406 let inner_params = Rc::new(self.params3.clone());
407 let tree = Tree_x5::new_sequential(inner_params, Rc::new(()), &leaves.to_vec())?;
408 let root = tree.root();
409 let path = tree.generate_membership_proof::<TREE_DEPTH>(index);
410
411 Ok((path, root.inner()))
412 }
413
414 pub fn construct_public_inputs(
415 chain_id: F,
416 public_amount: F,
417 roots: Vec<F>,
418 nullifiers: Vec<F>,
419 commitments: Vec<F>,
420 ext_data_hash: F,
421 ) -> Vec<F> {
422 let mut public_inputs = vec![public_amount, ext_data_hash];
423 public_inputs.extend(nullifiers);
424 public_inputs.extend(commitments);
425 public_inputs.push(chain_id);
426 public_inputs.extend(roots);
427
428 public_inputs
429 }
430
431 pub fn deconstruct_public_inputs(
433 public_inputs: Vec<F>,
434 ) -> Result<
435 (
436 F, F, Vec<F>, Vec<F>, Vec<F>, F, ),
443 Error,
444 > {
445 let mut pub_ins = public_inputs;
446
447 let mut root_set = Vec::new();
448 for _ in 0..INS {
449 root_set.push(pub_ins.pop().unwrap());
450 }
451
452 let chain_id = pub_ins.pop().unwrap();
453
454 let mut out_commitments = Vec::new();
455 for _ in 0..OUTS {
456 out_commitments.push(pub_ins.pop().unwrap());
457 }
458
459 let mut in_nullifiers = Vec::new();
460 for _ in 0..INS {
461 in_nullifiers.push(pub_ins.pop().unwrap());
462 }
463
464 let ext_data_hash = pub_ins.pop().unwrap();
465 let public_amount = pub_ins.pop().unwrap();
466
467 Ok((
468 chain_id,
469 public_amount,
470 root_set,
471 in_nullifiers,
472 out_commitments,
473 ext_data_hash,
474 ))
475 }
476
477 pub fn setup_arbitrary_data(ext_data: F) -> VAnchorArbitraryData<F> {
478 VAnchorArbitraryData::new(ext_data)
479 }
480}
481
482pub type VAnchorProverBn2542x2 = VAnchorProverSetup<Bn254Fr, 30, 2, 2, 2>;
487
488pub fn setup_vanchor_arbitrary_data<F: PrimeField>(ext_data: F) -> VAnchorArbitraryData<F> {
491 VAnchorArbitraryData::new(ext_data)
492}