1use alloc::{format, string::String, vec::Vec};
7use ark_bn254::Fr;
8use ark_ff::{Field, PrimeField};
9use core::ops::{Add, Mul};
10use wasm_bindgen::prelude::*;
11use zkhash::fields::bn256::FpBN256 as Scalar;
12
13use crate::types::FIELD_SIZE;
14
15pub fn bytes_to_fr(bytes: &[u8]) -> Result<Fr, JsValue> {
17 if bytes.len() != FIELD_SIZE {
18 return Err(JsValue::from_str(&format!(
19 "Expected {} bytes, got {}",
20 FIELD_SIZE,
21 bytes.len()
22 )));
23 }
24 Ok(Fr::from_le_bytes_mod_order(bytes))
25}
26
27pub fn fr_to_bytes(fr: &Fr) -> Vec<u8> {
29 let mut bytes = Vec::with_capacity(FIELD_SIZE);
30 let bigint = fr.into_bigint();
32 for limb in bigint.0.iter() {
33 bytes.extend_from_slice(&limb.to_le_bytes());
34 }
35 bytes.truncate(FIELD_SIZE);
36 bytes
37}
38
39pub fn bytes_to_scalar(bytes: &[u8]) -> Result<Scalar, JsValue> {
41 if bytes.len() != FIELD_SIZE {
42 return Err(JsValue::from_str(&format!(
43 "Expected {} bytes, got {}",
44 FIELD_SIZE,
45 bytes.len()
46 )));
47 }
48 Ok(Scalar::from_le_bytes_mod_order(bytes))
49}
50
51pub fn scalar_to_bytes(scalar: &Scalar) -> Vec<u8> {
53 let mut bytes = Vec::with_capacity(FIELD_SIZE);
54 let bigint = scalar.into_bigint();
55 for limb in bigint.0.iter() {
56 bytes.extend_from_slice(&limb.to_le_bytes());
57 }
58 bytes.truncate(FIELD_SIZE);
59 bytes
60}
61
62pub fn scalar_to_hex(scalar: &Scalar) -> String {
64 let bytes = scalar_to_bytes(scalar);
65 let mut hex = String::from("0x");
67 for byte in bytes.iter().rev() {
68 hex.push_str(&format!("{:02x}", byte));
69 }
70 hex
71}
72
73pub fn hex_to_scalar(hex: &str) -> Result<Scalar, JsValue> {
75 let hex = hex.strip_prefix("0x").unwrap_or(hex);
76
77 if hex.len() > 64 {
78 return Err(JsValue::from_str("Hex string too long"));
79 }
80
81 let padded = format!("{:0>64}", hex);
83
84 let mut bytes = [0u8; FIELD_SIZE];
86 for (i, chunk) in padded.as_bytes().chunks(2).enumerate() {
87 let byte_str =
88 core::str::from_utf8(chunk).map_err(|_| JsValue::from_str("Invalid hex character"))?;
89 let idx = FIELD_SIZE
90 .checked_sub(1)
91 .and_then(|v| v.checked_sub(i))
92 .ok_or_else(|| JsValue::from_str("Index overflow"))?;
93 bytes[idx] = u8::from_str_radix(byte_str, 16)
94 .map_err(|_| JsValue::from_str("Invalid hex character"))?;
95 }
96
97 Ok(Scalar::from_le_bytes_mod_order(&bytes))
98}
99
100#[wasm_bindgen]
104pub fn parse_witness(witness_bytes: &[u8]) -> Result<Vec<u8>, JsValue> {
105 if !witness_bytes.len().is_multiple_of(FIELD_SIZE) {
106 return Err(JsValue::from_str(&format!(
107 "Witness bytes length {} is not a multiple of {}",
108 witness_bytes.len(),
109 FIELD_SIZE
110 )));
111 }
112
113 Ok(witness_bytes.to_vec())
116}
117
118#[wasm_bindgen]
120pub fn witness_element_count(witness_bytes: &[u8]) -> Result<u32, JsValue> {
121 if !witness_bytes.len().is_multiple_of(FIELD_SIZE) {
122 return Err(JsValue::from_str("Invalid witness bytes length"));
123 }
124 let count = witness_bytes.len() / FIELD_SIZE;
125 u32::try_from(count).map_err(|_| JsValue::from_str("Witness count exceeds u32"))
126}
127
128#[wasm_bindgen]
130pub fn u64_to_field_bytes(value: u64) -> Vec<u8> {
131 let scalar = Scalar::from(value);
132 scalar_to_bytes(&scalar)
133}
134
135#[wasm_bindgen]
137pub fn decimal_to_field_bytes(decimal: &str) -> Result<Vec<u8>, JsValue> {
138 let value: u128 = decimal
141 .parse()
142 .map_err(|_| JsValue::from_str("Invalid decimal string"))?;
143
144 let low = (value & 0xFFFFFFFFFFFFFFFF) as u64;
146 let high = (value >> 64) as u64;
147
148 let scalar = Scalar::from(low).add(Scalar::from(high).mul(Scalar::from(1u64 << 32).square()));
149 Ok(scalar_to_bytes(&scalar))
150}
151
152#[wasm_bindgen]
154pub fn field_bytes_to_hex(bytes: &[u8]) -> Result<String, JsValue> {
155 let scalar = bytes_to_scalar(bytes)?;
156 Ok(scalar_to_hex(&scalar))
157}
158
159#[wasm_bindgen]
161pub fn hex_to_field_bytes(hex: &str) -> Result<Vec<u8>, JsValue> {
162 let scalar = hex_to_scalar(hex)?;
163 Ok(scalar_to_bytes(&scalar))
164}