wasm_utils/proof/
mod.rs

1#![allow(clippy::unused_unit)]
2
3use crate::proof::mixer::{MixerProof, MixerProofInput, MixerProofPayload};
4use crate::proof::vanchor::{VAnchorProof, VAnchorProofInput, VAnchorProofPayload};
5use core::convert::TryFrom;
6
7use ark_bls12_381::Bls12_381;
8use ark_bn254::{Bn254, Fr as Bn254Fr};
9use ark_ff::{BigInteger, PrimeField};
10use arkworks_native_gadgets::merkle_tree::SparseMerkleTree;
11use arkworks_native_gadgets::poseidon::Poseidon;
12use arkworks_setups::common::{
13	setup_keys_unchecked, setup_params, setup_tree_and_create_path, verify_unchecked_raw, Leaf,
14};
15use arkworks_setups::Curve as ArkCurve;
16use js_sys::{Array, JsString, Uint8Array};
17use rand::rngs::OsRng;
18use wasm_bindgen::__rt::std::collections::btree_map::BTreeMap;
19// https://github.com/rustwasm/wasm-bindgen/issues/2231#issuecomment-656293288
20use wasm_bindgen::convert::FromWasmAbi;
21use wasm_bindgen::prelude::*;
22
23use crate::note::JsNote;
24use crate::types::{
25	Backend, Curve, Indices, Leaves, NoteProtocol, OpStatusCode, OperationError, Protocol, Uint8Arrayx32, WasmCurve,
26};
27use crate::utxo::JsUtxo;
28use crate::{
29	MixerR1CSProverBn254_30, VAnchorR1CSProverBn254_30_16_16_2, VAnchorR1CSProverBn254_30_16_2_2,
30	VAnchorR1CSProverBn254_30_2_16_2, VAnchorR1CSProverBn254_30_2_2_2, DEFAULT_LEAF, TREE_HEIGHT,
31};
32
33pub mod ext_data;
34pub mod mixer;
35pub mod vanchor;
36
37#[cfg(test)]
38mod test;
39
40#[cfg(test)]
41mod test_utils;
42
43pub fn truncate_and_pad(t: &[u8]) -> Vec<u8> {
44	let mut truncated_bytes = t[..20].to_vec();
45	truncated_bytes.extend_from_slice(&[0u8; 12]);
46	truncated_bytes
47}
48
49#[derive(Debug, Clone)]
50pub enum ProofOutput {
51	Mixer(MixerProof),
52	VAnchor(VAnchorProof),
53}
54
55#[derive(Debug, Clone)]
56#[wasm_bindgen]
57pub struct JsProofOutput {
58	#[wasm_bindgen(skip)]
59	pub inner: ProofOutput,
60}
61
62#[wasm_bindgen]
63impl JsProofOutput {
64	#[wasm_bindgen(getter)]
65	#[wasm_bindgen(js_name  = OutputProtocol)]
66	pub fn output_protocol(&self) -> Protocol {
67		let protocol = match self.inner {
68			ProofOutput::Mixer(_) => "mixer",
69			ProofOutput::VAnchor(_) => "vanchor",
70		};
71
72		JsValue::from(protocol).into()
73	}
74
75	#[wasm_bindgen(getter)]
76	#[wasm_bindgen(js_name = "mixerProof")]
77	pub fn mixer_proof(&self) -> Result<MixerProof, OperationError> {
78		match self.inner.clone() {
79			ProofOutput::Mixer(proof) => Ok(proof),
80			_ => Err(OpStatusCode::InvalidNoteProtocol.into()),
81		}
82	}
83
84	#[wasm_bindgen(getter)]
85	#[wasm_bindgen(js_name = vanchorProof)]
86	pub fn vanchor_proof(&self) -> Result<VAnchorProof, OperationError> {
87		match self.inner.clone() {
88			ProofOutput::VAnchor(proof) => Ok(proof),
89			_ => Err(OpStatusCode::InvalidNoteProtocol.into()),
90		}
91	}
92}
93
94pub fn generic_of_jsval<T: FromWasmAbi<Abi = u32>>(js: JsValue, classname: &str) -> Result<T, JsValue> {
95	use js_sys::{Object, Reflect};
96	let ctor_name = Object::get_prototype_of(&js).constructor().name();
97	if ctor_name == classname {
98		let ptr = Reflect::get(&js, &JsValue::from_str("ptr"))?;
99		let ptr_u32: u32 = ptr.as_f64().ok_or(JsValue::NULL)? as u32;
100		let t = unsafe { T::from_abi(ptr_u32) };
101		Ok(t)
102	} else {
103		Err(JsValue::NULL)
104	}
105}
106
107#[wasm_bindgen]
108pub fn js_note_of_jsval(js: JsValue) -> Option<JsNote> {
109	generic_of_jsval(js, "JsNote").unwrap_or(None)
110}
111
112#[wasm_bindgen]
113pub struct LeavesMapInput {
114	#[wasm_bindgen(skip)]
115	pub leaves: BTreeMap<u64, Vec<Vec<u8>>>,
116}
117
118impl Default for LeavesMapInput {
119	fn default() -> Self {
120		Self::new()
121	}
122}
123#[wasm_bindgen]
124impl LeavesMapInput {
125	#[wasm_bindgen(constructor)]
126	pub fn new() -> LeavesMapInput {
127		Self {
128			leaves: Default::default(),
129		}
130	}
131
132	#[wasm_bindgen(js_name=setChainLeaves)]
133	pub fn set_chain_leaves(&mut self, chain_id: u64, leaves: Leaves) -> Result<(), JsValue> {
134		let leaves: Vec<_> = Array::from(&leaves)
135			.to_vec()
136			.into_iter()
137			.map(|v| Uint8Array::new_with_byte_offset_and_length(&v, 0, 32))
138			.map(Uint8Arrayx32::try_from)
139			.collect::<Result<Vec<_>, _>>()
140			.map_err(|_| OpStatusCode::InvalidLeaves)?
141			.into_iter()
142			.map(|v| v.0.to_vec())
143			.collect();
144
145		self.leaves.insert(chain_id, leaves);
146
147		Ok(())
148	}
149}
150
151#[derive(Debug, Clone)]
152pub enum ProofInput {
153	Mixer(Box<MixerProofPayload>),
154	VAnchor(Box<VAnchorProofPayload>),
155}
156
157impl ProofInput {
158	pub fn mixer_input(&self) -> Result<MixerProofPayload, OperationError> {
159		match self {
160			ProofInput::Mixer(mixer_input) => Ok(*mixer_input.clone()),
161			_ => {
162				let message = "Can't construct proof input for AnchorProofInput".to_string();
163				Err(OperationError::new_with_message(
164					OpStatusCode::InvalidNoteProtocol,
165					message,
166				))
167			}
168		}
169	}
170
171	pub fn vanchor_input(&self) -> Result<VAnchorProofPayload, OperationError> {
172		match self {
173			ProofInput::VAnchor(vanchor) => Ok(*vanchor.clone()),
174			_ => {
175				let message = "Can't cant construct proof input for VAnchorProofInput".to_string();
176				Err(OperationError::new_with_message(
177					OpStatusCode::InvalidNoteProtocol,
178					message,
179				))
180			}
181		}
182	}
183}
184
185#[allow(unused_macros)]
186macro_rules! console_log {
187	// Note that this is using the `log` function imported above during
188	// `bare_bones`
189	($($t:tt)*) => (crate::types::log(&format_args!($($t)*).to_string()))
190}
191
192#[wasm_bindgen]
193#[derive(Debug, Clone)]
194pub struct JsProofInput {
195	#[wasm_bindgen(skip)]
196	pub inner: ProofInput,
197}
198#[derive(Debug, Clone)]
199pub enum ProofInputBuilder {
200	Mixer(Box<MixerProofInput>),
201	VAnchor(Box<VAnchorProofInput>),
202}
203impl ProofInputBuilder {
204	pub fn set_input_utxos(&mut self, utxo_list: Vec<JsUtxo>) -> Result<(), OperationError> {
205		match self {
206			Self::VAnchor(input) => {
207				input.secret = Some(utxo_list);
208				Ok(())
209			}
210			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
211		}
212	}
213
214	/// Directly set the output Utxos in the proving payload
215	pub fn set_output_utxos(&mut self, output_utxos: [JsUtxo; 2]) -> Result<(), OperationError> {
216		match self {
217			Self::VAnchor(input) => {
218				input.output_utxos = Some(output_utxos);
219				Ok(())
220			}
221			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
222		}
223	}
224
225	pub fn roots(&mut self, roots: Vec<Vec<u8>>) -> Result<(), OperationError> {
226		match self {
227			ProofInputBuilder::VAnchor(value) => {
228				value.roots = Some(roots);
229				Ok(())
230			}
231			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
232		}
233	}
234
235	pub fn public_amount(&mut self, public_amount: i128) -> Result<(), OperationError> {
236		match self {
237			ProofInputBuilder::VAnchor(input) => {
238				input.public_amount = Some(public_amount);
239				Ok(())
240			}
241			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
242		}
243	}
244
245	pub fn secrets(&mut self, leaf: Leaf) -> Result<(), OperationError> {
246		match self {
247			ProofInputBuilder::Mixer(input) => {
248				input.secret = Some(leaf.secret_bytes);
249				input.nullifier = Some(leaf.nullifier_bytes);
250				Ok(())
251			}
252			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
253		}
254	}
255
256	pub fn leaves_map(&mut self, leaves: BTreeMap<u64, Vec<Vec<u8>>>) -> Result<(), OperationError> {
257		match self {
258			Self::VAnchor(input) => {
259				input.leaves = Some(leaves);
260				Ok(())
261			}
262			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
263		}
264	}
265
266	pub fn ext_data_hash(&mut self, ext_data_hash_bytes: Vec<u8>) -> Result<(), OperationError> {
267		match self {
268			Self::VAnchor(input) => {
269				input.ext_data_hash = Some(ext_data_hash_bytes);
270				Ok(())
271			}
272			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
273		}
274	}
275
276	pub fn leaf_indices(&mut self, leaf_indices: Vec<u64>) -> Result<(), OperationError> {
277		match self {
278			Self::VAnchor(input) => {
279				input.indices = Some(leaf_indices);
280				Ok(())
281			}
282			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
283		}
284	}
285
286	pub fn recipient(&mut self, recipient: Vec<u8>) -> Result<(), OperationError> {
287		match self {
288			Self::Mixer(input) => {
289				input.recipient = Some(recipient);
290				Ok(())
291			}
292			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
293		}
294	}
295
296	pub fn relayer(&mut self, relayer: Vec<u8>) -> Result<(), OperationError> {
297		match self {
298			Self::Mixer(input) => {
299				input.relayer = Some(relayer);
300				Ok(())
301			}
302			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
303		}
304	}
305
306	pub fn leaves_list(&mut self, leaves: Vec<Vec<u8>>) -> Result<(), OperationError> {
307		match self {
308			Self::Mixer(input) => {
309				input.leaves = Some(leaves);
310				Ok(())
311			}
312			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
313		}
314	}
315
316	pub fn leaf_index(&mut self, leaf_index: u64) -> Result<(), OperationError> {
317		match self {
318			Self::Mixer(input) => {
319				input.leaf_index = Some(leaf_index);
320				Ok(())
321			}
322			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
323		}
324	}
325
326	pub fn fee(&mut self, fee: u128) -> Result<(), OperationError> {
327		match self {
328			Self::Mixer(input) => {
329				input.fee = Some(fee);
330				Ok(())
331			}
332			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
333		}
334	}
335
336	pub fn refund(&mut self, refund: u128) -> Result<(), OperationError> {
337		match self {
338			Self::Mixer(input) => {
339				input.refund = Some(refund);
340				Ok(())
341			}
342			_ => Err(OpStatusCode::ProofInputFieldInstantiationProtocolInvalid.into()),
343		}
344	}
345
346	pub fn pk(&mut self, pk: Vec<u8>) -> Result<(), OperationError> {
347		match self {
348			ProofInputBuilder::Mixer(input) => {
349				input.pk = Some(pk);
350			}
351			ProofInputBuilder::VAnchor(input) => {
352				input.pk = Some(pk);
353			}
354		}
355		Ok(())
356	}
357
358	pub fn exponentiation(&mut self, exponentiation: i8) -> Result<(), OperationError> {
359		match self {
360			ProofInputBuilder::Mixer(input) => {
361				input.exponentiation = Some(exponentiation);
362			}
363			ProofInputBuilder::VAnchor(input) => {
364				input.exponentiation = Some(exponentiation);
365			}
366		}
367		Ok(())
368	}
369
370	pub fn width(&mut self, width: usize) -> Result<(), OperationError> {
371		match self {
372			ProofInputBuilder::Mixer(input) => {
373				input.width = Some(width);
374			}
375			ProofInputBuilder::VAnchor(input) => {
376				input.width = Some(width);
377			}
378		}
379		Ok(())
380	}
381
382	pub fn curve(&mut self, curve: Curve) -> Result<(), OperationError> {
383		match self {
384			ProofInputBuilder::Mixer(input) => {
385				input.curve = Some(curve);
386			}
387			ProofInputBuilder::VAnchor(input) => {
388				input.curve = Some(curve);
389			}
390		}
391		Ok(())
392	}
393
394	pub fn backend(&mut self, backend: Backend) -> Result<(), OperationError> {
395		match self {
396			ProofInputBuilder::Mixer(input) => {
397				input.backend = Some(backend);
398			}
399			ProofInputBuilder::VAnchor(input) => {
400				input.backend = Some(backend);
401			}
402		}
403		Ok(())
404	}
405
406	pub fn chain_id(&mut self, chain_id: u128) -> Result<(), OperationError> {
407		match self {
408			ProofInputBuilder::Mixer(input) => {
409				input.chain_id = Some(chain_id);
410			}
411			ProofInputBuilder::VAnchor(input) => {
412				input.chain_id = Some(chain_id);
413			}
414		}
415		Ok(())
416	}
417	/* Shared fields  [VAnchor,Anchor,Mixer] */
418}
419#[wasm_bindgen]
420#[derive(Debug)]
421pub struct JsProofInputBuilder {
422	#[wasm_bindgen(skip)]
423	pub inner: ProofInputBuilder,
424}
425#[wasm_bindgen]
426impl JsProofInputBuilder {
427	#[wasm_bindgen(constructor)]
428	pub fn new(protocol: Protocol) -> Result<JsProofInputBuilder, OperationError> {
429		let protocol: String = JsValue::from(&protocol)
430			.as_string()
431			.ok_or(OpStatusCode::InvalidNoteProtocol)?;
432		let note_protocol: NoteProtocol = protocol
433			.as_str()
434			.parse()
435			.map_err(|_| OpStatusCode::InvalidNoteProtocol)?;
436		let proof_input_builder = match note_protocol {
437			NoteProtocol::Mixer => ProofInputBuilder::Mixer(Default::default()),
438			NoteProtocol::VAnchor => ProofInputBuilder::VAnchor(Default::default()),
439		};
440
441		Ok(JsProofInputBuilder {
442			inner: proof_input_builder,
443		})
444	}
445
446	#[wasm_bindgen(js_name = setRoots)]
447	pub fn set_roots(&mut self, roots: Leaves) -> Result<(), JsValue> {
448		let rs: Vec<Vec<u8>> = Array::from(&roots)
449			.to_vec()
450			.into_iter()
451			.map(|v| Uint8Array::new_with_byte_offset_and_length(&v, 0, 32))
452			.map(Uint8Arrayx32::try_from)
453			.collect::<Result<Vec<_>, _>>()
454			.map_err(|_| OpStatusCode::InvalidLeaves)?
455			.into_iter()
456			.map(|v| v.0.to_vec())
457			.collect();
458		self.inner.roots(rs)?;
459		Ok(())
460	}
461
462	#[wasm_bindgen(js_name = setRecipient)]
463	pub fn set_recipient(&mut self, recipient: JsString) -> Result<(), JsValue> {
464		let r: String = recipient.into();
465		let recipient = hex::decode(r).map_err(|_| OpStatusCode::InvalidRecipient)?;
466		self.inner.recipient(recipient)?;
467		Ok(())
468	}
469
470	#[wasm_bindgen(js_name = setRelayer)]
471	pub fn set_relayer(&mut self, relayer: JsString) -> Result<(), JsValue> {
472		let r: String = relayer.into();
473		let relayer = hex::decode(r).map_err(|_| OpStatusCode::DeserializationFailed)?;
474		self.inner.relayer(relayer)?;
475		Ok(())
476	}
477
478	#[wasm_bindgen(js_name = setLeaves)]
479	pub fn set_leaves(&mut self, leaves: Leaves) -> Result<(), JsValue> {
480		let ls: Vec<_> = Array::from(&leaves)
481			.to_vec()
482			.into_iter()
483			.map(|v| Uint8Array::new_with_byte_offset_and_length(&v, 0, 32))
484			.map(Uint8Arrayx32::try_from)
485			.collect::<Result<Vec<_>, _>>()
486			.map_err(|_| OpStatusCode::InvalidLeaves)?
487			.into_iter()
488			.map(|v| v.0.to_vec())
489			.collect();
490		self.inner.leaves_list(ls)?;
491		Ok(())
492	}
493
494	#[wasm_bindgen(js_name = setOutputUtxos)]
495	pub fn set_output_utxos(&mut self, utxo1: JsUtxo, utxo2: JsUtxo) -> Result<(), JsValue> {
496		self.inner.set_output_utxos([utxo1, utxo2])?;
497		Ok(())
498	}
499
500	#[wasm_bindgen(js_name = setLeavesMap)]
501	pub fn set_leaves_map(&mut self, leaves_input: LeavesMapInput) -> Result<(), JsValue> {
502		self.inner.leaves_map(leaves_input.leaves)?;
503		Ok(())
504	}
505
506	#[wasm_bindgen(js_name = setIndices)]
507	pub fn set_indices(&mut self, indices: Indices) -> Result<(), JsValue> {
508		let indices: Vec<_> = Array::from(&indices)
509			.to_vec()
510			.into_iter()
511			.map(|v| {
512				let s: String = JsString::from(v).into();
513				s.parse::<u64>()
514			})
515			.collect::<Result<Vec<u64>, _>>()
516			.map_err(|_| OpStatusCode::InvalidIndices)?
517			.into_iter()
518			.collect();
519		self.inner.leaf_indices(indices)?;
520		Ok(())
521	}
522
523	#[wasm_bindgen(js_name = setLeafIndex)]
524	pub fn set_leaf_index(&mut self, leaf_index: JsString) -> Result<(), JsValue> {
525		let leaf_index: String = leaf_index.into();
526		let leaf_index = leaf_index
527			.as_str()
528			.parse()
529			.map_err(|_| OpStatusCode::InvalidLeafIndex)?;
530		self.inner.leaf_index(leaf_index)?;
531		Ok(())
532	}
533
534	#[wasm_bindgen(js_name = setFee)]
535	pub fn set_fee(&mut self, fee: JsString) -> Result<(), JsValue> {
536		let fee: String = fee.into();
537		let fee = fee.as_str().parse().map_err(|_| OpStatusCode::InvalidFee)?;
538		self.inner.fee(fee)?;
539		Ok(())
540	}
541
542	#[wasm_bindgen(js_name = setRefund)]
543	pub fn set_refund(&mut self, refund: JsString) -> Result<(), JsValue> {
544		let refund: String = refund.into();
545		let refund = refund.as_str().parse().map_err(|_| OpStatusCode::InvalidRefund)?;
546		self.inner.refund(refund)?;
547		Ok(())
548	}
549
550	#[wasm_bindgen(js_name = setPk)]
551	pub fn set_pk(&mut self, pk: JsString) -> Result<(), JsValue> {
552		let p: String = pk.into();
553		let proving_key = hex::decode(p).map_err(|_| OpStatusCode::InvalidProvingKey)?;
554		self.inner.pk(proving_key)?;
555		Ok(())
556	}
557
558	#[wasm_bindgen]
559	pub fn public_amount(&mut self, public_amount: JsString) -> Result<(), JsValue> {
560		let pa: String = public_amount.into();
561		let pa: i128 = pa.parse().map_err(|_| OpStatusCode::InvalidPublicAmount)?;
562		self.inner.public_amount(pa)?;
563		Ok(())
564	}
565
566	#[wasm_bindgen]
567	pub fn chain_id(&mut self, chain_id: JsString) -> Result<(), JsValue> {
568		let chain_id: String = chain_id.into();
569		let chain_id = chain_id.parse().map_err(|_| OpStatusCode::InvalidChainId)?;
570		self.inner.chain_id(chain_id)?;
571		Ok(())
572	}
573
574	fn set_meta_data(&mut self, note: &JsNote) -> Result<(), OperationError> {
575		let exponentiation = note.exponentiation.unwrap_or(5);
576		let backend = note.backend.unwrap_or(Backend::Circom);
577		let curve = note.curve.unwrap_or(Curve::Bn254);
578		let width = note.width.unwrap_or(3);
579
580		let chain_id = note
581			.target_chain_id
582			.parse()
583			.map_err(|_| OpStatusCode::InvalidTargetChain)?;
584
585		self.inner.exponentiation(exponentiation)?;
586		self.inner.backend(backend)?;
587		self.inner.width(width)?;
588		self.inner.curve(curve)?;
589		self.inner.chain_id(chain_id)?;
590		Ok(())
591	}
592
593	#[wasm_bindgen(js_name = setNote)]
594	pub fn set_metadata_from_note(&mut self, note: &JsNote) -> Result<(), JsValue> {
595		// For the Mixer/Anchor secrets live in the the note
596		// For the VAnchor there is a call `set_notes` that will set UTXOs in the
597		// `ProofInput::VAnchor(VAnchorProofInput)`
598		match self.inner {
599			ProofInputBuilder::Mixer(_) => self.set_meta_data(note)?,
600			_ => return Err(OpStatusCode::InvalidNoteProtocol.into()),
601		}
602
603		#[allow(clippy::single_match)]
604		match self.inner {
605			ProofInputBuilder::Mixer(_) => {
606				let leaf = note.get_leaf_and_nullifier()?;
607				let mixer_leaf = leaf.mixer_leaf()?;
608				self.inner.secrets(mixer_leaf)?
609			}
610			_ => {}
611		}
612		Ok(())
613	}
614
615	#[wasm_bindgen]
616	pub fn build_js(self) -> Result<JsProofInput, JsValue> {
617		let proof_input = self.build()?;
618		Ok(JsProofInput { inner: proof_input })
619	}
620
621	/// Set notes for VAnchor
622	#[wasm_bindgen(js_name=setNotes)]
623	pub fn set_notes(&mut self, notes: Array) -> Result<(), JsValue> {
624		let notes: Vec<JsNote> = notes
625			.iter()
626			.map(|v| js_note_of_jsval(v).ok_or(OpStatusCode::InvalidNoteSecrets))
627			.collect::<Result<Vec<JsNote>, _>>()?;
628		self.set_meta_data(&notes[0])?;
629		let utxos = notes.iter().map(|n| n.get_js_utxo()).collect::<Result<Vec<_>, _>>()?;
630
631		self.inner.set_input_utxos(utxos)?;
632		Ok(())
633	}
634
635	#[wasm_bindgen(js_name=setExtDatahash)]
636	pub fn set_ext_data_hash(&mut self, ex_data_hash: JsString) -> Result<(), JsValue> {
637		let ex_data_hash: String = ex_data_hash.into();
638		let bytes = hex::decode(&ex_data_hash).map_err(|_| OpStatusCode::InvalidExtDataHash)?;
639
640		self.inner.ext_data_hash(bytes)?;
641		Ok(())
642	}
643}
644impl JsProofInputBuilder {
645	pub fn build(self) -> Result<ProofInput, OperationError> {
646		let proof_input = match self.inner {
647			ProofInputBuilder::Mixer(mixer_proof_input) => {
648				let mixer_payload = mixer_proof_input.build()?;
649				ProofInput::Mixer(Box::new(mixer_payload))
650			}
651			ProofInputBuilder::VAnchor(vanchor_proof_input) => {
652				let vanchor_payload = vanchor_proof_input.build()?;
653				ProofInput::VAnchor(Box::new(vanchor_payload))
654			}
655		};
656		Ok(proof_input)
657	}
658}
659
660#[wasm_bindgen]
661pub struct MTBn254X5 {
662	#[wasm_bindgen(skip)]
663	pub inner: SparseMerkleTree<Bn254Fr, Poseidon<Bn254Fr>, TREE_HEIGHT>,
664}
665
666#[allow(clippy::unused_unit)]
667#[wasm_bindgen]
668impl MTBn254X5 {
669	#[wasm_bindgen(constructor)]
670	pub fn new(initial_leaves: Leaves, leaf_index: JsString) -> Result<MTBn254X5, JsValue> {
671		let leaf_index: String = leaf_index.into();
672		let leaf_index: u64 = leaf_index.parse().expect("Failed to parse the leaf index");
673		let leaves: Vec<_> = Array::from(&initial_leaves)
674			.to_vec()
675			.into_iter()
676			.map(|v| Uint8Array::new_with_byte_offset_and_length(&v, 0, 32))
677			.map(Uint8Arrayx32::try_from)
678			.collect::<Result<Vec<_>, _>>()
679			.map_err(|_| OpStatusCode::InvalidLeaves)?
680			.into_iter()
681			.map(|v| Bn254Fr::from_le_bytes_mod_order(v.0.as_ref()))
682			.collect();
683
684		let curve = ArkCurve::Bn254;
685		let params3 = setup_params::<Bn254Fr>(curve, 5, 3);
686		let poseidon3 = Poseidon::new(params3);
687
688		let (tree, _) = setup_tree_and_create_path::<Bn254Fr, Poseidon<Bn254Fr>, TREE_HEIGHT>(
689			&poseidon3,
690			&leaves,
691			leaf_index,
692			&DEFAULT_LEAF,
693		)
694		.unwrap();
695		Ok(Self { inner: tree })
696	}
697
698	#[wasm_bindgen(getter)]
699	pub fn root(&self) -> JsString {
700		let root = self.inner.root().into_repr().to_bytes_le().to_vec();
701		JsString::from(hex::encode(root))
702	}
703
704	#[wasm_bindgen]
705	pub fn insert(&mut self, leaves: Leaves) -> Result<(), JsValue> {
706		let mut leaves_bt = BTreeMap::<_, Bn254Fr>::new();
707		Array::from(&leaves)
708			.to_vec()
709			.into_iter()
710			.map(|v| Uint8Array::new_with_byte_offset_and_length(&v, 0, 32))
711			.map(Uint8Arrayx32::try_from)
712			.collect::<Result<Vec<_>, _>>()
713			.map_err(|_| OpStatusCode::InvalidLeaves)?
714			.iter()
715			.for_each(|leaf| {
716				leaves_bt
717					.insert(
718						leaves_bt.len() as u32 + 1_u32,
719						Bn254Fr::from_le_bytes_mod_order(leaf.0.as_ref()),
720					)
721					.unwrap();
722			});
723
724		let params3 = setup_params::<Bn254Fr>(ArkCurve::Bn254, 5, 3);
725		let poseidon3 = Poseidon::new(params3);
726		self.inner
727			.insert_batch(&leaves_bt, &poseidon3)
728			.map_err(|_| OpStatusCode::InvalidLeaves)?;
729		Ok(())
730	}
731}
732// For testing on js side
733#[wasm_bindgen]
734pub fn verify_js_proof(proof: JsString, public_inputs: Array, vk: JsString, curve: WasmCurve) -> bool {
735	let proof = hex::decode(JsValue::from(proof).as_string().unwrap()).unwrap();
736	let pub_ins: Vec<Vec<u8>> = public_inputs
737		.to_vec()
738		.into_iter()
739		.map(|v| JsValue::from(JsString::from(v)).as_string().unwrap())
740		.map(|x| hex::decode(&x).unwrap())
741		.collect();
742
743	let curve: Curve = JsValue::from(curve).as_string().unwrap().parse().unwrap();
744	let vk = hex::decode(JsValue::from(vk).as_string().unwrap()).unwrap();
745	match curve {
746		Curve::Bls381 => verify_unchecked_raw::<Bls12_381>(&pub_ins, &vk, &proof).unwrap(),
747		Curve::Bn254 => verify_unchecked_raw::<Bn254>(&pub_ins, &vk, &proof).unwrap(),
748	}
749}
750
751#[wasm_bindgen]
752pub struct JsProvingKeys {
753	#[wasm_bindgen(skip)]
754	pub pk: Vec<u8>,
755	#[wasm_bindgen(skip)]
756	pub vk: Vec<u8>,
757}
758#[wasm_bindgen]
759impl JsProvingKeys {
760	#[wasm_bindgen(getter)]
761	pub fn pk(&self) -> Uint8Array {
762		Uint8Array::from(self.pk.as_slice())
763	}
764
765	#[wasm_bindgen(getter)]
766	pub fn vk(&self) -> Uint8Array {
767		Uint8Array::from(self.pk.as_slice())
768	}
769}
770#[wasm_bindgen(js_name = setupKeys)]
771pub fn setup_keys(
772	protocol: Protocol,
773	curve: Option<WasmCurve>,
774	anchor_count: Option<u32>,
775	in_count: Option<u32>,
776	out_count: Option<u32>,
777) -> Result<JsProvingKeys, JsValue> {
778	let curve: Curve = match curve {
779		Some(curve) => JsValue::from(curve).as_string().unwrap().parse().unwrap(),
780		None => Curve::Bn254,
781	};
782	let anchor_count = anchor_count.unwrap_or(2);
783	let in_count = in_count.unwrap_or(2);
784	let out_count = out_count.unwrap_or(2);
785	let note_protocol: NoteProtocol = JsValue::from(protocol).as_string().unwrap().parse().unwrap();
786	let (pk, vk) = match (note_protocol, curve, anchor_count, in_count, out_count) {
787		(NoteProtocol::Mixer, ..) => {
788			let (c, ..) = MixerR1CSProverBn254_30::setup_random_circuit(ArkCurve::Bn254, DEFAULT_LEAF, &mut OsRng)
789				.expect("Failed to create a circuit");
790			let (pk, vk) = setup_keys_unchecked::<Bn254, _, _>(c, &mut OsRng).expect("failed to generate keys");
791			(pk, vk)
792		}
793		(NoteProtocol::VAnchor, Curve::Bn254, 2, 2, 2) => {
794			let c = VAnchorR1CSProverBn254_30_2_2_2::setup_random_circuit(ArkCurve::Bn254, DEFAULT_LEAF, &mut OsRng)
795				.expect("Failed to create a circuit");
796			let (pk, vk) = setup_keys_unchecked::<Bn254, _, _>(c, &mut OsRng).expect("failed to generate keys");
797			(pk, vk)
798		}
799		(NoteProtocol::VAnchor, Curve::Bn254, 2, 16, 2) => {
800			let c = VAnchorR1CSProverBn254_30_2_16_2::setup_random_circuit(ArkCurve::Bn254, DEFAULT_LEAF, &mut OsRng)
801				.expect("Failed to create a circuit");
802			let (pk, vk) = setup_keys_unchecked::<Bn254, _, _>(c, &mut OsRng).expect("failed to generate keys");
803			(pk, vk)
804		}
805		(NoteProtocol::VAnchor, Curve::Bn254, 16, 2, 2) => {
806			let c = VAnchorR1CSProverBn254_30_16_2_2::setup_random_circuit(ArkCurve::Bn254, DEFAULT_LEAF, &mut OsRng)
807				.expect("Failed to create a circuit");
808			let (pk, vk) = setup_keys_unchecked::<Bn254, _, _>(c, &mut OsRng).expect("failed to generate keys");
809			(pk, vk)
810		}
811		(NoteProtocol::VAnchor, Curve::Bn254, 16, 16, 2) => {
812			let c = VAnchorR1CSProverBn254_30_16_16_2::setup_random_circuit(ArkCurve::Bn254, DEFAULT_LEAF, &mut OsRng)
813				.expect("Failed to create a circuit");
814			let (pk, vk) = setup_keys_unchecked::<Bn254, _, _>(c, &mut OsRng).expect("failed to generate keys");
815			(pk, vk)
816		}
817		_ => return Err(JsValue::from(JsString::from("Unsupported input"))),
818	};
819	Ok(JsProvingKeys { pk, vk })
820}
821#[wasm_bindgen]
822pub fn generate_proof_js(proof_input: JsProofInput) -> Result<JsProofOutput, JsValue> {
823	let mut rng = OsRng;
824	let proof_input_value = proof_input.inner;
825	match proof_input_value {
826		ProofInput::Mixer(mixer_proof_input) => {
827			mixer::create_proof(*mixer_proof_input, &mut rng).map(|v| JsProofOutput {
828				inner: ProofOutput::Mixer(v),
829			})
830		}
831		ProofInput::VAnchor(vanchor_proof_input) => {
832			vanchor::create_proof(*vanchor_proof_input, &mut rng).map(|v| JsProofOutput {
833				inner: ProofOutput::VAnchor(v),
834			})
835		}
836	}
837	.map_err(|e| e.into())
838}