1use crate::serialization::{bytes_to_scalar, scalar_to_bytes, scalar_to_hex};
7use alloc::{string::String, vec, vec::Vec};
8use core::ops::Add;
9use wasm_bindgen::prelude::*;
10use zkhash::{
11 fields::bn256::FpBN256 as Scalar,
12 poseidon2::{
13 poseidon2::Poseidon2,
14 poseidon2_instance_bn256::{
15 POSEIDON2_BN256_PARAMS_2, POSEIDON2_BN256_PARAMS_3, POSEIDON2_BN256_PARAMS_4,
16 },
17 },
18};
19
20pub const BN256_MOD_BYTES: [u8; 32] = [
23 48, 100, 78, 114, 225, 49, 160, 41, 184, 80, 69, 182, 129, 129, 88, 93, 40, 51, 232, 72, 121,
24 185, 112, 145, 67, 225, 245, 147, 240, 0, 0, 1,
25];
26
27pub const ZERO_LEAF_BYTES: [u8; 32] = [
29 37, 48, 34, 136, 219, 153, 53, 3, 68, 151, 65, 131, 206, 49, 13, 99, 181, 58, 187, 158, 240,
30 248, 87, 87, 83, 238, 211, 110, 1, 24, 249, 206,
31];
32
33pub(crate) fn poseidon2_hash2_internal(a: Scalar, b: Scalar, domain: Option<Scalar>) -> Scalar {
38 let poseidon2 = Poseidon2::new(&POSEIDON2_BN256_PARAMS_3);
39 let input = match domain {
40 Some(d) => vec![a, b, d],
41 None => vec![a, b, Scalar::from(0u64)],
42 };
43 let perm = poseidon2.permutation(&input);
44 perm[0]
45}
46
47pub(crate) fn poseidon2_hash3_internal(
51 a: Scalar,
52 b: Scalar,
53 c: Scalar,
54 domain: Option<Scalar>,
55) -> Scalar {
56 let poseidon2 = Poseidon2::new(&POSEIDON2_BN256_PARAMS_4);
57 let input = match domain {
58 Some(d) => vec![a, b, c, d],
59 None => vec![a, b, c, Scalar::from(0u64)],
60 };
61 let perm = poseidon2.permutation(&input);
62 perm[0]
63}
64
65pub(crate) fn poseidon2_compression(left: Scalar, right: Scalar) -> Scalar {
69 let poseidon2 = Poseidon2::new(&POSEIDON2_BN256_PARAMS_2);
70 let input = [left, right];
71 let perm = poseidon2.permutation(&input);
72 perm[0].add(input[0])
74}
75
76#[wasm_bindgen]
79pub fn poseidon2_compression_wasm(input0: &[u8], input1: &[u8]) -> Result<Vec<u8>, JsValue> {
80 let a = bytes_to_scalar(input0)?;
81 let b = bytes_to_scalar(input1)?;
82
83 let result = poseidon2_compression(a, b);
84 Ok(scalar_to_bytes(&result))
85}
86
87#[wasm_bindgen]
91pub fn poseidon2_hash2(
92 input0: &[u8],
93 input1: &[u8],
94 domain_separation: u8,
95) -> Result<Vec<u8>, JsValue> {
96 let a = bytes_to_scalar(input0)?;
97 let b = bytes_to_scalar(input1)?;
98 let domain = Scalar::from(domain_separation);
99
100 let result = poseidon2_hash2_internal(a, b, Some(domain));
101 Ok(scalar_to_bytes(&result))
102}
103
104#[wasm_bindgen]
108pub fn derive_public_key(private_key: &[u8]) -> Result<Vec<u8>, JsValue> {
109 let sk = bytes_to_scalar(private_key)?;
110 let pk = derive_public_key_internal(sk);
111 Ok(scalar_to_bytes(&pk))
112}
113
114#[wasm_bindgen]
116pub fn derive_public_key_hex(private_key: &[u8]) -> Result<String, JsValue> {
117 let sk = bytes_to_scalar(private_key)?;
118 let pk = derive_public_key_internal(sk);
119 Ok(scalar_to_hex(&pk))
120}
121
122#[wasm_bindgen]
126pub fn compute_commitment(
127 amount: &[u8],
128 public_key: &[u8],
129 blinding: &[u8],
130) -> Result<Vec<u8>, JsValue> {
131 let amt = bytes_to_scalar(amount)?;
132 let pk = bytes_to_scalar(public_key)?;
133 let blind = bytes_to_scalar(blinding)?;
134
135 let commitment = poseidon2_hash3_internal(amt, pk, blind, Some(Scalar::from(1u64)));
137 Ok(scalar_to_bytes(&commitment))
138}
139
140#[wasm_bindgen]
142pub fn compute_signature(
143 private_key: &[u8],
144 commitment: &[u8],
145 merkle_path: &[u8],
146) -> Result<Vec<u8>, JsValue> {
147 let sk = bytes_to_scalar(private_key)?;
148 let comm = bytes_to_scalar(commitment)?;
149 let path = bytes_to_scalar(merkle_path)?;
150
151 let sig = poseidon2_hash3_internal(sk, comm, path, Some(Scalar::from(4u64)));
152 Ok(scalar_to_bytes(&sig))
153}
154
155#[wasm_bindgen]
159pub fn compute_nullifier(
160 commitment: &[u8],
161 path_indices: &[u8],
162 signature: &[u8],
163) -> Result<Vec<u8>, JsValue> {
164 let comm = bytes_to_scalar(commitment)?;
165 let indices = bytes_to_scalar(path_indices)?;
166 let sig = bytes_to_scalar(signature)?;
167
168 let nullifier = poseidon2_hash3_internal(comm, indices, sig, Some(Scalar::from(2u64)));
170 Ok(scalar_to_bytes(&nullifier))
171}
172
173#[wasm_bindgen]
175pub fn bn256_modulus() -> Vec<u8> {
176 BN256_MOD_BYTES.to_vec()
177}
178
179#[wasm_bindgen]
181pub fn zero_leaf() -> Vec<u8> {
182 ZERO_LEAF_BYTES.to_vec()
183}
184
185pub(crate) fn derive_public_key_internal(private_key: Scalar) -> Scalar {
188 poseidon2_hash2_internal(private_key, Scalar::from(0u64), Some(Scalar::from(3u64)))
189}