kimchi_stubs/arkworks/
bigint_256.rs

1use crate::caml::caml_bytes_string::CamlBytesString;
2use ark_ff::{BigInteger as ark_BigInteger, BigInteger256};
3use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
4use core::{
5    cmp::Ordering::{Equal, Greater, Less},
6    convert::{TryFrom, TryInto},
7    fmt::{Display, Formatter},
8    ops::Deref,
9};
10use num_bigint::BigUint;
11
12//
13// Handy constants
14//
15
16const BIGINT256_NUM_BITS: i32 = 256;
17const BIGINT256_LIMB_BITS: i32 = 64;
18const BIGINT256_LIMB_BYTES: i32 = BIGINT256_LIMB_BITS / 8;
19const BIGINT256_NUM_LIMBS: i32 =
20    (BIGINT256_NUM_BITS + BIGINT256_LIMB_BITS - 1) / BIGINT256_LIMB_BITS;
21
22//
23// Wrapper struct to implement OCaml bindings
24//
25
26#[derive(Clone, Copy, Debug, ocaml_gen::CustomType)]
27pub struct CamlBigInteger256(pub BigInteger256);
28
29impl From<BigInteger256> for CamlBigInteger256 {
30    fn from(big: BigInteger256) -> Self {
31        Self(big)
32    }
33}
34
35unsafe impl<'a> ocaml::FromValue<'a> for CamlBigInteger256 {
36    fn from_value(value: ocaml::Value) -> Self {
37        let x: ocaml::Pointer<Self> = ocaml::FromValue::from_value(value);
38        *x.as_ref()
39    }
40}
41
42impl CamlBigInteger256 {
43    unsafe extern "C" fn caml_pointer_finalize(v: ocaml::Raw) {
44        let ptr = v.as_pointer::<Self>();
45        ptr.drop_in_place()
46    }
47
48    unsafe extern "C" fn ocaml_compare(x: ocaml::Raw, y: ocaml::Raw) -> i32 {
49        let x = x.as_pointer::<Self>();
50        let y = y.as_pointer::<Self>();
51        match x.as_ref().0.cmp(&y.as_ref().0) {
52            core::cmp::Ordering::Less => -1,
53            core::cmp::Ordering::Equal => 0,
54            core::cmp::Ordering::Greater => 1,
55        }
56    }
57}
58
59ocaml::custom!(CamlBigInteger256 {
60    finalize: CamlBigInteger256::caml_pointer_finalize,
61    compare: CamlBigInteger256::ocaml_compare,
62});
63
64impl Deref for CamlBigInteger256 {
65    type Target = BigInteger256;
66
67    fn deref(&self) -> &Self::Target {
68        &self.0
69    }
70}
71
72//
73// BigUint handy methods
74//
75
76impl From<CamlBigInteger256> for BigUint {
77    fn from(x: CamlBigInteger256) -> BigUint {
78        x.0.into()
79    }
80}
81
82impl From<&CamlBigInteger256> for BigUint {
83    fn from(x: &CamlBigInteger256) -> BigUint {
84        x.0.into()
85    }
86}
87
88impl TryFrom<BigUint> for CamlBigInteger256 {
89    type Error = String;
90
91    fn try_from(x: BigUint) -> Result<Self, Self::Error> {
92        Ok(Self(
93            BigInteger256::try_from(x).map_err(|()| "Biginteger256 was too big")?,
94        ))
95    }
96}
97
98impl TryFrom<&BigUint> for CamlBigInteger256 {
99    type Error = String;
100
101    fn try_from(x: &BigUint) -> Result<Self, Self::Error> {
102        Ok(Self(
103            BigInteger256::try_from(x.clone()).map_err(|()| "Biginteger256 was too big")?,
104        ))
105    }
106}
107
108impl Display for CamlBigInteger256 {
109    fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
110        write!(f, "{}", Into::<BigUint>::into(self))
111    }
112}
113
114//
115// OCaml stuff
116//
117
118#[ocaml_gen::func]
119#[ocaml::func]
120pub fn caml_bigint_256_of_numeral(
121    s: CamlBytesString,
122    _len: ocaml::Int,
123    base: ocaml::Int,
124) -> Result<CamlBigInteger256, ocaml::Error> {
125    match BigUint::parse_bytes(
126        s.0,
127        base.try_into()
128            .map_err(|_| ocaml::Error::Message("caml_bigint_256_of_numeral"))?,
129    ) {
130        Some(data) => CamlBigInteger256::try_from(data)
131            .map_err(|_| ocaml::Error::Message("caml_bigint_256_of_numeral")),
132        None => Err(ocaml::Error::Message("caml_bigint_256_of_numeral")),
133    }
134}
135
136#[ocaml_gen::func]
137#[ocaml::func]
138pub fn caml_bigint_256_of_decimal_string(
139    s: CamlBytesString,
140) -> Result<CamlBigInteger256, ocaml::Error> {
141    match BigUint::parse_bytes(s.0, 10) {
142        Some(data) => CamlBigInteger256::try_from(data)
143            .map_err(|_| ocaml::Error::Message("caml_bigint_256_of_decimal_string")),
144        None => Err(ocaml::Error::Message("caml_bigint_256_of_decimal_string")),
145    }
146}
147
148#[ocaml_gen::func]
149#[ocaml::func]
150pub fn caml_bigint_256_num_limbs() -> ocaml::Int {
151    BIGINT256_NUM_LIMBS.try_into().unwrap()
152}
153
154#[ocaml_gen::func]
155#[ocaml::func]
156pub fn caml_bigint_256_bytes_per_limb() -> ocaml::Int {
157    BIGINT256_LIMB_BYTES.try_into().unwrap()
158}
159
160#[ocaml_gen::func]
161#[ocaml::func]
162pub fn caml_bigint_256_div(x: CamlBigInteger256, y: CamlBigInteger256) -> CamlBigInteger256 {
163    let x: BigUint = x.into();
164    let y: BigUint = y.into();
165    let res: BigUint = x / y;
166    let inner: BigInteger256 = res.try_into().expect("BigUint division has a bug");
167    inner.into()
168}
169
170#[ocaml_gen::func]
171#[ocaml::func]
172pub fn caml_bigint_256_compare(
173    x: ocaml::Pointer<CamlBigInteger256>,
174    y: ocaml::Pointer<CamlBigInteger256>,
175) -> ocaml::Int {
176    match x.as_ref().cmp(y.as_ref()) {
177        Less => -1,
178        Equal => 0,
179        Greater => 1,
180    }
181}
182
183#[ocaml_gen::func]
184#[ocaml::func]
185pub fn caml_bigint_256_print(x: CamlBigInteger256) {
186    println!("{}", x)
187}
188
189#[ocaml_gen::func]
190#[ocaml::func]
191pub fn caml_bigint_256_to_string(x: CamlBigInteger256) -> String {
192    x.to_string()
193}
194
195#[ocaml_gen::func]
196#[ocaml::func]
197pub fn caml_bigint_256_test_bit(
198    x: ocaml::Pointer<CamlBigInteger256>,
199    i: ocaml::Int,
200) -> Result<bool, ocaml::Error> {
201    match i.try_into() {
202        Ok(i) => Ok(x.as_ref().get_bit(i)),
203        Err(_) => Err(ocaml::Error::invalid_argument("caml_bigint_256_test_bit")
204            .err()
205            .unwrap()),
206    }
207}
208
209#[ocaml_gen::func]
210#[ocaml::func]
211pub fn caml_bigint_256_to_bytes(
212    x: ocaml::Pointer<CamlBigInteger256>,
213) -> [u8; core::mem::size_of::<BigInteger256>()] {
214    let mut res = [0u8; core::mem::size_of::<BigInteger256>()];
215    x.as_ref().0.serialize_compressed(&mut res[..]).unwrap();
216    res
217}
218
219#[ocaml_gen::func]
220#[ocaml::func]
221pub fn caml_bigint_256_of_bytes(x: &[u8]) -> Result<CamlBigInteger256, ocaml::Error> {
222    let len = core::mem::size_of::<BigInteger256>();
223    if x.len() != len {
224        ocaml::Error::failwith("caml_bigint_256_of_bytes")?;
225    };
226    let result = BigInteger256::deserialize_compressed(&mut &*x)
227        .map_err(|_| ocaml::Error::Message("deserialization error"))?;
228    Ok(CamlBigInteger256(result))
229}
230
231#[ocaml_gen::func]
232#[ocaml::func]
233pub fn caml_bigint_256_deep_copy(x: CamlBigInteger256) -> CamlBigInteger256 {
234    x
235}
236
237//
238// Tests
239//
240
241#[cfg(test)]
242mod tests {
243    use super::*;
244    use num_bigint::ToBigUint;
245
246    #[test]
247    fn biguint() {
248        let x = 10000.to_biguint().unwrap();
249        println!("biguint.to_string: {}", x);
250        let y = CamlBigInteger256::try_from(x.clone()).unwrap();
251        println!("camlbigint.to_string: {}", y);
252        //assert!(&y.to_string() == "10000");
253        let x2: BigUint = y.into();
254        assert!(x2 == x);
255        println!("biguint.to_string: {}", x2);
256    }
257}