plonk_wasm/arkworks/
pasta_fq.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, fq::FqParameters as Fq_params},
11    Fq,
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 WasmPastaFq(pub Fq);
23
24impl crate::wasm_flat_vector::FlatVectorElem for WasmPastaFq {
25    const FLATTENED_SIZE: usize = core::mem::size_of::<Fq>();
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        WasmPastaFq(Fq::deserialize_compressed(flat.as_slice()).unwrap())
33    }
34}
35
36impl From<Fq> for WasmPastaFq {
37    fn from(x: Fq) -> Self {
38        WasmPastaFq(x)
39    }
40}
41
42impl From<WasmPastaFq> for Fq {
43    fn from(x: WasmPastaFq) -> Self {
44        x.0
45    }
46}
47
48impl<'a> From<&'a WasmPastaFq> for &'a Fq {
49    fn from(x: &'a WasmPastaFq) -> Self {
50        &x.0
51    }
52}
53
54impl wasm_bindgen::describe::WasmDescribe for WasmPastaFq {
55    fn describe() {
56        <Vec<u8> as wasm_bindgen::describe::WasmDescribe>::describe()
57    }
58}
59
60impl FromWasmAbi for WasmPastaFq {
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        WasmPastaFq(Fq::deserialize_compressed(bytes.as_slice()).unwrap())
65    }
66}
67
68impl IntoWasmAbi for WasmPastaFq {
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 WasmPastaFq {
78    fn none() -> Self::Abi {
79        <Vec<u8> as OptionIntoWasmAbi>::none()
80    }
81}
82
83impl OptionFromWasmAbi for WasmPastaFq {
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_fq_size_in_bits() -> isize {
91    Fq_params::MODULUS_BITS as isize
92}
93
94#[wasm_bindgen]
95pub fn caml_pasta_fq_size() -> WasmBigInteger256 {
96    WasmBigInteger256(Fq_params::MODULUS)
97}
98
99#[wasm_bindgen]
100pub fn caml_pasta_fq_add(x: WasmPastaFq, y: WasmPastaFq) -> WasmPastaFq {
101    WasmPastaFq(x.0 + y.0)
102}
103
104#[wasm_bindgen]
105pub fn caml_pasta_fq_sub(x: WasmPastaFq, y: WasmPastaFq) -> WasmPastaFq {
106    WasmPastaFq(x.0 - y.0)
107}
108
109#[wasm_bindgen]
110pub fn caml_pasta_fq_negate(x: WasmPastaFq) -> WasmPastaFq {
111    WasmPastaFq(-x.0)
112}
113
114#[wasm_bindgen]
115pub fn caml_pasta_fq_mul(x: WasmPastaFq, y: WasmPastaFq) -> WasmPastaFq {
116    WasmPastaFq(x.0 * y.0)
117}
118
119#[wasm_bindgen]
120pub fn caml_pasta_fq_div(x: WasmPastaFq, y: WasmPastaFq) -> WasmPastaFq {
121    WasmPastaFq(x.0 / y.0)
122}
123
124#[wasm_bindgen]
125pub fn caml_pasta_fq_inv(x: WasmPastaFq) -> Option<WasmPastaFq> {
126    x.0.inverse().map(WasmPastaFq)
127}
128
129#[wasm_bindgen]
130pub fn caml_pasta_fq_square(x: WasmPastaFq) -> WasmPastaFq {
131    WasmPastaFq(x.0.square())
132}
133
134#[wasm_bindgen]
135pub fn caml_pasta_fq_is_square(x: WasmPastaFq) -> bool {
136    let s = x.0.pow(Fq_params::MODULUS_MINUS_ONE_DIV_TWO);
137    s.is_zero() || s.is_one()
138}
139
140#[wasm_bindgen]
141pub fn caml_pasta_fq_sqrt(x: WasmPastaFq) -> Option<WasmPastaFq> {
142    x.0.sqrt().map(WasmPastaFq)
143}
144
145#[wasm_bindgen]
146pub fn caml_pasta_fq_of_int(i: i32) -> WasmPastaFq {
147    WasmPastaFq(Fq::from(i as u64))
148}
149
150#[wasm_bindgen]
151pub fn caml_pasta_fq_to_string(x: WasmPastaFq) -> String {
152    bigint_256::to_biguint(&x.0.into_bigint()).to_string()
153}
154
155#[wasm_bindgen]
156pub fn caml_pasta_fq_of_string(s: String) -> Result<WasmPastaFq, JsValue> {
157    let biguint = BigUint::parse_bytes(s.as_bytes(), 10)
158        .ok_or(JsValue::from_str("caml_pasta_fq_of_string"))?;
159
160    match Fq::from_bigint(bigint_256::of_biguint(&biguint)) {
161        Some(x) => Ok(x.into()),
162        None => Err(JsValue::from_str("caml_pasta_fq_of_string")),
163    }
164}
165
166#[wasm_bindgen]
167pub fn caml_pasta_fq_print(x: WasmPastaFq) {
168    println!("{}", bigint_256::to_biguint(&(x.0.into_bigint())));
169}
170
171#[wasm_bindgen]
172pub fn caml_pasta_fq_compare(x: WasmPastaFq, y: WasmPastaFq) -> 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_fq_equal(x: WasmPastaFq, y: WasmPastaFq) -> bool {
182    x.0 == y.0
183}
184
185#[wasm_bindgen]
186pub fn caml_pasta_fq_random() -> WasmPastaFq {
187    WasmPastaFq(UniformRand::rand(&mut rand::thread_rng()))
188}
189
190#[wasm_bindgen]
191pub fn caml_pasta_fq_rng(i: i32) -> WasmPastaFq {
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    WasmPastaFq(UniformRand::rand(&mut rng))
196}
197
198#[wasm_bindgen]
199pub fn caml_pasta_fq_to_bigint(x: WasmPastaFq) -> WasmBigInteger256 {
200    WasmBigInteger256(x.0.into_bigint())
201}
202
203#[wasm_bindgen]
204pub fn caml_pasta_fq_of_bigint(x: WasmBigInteger256) -> Result<WasmPastaFq, JsValue> {
205    match Fq::from_bigint(x.0) {
206        Some(x) => Ok(x.into()),
207        None => Err(JsValue::from_str("caml_pasta_fq_of_bigint")),
208    }
209}
210
211#[wasm_bindgen]
212pub fn caml_pasta_fq_two_adic_root_of_unity() -> WasmPastaFq {
213    WasmPastaFq(<Fq as FftField>::TWO_ADIC_ROOT_OF_UNITY)
214}
215
216#[wasm_bindgen]
217pub fn caml_pasta_fq_domain_generator(log2_size: i32) -> WasmPastaFq {
218    match Domain::new(1 << log2_size) {
219        Some(x) => WasmPastaFq(x.group_gen),
220        None => panic!("caml_pasta_fq_domain_generator"),
221    }
222}
223
224#[wasm_bindgen]
225pub fn caml_pasta_fq_to_bytes(x: WasmPastaFq) -> Vec<u8> {
226    let len = core::mem::size_of::<Fq>();
227    let mut str: Vec<u8> = vec![0; len];
228    str.resize(len, 0);
229    let str_as_fq: *mut Fq = str.as_mut_ptr().cast::<Fq>();
230    unsafe {
231        *str_as_fq = x.0;
232    }
233    str
234}
235
236#[wasm_bindgen]
237pub fn caml_pasta_fq_of_bytes(x: &[u8]) -> WasmPastaFq {
238    let len = core::mem::size_of::<Fq>();
239    if x.len() != len {
240        panic!("caml_pasta_fq_of_bytes");
241    };
242    let x = unsafe { *(x.as_ptr() as *const Fq) };
243    WasmPastaFq(x)
244}
245
246#[wasm_bindgen]
247pub fn caml_pasta_fq_deep_copy(x: WasmPastaFq) -> WasmPastaFq {
248    x
249}