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}