kimchi_stubs/arkworks/
bigint_256.rs1use 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
12const 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#[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
72impl 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#[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#[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 let x2: BigUint = y.into();
254 assert!(x2 == x);
255 println!("biguint.to_string: {}", x2);
256 }
257}