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;
19use 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 ($($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 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 }
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 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 #[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(¬es[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#[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}