plonk_wasm/arkworks/
pasta_fp.rs

1use crate::arkworks::bigint_256::{self, WasmBigInteger256};
2use ark_ff::{
3    fields::{Field, PrimeField},
4    FftField, One, UniformRand, Zero,
5};
6use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as Domain};
7use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
8use core::cmp::Ordering::{Equal, Greater, Less};
9use mina_curves::pasta::{
10    fields::{fft::FpParameters, fp::FpParameters as Fp_params},
11    Fp,
12};
13use num_bigint::BigUint;
14use rand::rngs::StdRng;
15use wasm_bindgen::{
16    convert::{FromWasmAbi, IntoWasmAbi, OptionFromWasmAbi, OptionIntoWasmAbi},
17    prelude::*,
18};
19
20#[repr(C)]
21#[derive(Clone, Copy, Debug)]
22pub struct WasmPastaFp(pub Fp);
23
24impl crate::wasm_flat_vector::FlatVectorElem for WasmPastaFp {
25    const FLATTENED_SIZE: usize = core::mem::size_of::<Fp>();
26    fn flatten(self) -> Vec<u8> {
27        let mut bytes: Vec<u8> = Vec::with_capacity(Self::FLATTENED_SIZE);
28        self.0.serialize_compressed(&mut bytes).unwrap();
29        bytes
30    }
31    fn unflatten(flat: Vec<u8>) -> Self {
32        WasmPastaFp(Fp::deserialize_compressed(flat.as_slice()).unwrap())
33    }
34}
35
36impl From<Fp> for WasmPastaFp {
37    fn from(x: Fp) -> Self {
38        WasmPastaFp(x)
39    }
40}
41
42impl From<WasmPastaFp> for Fp {
43    fn from(x: WasmPastaFp) -> Self {
44        x.0
45    }
46}
47
48impl<'a> From<&'a WasmPastaFp> for &'a Fp {
49    fn from(x: &'a WasmPastaFp) -> Self {
50        &x.0
51    }
52}
53
54impl wasm_bindgen::describe::WasmDescribe for WasmPastaFp {
55    fn describe() {
56        <Vec<u8> as wasm_bindgen::describe::WasmDescribe>::describe()
57    }
58}
59
60impl FromWasmAbi for WasmPastaFp {
61    type Abi = <Vec<u8> as FromWasmAbi>::Abi;
62    unsafe fn from_abi(js: Self::Abi) -> Self {
63        let bytes: Vec<u8> = FromWasmAbi::from_abi(js);
64        WasmPastaFp(Fp::deserialize_compressed(bytes.as_slice()).unwrap())
65    }
66}
67
68impl IntoWasmAbi for WasmPastaFp {
69    type Abi = <Vec<u8> as FromWasmAbi>::Abi;
70    fn into_abi(self) -> Self::Abi {
71        let mut bytes: Vec<u8> = vec![];
72        self.0.serialize_compressed(&mut bytes).unwrap();
73        bytes.into_abi()
74    }
75}
76
77impl OptionIntoWasmAbi for WasmPastaFp {
78    fn none() -> Self::Abi {
79        <Vec<u8> as OptionIntoWasmAbi>::none()
80    }
81}
82
83impl OptionFromWasmAbi for WasmPastaFp {
84    fn is_none(abi: &Self::Abi) -> bool {
85        <Vec<u8> as OptionFromWasmAbi>::is_none(abi)
86    }
87}
88
89#[wasm_bindgen]
90pub fn caml_pasta_fp_size_in_bits() -> isize {
91    Fp_params::MODULUS_BITS as isize
92}
93
94#[wasm_bindgen]
95pub fn caml_pasta_fp_size() -> WasmBigInteger256 {
96    WasmBigInteger256(Fp_params::MODULUS)
97}
98
99#[wasm_bindgen]
100pub fn caml_pasta_fp_add(x: WasmPastaFp, y: WasmPastaFp) -> WasmPastaFp {
101    WasmPastaFp(x.0 + y.0)
102}
103
104#[wasm_bindgen]
105pub fn caml_pasta_fp_sub(x: WasmPastaFp, y: WasmPastaFp) -> WasmPastaFp {
106    WasmPastaFp(x.0 - y.0)
107}
108
109#[wasm_bindgen]
110pub fn caml_pasta_fp_negate(x: WasmPastaFp) -> WasmPastaFp {
111    WasmPastaFp(-x.0)
112}
113
114#[wasm_bindgen]
115pub fn caml_pasta_fp_mul(x: WasmPastaFp, y: WasmPastaFp) -> WasmPastaFp {
116    WasmPastaFp(x.0 * y.0)
117}
118
119#[wasm_bindgen]
120pub fn caml_pasta_fp_div(x: WasmPastaFp, y: WasmPastaFp) -> WasmPastaFp {
121    WasmPastaFp(x.0 / y.0)
122}
123
124#[wasm_bindgen]
125pub fn caml_pasta_fp_inv(x: WasmPastaFp) -> Option<WasmPastaFp> {
126    x.0.inverse().map(WasmPastaFp)
127}
128
129#[wasm_bindgen]
130pub fn caml_pasta_fp_square(x: WasmPastaFp) -> WasmPastaFp {
131    WasmPastaFp(x.0.square())
132}
133
134#[wasm_bindgen]
135pub fn caml_pasta_fp_is_square(x: WasmPastaFp) -> bool {
136    let s = x.0.pow(Fp_params::MODULUS_MINUS_ONE_DIV_TWO);
137    s.is_zero() || s.is_one()
138}
139
140#[wasm_bindgen]
141pub fn caml_pasta_fp_sqrt(x: WasmPastaFp) -> Option<WasmPastaFp> {
142    x.0.sqrt().map(WasmPastaFp)
143}
144
145#[wasm_bindgen]
146pub fn caml_pasta_fp_of_int(i: i32) -> WasmPastaFp {
147    WasmPastaFp(Fp::from(i as u64))
148}
149
150#[wasm_bindgen]
151pub fn caml_pasta_fp_to_string(x: WasmPastaFp) -> String {
152    bigint_256::to_biguint(&x.0.into_bigint()).to_string()
153}
154
155#[wasm_bindgen]
156pub fn caml_pasta_fp_of_string(s: String) -> Result<WasmPastaFp, JsValue> {
157    let biguint = BigUint::parse_bytes(s.as_bytes(), 10)
158        .ok_or(JsValue::from_str("caml_pasta_fp_of_string"))?;
159
160    match Fp::from_bigint(bigint_256::of_biguint(&biguint)) {
161        Some(x) => Ok(x.into()),
162        None => Err(JsValue::from_str("caml_pasta_fp_of_string")),
163    }
164}
165
166#[wasm_bindgen]
167pub fn caml_pasta_fp_print(x: WasmPastaFp) {
168    println!("{}", bigint_256::to_biguint(&(x.0.into_bigint())));
169}
170
171#[wasm_bindgen]
172pub fn caml_pasta_fp_compare(x: WasmPastaFp, y: WasmPastaFp) -> i32 {
173    match x.0.cmp(&y.0) {
174        Less => -1,
175        Equal => 0,
176        Greater => 1,
177    }
178}
179
180#[wasm_bindgen]
181pub fn caml_pasta_fp_equal(x: WasmPastaFp, y: WasmPastaFp) -> bool {
182    x.0 == y.0
183}
184
185#[wasm_bindgen]
186pub fn caml_pasta_fp_random() -> WasmPastaFp {
187    WasmPastaFp(UniformRand::rand(&mut rand::thread_rng()))
188}
189
190#[wasm_bindgen]
191pub fn caml_pasta_fp_rng(i: i32) -> WasmPastaFp {
192    // We only care about entropy here, so we force a conversion i32 -> u32.
193    let i: u64 = (i as u32).into();
194    let mut rng: StdRng = rand::SeedableRng::seed_from_u64(i);
195    WasmPastaFp(UniformRand::rand(&mut rng))
196}
197
198#[wasm_bindgen]
199pub fn caml_pasta_fp_to_bigint(x: WasmPastaFp) -> WasmBigInteger256 {
200    WasmBigInteger256(x.0.into_bigint())
201}
202
203#[wasm_bindgen]
204pub fn caml_pasta_fp_of_bigint(x: WasmBigInteger256) -> Result<WasmPastaFp, JsValue> {
205    match Fp::from_bigint(x.0) {
206        Some(x) => Ok(x.into()),
207        None => Err(JsValue::from_str("caml_pasta_fp_of_bigint")),
208    }
209}
210
211#[wasm_bindgen]
212pub fn caml_pasta_fp_two_adic_root_of_unity() -> WasmPastaFp {
213    WasmPastaFp(<Fp as FftField>::TWO_ADIC_ROOT_OF_UNITY)
214}
215
216#[wasm_bindgen]
217pub fn caml_pasta_fp_domain_generator(log2_size: i32) -> WasmPastaFp {
218    match Domain::new(1 << log2_size) {
219        Some(x) => WasmPastaFp(x.group_gen),
220        None => panic!("caml_pasta_fp_domain_generator"),
221    }
222}
223
224#[wasm_bindgen]
225pub fn caml_pasta_fp_to_bytes(x: WasmPastaFp) -> Vec<u8> {
226    let len = core::mem::size_of::<Fp>();
227    let mut str: Vec<u8> = vec![0; len];
228    str.resize(len, 0);
229    let str_as_fp: *mut Fp = str.as_mut_ptr().cast::<Fp>();
230    unsafe {
231        *str_as_fp = x.0;
232    }
233    str
234}
235
236#[wasm_bindgen]
237pub fn caml_pasta_fp_of_bytes(x: &[u8]) -> WasmPastaFp {
238    let len = core::mem::size_of::<Fp>();
239    if x.len() != len {
240        panic!("caml_pasta_fp_of_bytes");
241    };
242    let x = unsafe { *(x.as_ptr() as *const Fp) };
243    WasmPastaFp(x)
244}
245
246#[wasm_bindgen]
247pub fn caml_pasta_fp_deep_copy(x: WasmPastaFp) -> WasmPastaFp {
248    x
249}