wasm_utils/proof/
mixer.rs

1use crate::proof::truncate_and_pad;
2use crate::types::{Backend, Curve, OpStatusCode, OperationError};
3use crate::{MixerR1CSProverBls381_30, MixerR1CSProverBn254_30, DEFAULT_LEAF};
4use arkworks_setups::{Curve as ArkCurve, MixerProver};
5use js_sys::{Array, JsString, Uint8Array};
6use rand::rngs::OsRng;
7use wasm_bindgen::prelude::*;
8
9#[allow(clippy::unused_unit)]
10#[wasm_bindgen]
11#[derive(Debug, Clone)]
12pub struct MixerProof {
13	#[wasm_bindgen(skip)]
14	pub proof: Vec<u8>,
15	#[wasm_bindgen(skip)]
16	pub nullifier_hash: Vec<u8>,
17	#[wasm_bindgen(skip)]
18	pub root: Vec<u8>,
19	#[wasm_bindgen(skip)]
20	pub public_inputs: Vec<Vec<u8>>,
21	#[wasm_bindgen(skip)]
22	pub leaf: Vec<u8>,
23}
24#[wasm_bindgen]
25impl MixerProof {
26	#[wasm_bindgen(getter)]
27	pub fn proof(&self) -> JsString {
28		let proof_bytes = hex::encode(&self.proof);
29		proof_bytes.into()
30	}
31
32	#[wasm_bindgen(js_name = nullifierHash)]
33	#[wasm_bindgen(getter)]
34	pub fn nullifier_hash(&self) -> JsString {
35		let nullifier_bytes = hex::encode(&self.nullifier_hash);
36		nullifier_bytes.into()
37	}
38
39	#[wasm_bindgen(getter)]
40	pub fn root(&self) -> JsString {
41		let root = hex::encode(&self.root);
42		root.into()
43	}
44
45	#[wasm_bindgen(getter)]
46	#[wasm_bindgen(js_name = publicInputs)]
47	pub fn public_inputs_raw(&self) -> Array {
48		let inputs: Array = self
49			.public_inputs
50			.iter()
51			.map(|x| JsString::from(hex::encode(x)))
52			.collect();
53		inputs
54	}
55
56	#[wasm_bindgen(getter)]
57	#[wasm_bindgen(js_name = leaf)]
58	pub fn leaf(&self) -> Uint8Array {
59		let leaf = Uint8Array::from(self.leaf.as_slice());
60		leaf
61	}
62}
63
64#[derive(Debug, Clone)]
65pub struct MixerProofPayload {
66	pub exponentiation: i8,
67	pub width: usize,
68	pub curve: Curve,
69	pub backend: Backend,
70	pub secret: Vec<u8>,
71	pub nullifier: Vec<u8>,
72	pub recipient: Vec<u8>,
73	pub relayer: Vec<u8>,
74	pub pk: Vec<u8>,
75	pub refund: u128,
76	pub fee: u128,
77	pub chain_id: u128,
78	pub leaves: Vec<Vec<u8>>,
79	pub leaf_index: u64,
80}
81
82#[derive(Debug, Clone, Default)]
83pub struct MixerProofInput {
84	pub exponentiation: Option<i8>,
85	pub width: Option<usize>,
86	pub curve: Option<Curve>,
87	pub backend: Option<Backend>,
88	pub secret: Option<Vec<u8>>,
89	pub nullifier: Option<Vec<u8>>,
90	pub recipient: Option<Vec<u8>>,
91	pub relayer: Option<Vec<u8>>,
92	pub pk: Option<Vec<u8>>,
93	pub refund: Option<u128>,
94	pub fee: Option<u128>,
95	pub chain_id: Option<u128>,
96	pub leaves: Option<Vec<Vec<u8>>>,
97	pub leaf_index: Option<u64>,
98}
99
100impl MixerProofInput {
101	pub fn build(self) -> Result<MixerProofPayload, OperationError> {
102		let pk = self.pk.ok_or(OpStatusCode::InvalidProvingKey)?;
103		let recipient = self.recipient.ok_or(OpStatusCode::InvalidRecipient)?;
104		let relayer = self.relayer.ok_or(OpStatusCode::InvalidRelayer)?;
105		let leaf_index = self.leaf_index.ok_or(OpStatusCode::InvalidLeafIndex)?;
106		let secret = self.secret.ok_or(OpStatusCode::InvalidNoteSecrets)?;
107		let nullifier = self.nullifier.ok_or(OpStatusCode::InvalidNoteSecrets)?;
108		let leaves = self.leaves.ok_or(OpStatusCode::InvalidLeaves)?;
109		let fee = self.fee.ok_or(OpStatusCode::InvalidFee)?;
110		let refund = self.refund.ok_or(OpStatusCode::InvalidRefund)?;
111
112		let exponentiation = self.exponentiation.unwrap_or(5);
113		let width = self.width.unwrap_or(3);
114		let curve = self.curve.unwrap_or(Curve::Bn254);
115		let backend = self.backend.unwrap_or(Backend::Arkworks);
116
117		let processed_relayer = truncate_and_pad(&relayer);
118		let processed_recipient = truncate_and_pad(&recipient);
119
120		Ok(MixerProofPayload {
121			exponentiation,
122			width,
123			curve,
124			backend,
125			secret,
126			nullifier,
127			recipient: processed_recipient,
128			relayer: processed_relayer,
129			pk,
130			refund,
131			fee,
132			chain_id: 0,
133			leaves,
134			leaf_index,
135		})
136	}
137}
138
139pub fn create_proof(mixer_proof_input: MixerProofPayload, rng: &mut OsRng) -> Result<MixerProof, OperationError> {
140	let MixerProofPayload {
141		recipient,
142		relayer,
143		leaves,
144		leaf_index,
145		fee,
146		refund,
147		pk,
148		secret,
149		nullifier,
150		backend,
151		curve,
152		exponentiation,
153		width,
154		..
155	} = mixer_proof_input;
156
157	let mixer_proof = match (backend, curve, exponentiation, width) {
158		(Backend::Arkworks, Curve::Bn254, 5, 3) => MixerR1CSProverBn254_30::create_proof(
159			ArkCurve::Bn254,
160			secret,
161			nullifier,
162			leaves,
163			leaf_index,
164			recipient,
165			relayer,
166			fee,
167			refund,
168			pk,
169			DEFAULT_LEAF,
170			rng,
171		),
172		(Backend::Arkworks, Curve::Bls381, 5, 3) => MixerR1CSProverBls381_30::create_proof(
173			ArkCurve::Bls381,
174			secret,
175			nullifier,
176			leaves,
177			leaf_index,
178			recipient,
179			relayer,
180			fee,
181			refund,
182			pk,
183			DEFAULT_LEAF,
184			rng,
185		),
186		_ => return Err(OpStatusCode::UnsupportedParameterCombination.into()),
187	}
188	.map_err(|e| {
189		let mut error: OperationError = OpStatusCode::InvalidProofParameters.into();
190		error.data = Some(e.to_string());
191		error
192	})?;
193
194	Ok(MixerProof {
195		proof: mixer_proof.proof,
196		nullifier_hash: mixer_proof.nullifier_hash_raw,
197		root: mixer_proof.root_raw,
198		public_inputs: mixer_proof.public_inputs_raw,
199		leaf: mixer_proof.leaf_raw,
200	})
201}