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