arkworks/
bigint_256.rs

1extern crate alloc;
2
3use alloc::{string::String, vec::Vec};
4use ark_ff::{BigInt, BigInteger as ark_BigInteger, BigInteger256};
5use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
6
7use core::{
8    cmp::Ordering::{Equal, Greater, Less},
9    convert::TryInto,
10};
11use num_bigint::BigUint;
12use wasm_bindgen::{
13    convert::{FromWasmAbi, IntoWasmAbi},
14    prelude::*,
15};
16
17//
18// Handy constants
19//
20
21const BIGINT256_NUM_BITS: i32 = 256;
22const BIGINT256_LIMB_BITS: i32 = 64;
23const BIGINT256_LIMB_BYTES: i32 = BIGINT256_LIMB_BITS / 8;
24const BIGINT256_NUM_LIMBS: i32 =
25    (BIGINT256_NUM_BITS + BIGINT256_LIMB_BITS - 1) / BIGINT256_LIMB_BITS;
26const BIGINT256_NUM_BYTES: usize = (BIGINT256_NUM_LIMBS as usize) * 8;
27
28pub struct WasmBigInteger256(pub BigInteger256);
29
30impl wasm_bindgen::describe::WasmDescribe for WasmBigInteger256 {
31    fn describe() {
32        <Vec<u8> as wasm_bindgen::describe::WasmDescribe>::describe();
33    }
34}
35
36impl FromWasmAbi for WasmBigInteger256 {
37    type Abi = <Vec<u8> as FromWasmAbi>::Abi;
38    unsafe fn from_abi(js: Self::Abi) -> Self {
39        let bytes: Vec<u8> = FromWasmAbi::from_abi(js);
40        // TODO this used FromBytes before arkworks 0.4.2, check serialization is consistent after update
41        WasmBigInteger256(BigInteger256::deserialize_compressed(bytes.as_slice()).unwrap())
42    }
43}
44
45impl IntoWasmAbi for WasmBigInteger256 {
46    type Abi = <Vec<u8> as FromWasmAbi>::Abi;
47
48    fn into_abi(self) -> Self::Abi {
49        self.0.to_bytes_le().into_abi()
50    }
51}
52
53pub fn to_biguint(x: &BigInteger256) -> BigUint {
54    let x_ = x.0.as_ptr().cast::<u8>();
55    let x_ = unsafe { core::slice::from_raw_parts(x_, BIGINT256_NUM_BYTES) };
56    num_bigint::BigUint::from_bytes_le(x_)
57}
58
59pub fn of_biguint(x: &BigUint) -> BigInteger256 {
60    let mut bytes = x.to_bytes_le();
61    bytes.resize(BIGINT256_NUM_BYTES, 0);
62    let limbs = bytes.as_ptr();
63    let limbs = limbs.cast::<[u64; BIGINT256_NUM_LIMBS as usize]>();
64    let limbs = unsafe { &(*limbs) };
65    BigInt(*limbs)
66}
67
68#[wasm_bindgen]
69pub fn caml_bigint_256_of_numeral(s: String, _len: u32, base: u32) -> WasmBigInteger256 {
70    match BigUint::parse_bytes(&s.into_bytes(), base) {
71        Some(data) => WasmBigInteger256(of_biguint(&data)),
72        None => panic!("caml_bigint_256_of_numeral"),
73    }
74}
75
76#[wasm_bindgen]
77pub fn caml_bigint_256_of_decimal_string(s: String) -> WasmBigInteger256 {
78    match BigUint::parse_bytes(&s.into_bytes(), 10) {
79        Some(data) => WasmBigInteger256(of_biguint(&data)),
80        None => panic!("caml_bigint_256_of_decimal_string"),
81    }
82}
83
84#[wasm_bindgen]
85pub fn caml_bigint_256_num_limbs() -> i32 {
86    BIGINT256_NUM_LIMBS
87}
88
89#[wasm_bindgen]
90pub fn caml_bigint_256_bytes_per_limb() -> i32 {
91    BIGINT256_LIMB_BYTES
92}
93
94#[wasm_bindgen]
95pub fn caml_bigint_256_div(x: WasmBigInteger256, y: WasmBigInteger256) -> WasmBigInteger256 {
96    let res: BigUint = to_biguint(&x.0) / to_biguint(&y.0);
97    WasmBigInteger256(of_biguint(&res))
98}
99
100#[wasm_bindgen]
101pub fn caml_bigint_256_compare(x: WasmBigInteger256, y: WasmBigInteger256) -> i8 {
102    match x.0.cmp(&y.0) {
103        Less => -1,
104        Equal => 0,
105        Greater => 1,
106    }
107}
108
109// I don't think this is used anywhere
110#[cfg_attr(feature = "std", wasm_bindgen)]
111#[cfg(feature = "std")]
112pub fn caml_bigint_256_print(x: WasmBigInteger256) {
113    println!("{}", to_biguint(&x.0));
114}
115
116// I don't think this is used anywhere
117#[cfg_attr(feature = "std", wasm_bindgen)]
118#[cfg(feature = "std")]
119pub fn caml_bigint_256_to_string(x: WasmBigInteger256) -> String {
120    to_biguint(&x.0).to_string()
121}
122
123#[wasm_bindgen]
124pub fn caml_bigint_256_test_bit(x: WasmBigInteger256, i: i32) -> bool {
125    match i.try_into() {
126        Ok(i) => x.0.get_bit(i),
127        Err(_) => panic!("caml_bigint_256_test_bit"),
128    }
129}
130
131#[wasm_bindgen]
132pub fn caml_bigint_256_to_bytes(x: WasmBigInteger256) -> Vec<u8> {
133    // This is the size of the implementation of BigInteger256 at the time of writing
134    // but even if it changes, we will be no worse off than the original code `vec![]`
135    let mut serialized_bytes = Vec::with_capacity(core::mem::size_of::<WasmBigInteger256>());
136    x.0.serialize_compressed(&mut serialized_bytes)
137        .expect("serialize failed");
138    serialized_bytes
139}
140
141#[wasm_bindgen]
142pub fn caml_bigint_256_of_bytes(x: &[u8]) -> WasmBigInteger256 {
143    let len = core::mem::size_of::<WasmBigInteger256>();
144    assert!(x.len() == len, "caml_bigint_256_of_bytes");
145    // TODO this used FromBytes before arkworks 0.4.2, check serialization is consistent after update
146    WasmBigInteger256(
147        BigInteger256::deserialize_compressed(&mut &x[..]).expect("deserialization error"),
148    )
149}
150
151#[wasm_bindgen]
152pub fn caml_bigint_256_deep_copy(x: WasmBigInteger256) -> WasmBigInteger256 {
153    x
154}