mina_p2p_messages/
bigint.rs

1use ark_ff::{fields::arithmetic::InvalidBigInt, BigInteger256};
2use malloc_size_of::MallocSizeOf;
3use rsexp::{OfSexp, SexpOf};
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, derive_more::From, derive_more::Into)]
7pub struct BigInt(BigInteger256);
8
9impl std::fmt::Debug for BigInt {
10    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11        let Self(bigint) = self;
12        // Avoid vertical alignment
13        f.write_fmt(format_args!("BigInt({:?})", bigint.to_native()))
14    }
15}
16
17impl MallocSizeOf for BigInt {
18    fn size_of(&self, _ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
19        0
20    }
21}
22
23#[derive(Debug, thiserror::Error)]
24#[error("Invalid decimal number")]
25pub struct InvalidDecimalNumber;
26
27impl BigInt {
28    pub fn zero() -> Self {
29        mina_curves::pasta::Fp::from(0u64).into()
30    }
31
32    pub fn one() -> Self {
33        mina_curves::pasta::Fp::from(1u64).into()
34    }
35
36    pub fn to_field<F>(&self) -> Result<F, InvalidBigInt>
37    where
38        F: ark_ff::Field + TryFrom<BigInteger256, Error = InvalidBigInt>,
39    {
40        let Self(biginteger) = self;
41        F::try_from(*biginteger)
42    }
43
44    pub fn to_bytes(&self) -> [u8; 32] {
45        use ark_ff::ToBytes;
46        let mut bytes = std::io::Cursor::new([0u8; 32]);
47        self.0.write(&mut bytes).unwrap(); // Never fail, there is 32 bytes
48        bytes.into_inner()
49    }
50
51    pub fn from_bytes(bytes: [u8; 32]) -> Self {
52        use ark_ff::FromBytes;
53        Self(BigInteger256::read(&bytes[..]).unwrap()) // Never fail, we read from 32 bytes
54    }
55
56    pub fn from_decimal(s: &str) -> Result<Self, InvalidDecimalNumber> {
57        num_bigint::BigInt::<4>::parse_bytes(s.as_bytes(), 10)
58            .map(|num| {
59                let mut bytes = num.to_bytes_be().1;
60                bytes.reverse();
61                bytes.resize(32, 0); // Ensure the byte vector has 32 bytes
62                BigInt::from_bytes(bytes.try_into().unwrap())
63            })
64            .ok_or(InvalidDecimalNumber)
65    }
66
67    pub fn to_decimal(&self) -> String {
68        let bigint: num_bigint::BigUint = self.0.into();
69        bigint.to_string()
70    }
71}
72
73impl AsRef<BigInteger256> for BigInt {
74    fn as_ref(&self) -> &BigInteger256 {
75        let Self(biginteger) = self;
76        biginteger
77    }
78}
79
80impl From<mina_curves::pasta::Fp> for BigInt {
81    fn from(field: mina_curves::pasta::Fp) -> Self {
82        use ark_ff::PrimeField;
83        Self(field.into_repr())
84    }
85}
86
87impl From<mina_curves::pasta::Fq> for BigInt {
88    fn from(field: mina_curves::pasta::Fq) -> Self {
89        use ark_ff::PrimeField;
90        Self(field.into_repr())
91    }
92}
93
94impl From<&mina_curves::pasta::Fp> for BigInt {
95    fn from(field: &mina_curves::pasta::Fp) -> Self {
96        use ark_ff::PrimeField;
97        Self(field.into_repr())
98    }
99}
100
101impl From<&mina_curves::pasta::Fq> for BigInt {
102    fn from(field: &mina_curves::pasta::Fq) -> Self {
103        use ark_ff::PrimeField;
104        Self(field.into_repr())
105    }
106}
107
108impl TryFrom<BigInt> for mina_curves::pasta::Fp {
109    type Error = <mina_curves::pasta::Fp as TryFrom<BigInteger256>>::Error;
110    fn try_from(bigint: BigInt) -> Result<Self, Self::Error> {
111        bigint.to_field()
112    }
113}
114
115impl TryFrom<BigInt> for mina_curves::pasta::Fq {
116    type Error = <mina_curves::pasta::Fq as TryFrom<BigInteger256>>::Error;
117    fn try_from(bigint: BigInt) -> Result<Self, Self::Error> {
118        bigint.to_field()
119    }
120}
121
122impl TryFrom<&BigInt> for mina_curves::pasta::Fp {
123    type Error = <mina_curves::pasta::Fp as TryFrom<BigInteger256>>::Error;
124    fn try_from(bigint: &BigInt) -> Result<Self, Self::Error> {
125        bigint.to_field()
126    }
127}
128
129impl TryFrom<&BigInt> for mina_curves::pasta::Fq {
130    type Error = <mina_curves::pasta::Fq as TryFrom<BigInteger256>>::Error;
131    fn try_from(bigint: &BigInt) -> Result<Self, Self::Error> {
132        bigint.to_field()
133    }
134}
135
136impl OfSexp for BigInt {
137    fn of_sexp(s: &rsexp::Sexp) -> Result<Self, rsexp::IntoSexpError>
138    where
139        Self: Sized,
140    {
141        let bytes = s.extract_atom("BigInt")?;
142        let hex_str = std::str::from_utf8(bytes).map_err(|_| {
143            rsexp::IntoSexpError::StringConversionError {
144                err: format!("Expected hex string with 0x prefix, got {bytes:?}"),
145            }
146        })?;
147
148        let hex_str = hex_str.strip_prefix("0x").unwrap_or(hex_str);
149
150        let padded_hex = format!("{:0>64}", hex_str);
151
152        if padded_hex.len() != 64 {
153            return Err(rsexp::IntoSexpError::StringConversionError {
154                err: format!("Expected 64-character hex string, got {padded_hex:?}"),
155            });
156        }
157
158        let byte_vec: Vec<u8> = (0..padded_hex.len())
159            .step_by(2)
160            .map(|i| u8::from_str_radix(&padded_hex[i..i + 2], 16))
161            .rev()
162            .collect::<Result<Vec<u8>, _>>()
163            .map_err(|_| rsexp::IntoSexpError::StringConversionError {
164                err: format!("Failed to parse hex string: {padded_hex:?}"),
165            })?;
166
167        Ok(BigInt::from_bytes(byte_vec.try_into().unwrap()))
168    }
169}
170
171impl SexpOf for BigInt {
172    fn sexp_of(&self) -> rsexp::Sexp {
173        use std::fmt::Write;
174        let byte_vec = self.to_bytes();
175        let hex_str = byte_vec
176            .iter()
177            .rev()
178            .fold("0x".to_string(), |mut output, byte| {
179                let _ = write!(output, "{byte:02X}");
180                output
181            });
182
183        rsexp::Sexp::Atom(hex_str.into_bytes())
184    }
185}
186
187impl binprot::BinProtRead for BigInt {
188    fn binprot_read<R: std::io::Read + ?Sized>(r: &mut R) -> Result<Self, binprot::Error>
189    where
190        Self: Sized,
191    {
192        use ark_ff::FromBytes;
193        Ok(Self(BigInteger256::read(r)?))
194    }
195}
196
197impl binprot::BinProtWrite for BigInt {
198    fn binprot_write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
199        use ark_ff::ToBytes;
200        let Self(biginteger) = self;
201        biginteger.write(w)
202    }
203}
204
205impl Serialize for BigInt {
206    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
207    where
208        S: serde::Serializer,
209    {
210        if serializer.is_human_readable() {
211            // TODO get rid of copying
212            let mut rev = self.to_bytes();
213            rev[..].reverse();
214            let mut hex = [0_u8; 32 * 2 + 2];
215            hex[..2].copy_from_slice(b"0x");
216            hex::encode_to_slice(rev, &mut hex[2..]).unwrap();
217            serializer.serialize_str(String::from_utf8_lossy(&hex).as_ref())
218        } else {
219            serializer.serialize_bytes(&self.to_bytes())
220        }
221    }
222}
223
224impl<'de> Deserialize<'de> for BigInt {
225    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
226    where
227        D: serde::Deserializer<'de>,
228    {
229        if deserializer.is_human_readable() {
230            struct V;
231            impl<'de> serde::de::Visitor<'de> for V {
232                type Value = Vec<u8>;
233
234                fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
235                    formatter.write_str("hex string or numeric string")
236                }
237
238                fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
239                where
240                    E: serde::de::Error,
241                {
242                    match v.strip_prefix("0x") {
243                        Some(v) => hex::decode(v).map_err(|_| {
244                            serde::de::Error::custom(format!("failed to decode hex str: {v}"))
245                        }),
246                        None => {
247                            // Try to parse as a decimal number
248                            num_bigint::BigInt::<4>::parse_bytes(v.as_bytes(), 10)
249                                .map(|num| {
250                                    let mut bytes = num.to_bytes_be().1;
251                                    bytes.reverse();
252                                    bytes.resize(32, 0); // Ensure the byte vector has 32 bytes
253                                    bytes.reverse();
254                                    bytes
255                                })
256                                .ok_or_else(|| {
257                                    serde::de::Error::custom(
258                                        "failed to parse decimal number".to_string(),
259                                    )
260                                })
261                        }
262                    }
263                }
264
265                fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
266                where
267                    E: serde::de::Error,
268                {
269                    self.visit_borrowed_str(v)
270                }
271            }
272            let mut v = deserializer.deserialize_str(V)?;
273            v.reverse();
274            v.try_into()
275                .map_err(|_| serde::de::Error::custom("failed to convert vec to array".to_string()))
276        } else {
277            struct V;
278            impl serde::de::Visitor<'_> for V {
279                type Value = [u8; 32];
280
281                fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
282                    formatter.write_str("sequence of 32 bytes")
283                }
284
285                fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
286                where
287                    E: serde::de::Error,
288                {
289                    let v: [u8; 32] = v
290                        .try_into()
291                        .map_err(|_| serde::de::Error::custom("expecting 32 bytes".to_string()))?;
292                    Ok(v)
293                }
294            }
295            deserializer.deserialize_bytes(V)
296        }
297        .map(Self::from_bytes)
298    }
299}
300
301impl mina_hasher::Hashable for BigInt {
302    type D = ();
303
304    fn to_roinput(&self) -> mina_hasher::ROInput {
305        mina_hasher::ROInput::new()
306            .append_field(self.to_field().expect("Failed to convert Hash into Fp"))
307    }
308
309    fn domain_string(_: Self::D) -> Option<String> {
310        None
311    }
312}
313
314#[cfg(test)]
315mod tests {
316    use binprot::{BinProtRead, BinProtWrite};
317
318    use super::BigInt;
319
320    fn to_binprot(v: &BigInt) -> Vec<u8> {
321        let mut w = Vec::new();
322        v.binprot_write(&mut w).unwrap();
323        w
324    }
325
326    fn from_binprot(mut b: &[u8]) -> BigInt {
327        BigInt::binprot_read(&mut b).unwrap()
328    }
329
330    fn from_byte(b: u8) -> BigInt {
331        BigInt::from_bytes([b; 32])
332    }
333
334    fn from_bytes<'a, I>(it: I) -> BigInt
335    where
336        I: IntoIterator<Item = &'a u8>,
337        I::IntoIter: Clone,
338    {
339        let mut bytes = [0; 32];
340        let it = it.into_iter().cycle();
341        bytes.iter_mut().zip(it).for_each(|(b, i)| *b = *i);
342        BigInt::from_bytes(bytes)
343    }
344
345    #[test]
346    fn serialize_bigint() {
347        let bigints = [
348            from_byte(0),
349            from_byte(1),
350            from_byte(0xff),
351            from_bytes(&[0, 1, 2, 3, 4]),
352        ];
353
354        for bigint in bigints {
355            let binprot = to_binprot(&bigint);
356            assert_eq!(binprot.as_slice(), bigint.to_bytes());
357        }
358    }
359
360    #[test]
361    fn deserialize_bigint() {
362        let bigints = [
363            from_byte(0),
364            from_byte(1),
365            from_byte(0xff),
366            from_bytes(&[0, 1, 2, 3, 4]),
367        ];
368
369        for bigint in bigints {
370            let deser: BigInt = from_binprot(&bigint.to_bytes());
371            assert_eq!(&bigint.0, &deser.0);
372        }
373    }
374
375    #[test]
376    fn to_json() {
377        let bigints = [
378            from_byte(0),
379            from_byte(1),
380            from_byte(0xff),
381            from_bytes(&[0, 1, 2, 3, 4]),
382        ];
383
384        for bigint in bigints {
385            let json = serde_json::to_string(&bigint).unwrap();
386            let mut v = bigint.to_bytes();
387            v.reverse();
388            let json_exp = format!(r#""0x{}""#, hex::encode(v));
389            assert_eq!(json, json_exp);
390        }
391    }
392
393    #[test]
394    fn from_json() {
395        let bigints = [
396            from_byte(0),
397            from_byte(1),
398            from_byte(0xff),
399            from_bytes(&[0, 1, 2, 3, 4]),
400        ];
401
402        for bigint in bigints {
403            let mut be = bigint.to_bytes();
404            be.reverse();
405            let json = format!(r#""0x{}""#, hex::encode(be.as_ref()));
406            let bigint_exp = serde_json::from_str(&json).unwrap();
407            assert_eq!(bigint, bigint_exp);
408        }
409    }
410
411    #[test]
412    fn from_numeric_string() {
413        let hex = "075bcd1500000000000000000000000000000000000000000000000000000000";
414        let deser: BigInt = serde_json::from_str(r#""123456789""#).unwrap();
415
416        let mut deser = deser.to_bytes();
417        deser.reverse();
418        let result_hex = hex::encode(deser);
419
420        assert_eq!(result_hex, hex.to_string());
421    }
422
423    #[test]
424    fn from_numeric_string_2() {
425        let rx =
426            r#""23298604903871047876308234794524469025218548053411207476198573374353464993732""#;
427        let s = r#""160863098041039391219472069845715442980741444645399750596310972807022542440""#;
428
429        let deser_rx: BigInt = serde_json::from_str(rx).unwrap();
430        let deser_s: BigInt = serde_json::from_str(s).unwrap();
431
432        println!("rx: {:?}", deser_rx);
433        println!("s: {:?}", deser_s);
434
435        let _ = deser_rx.to_field::<mina_curves::pasta::Fp>().unwrap();
436        println!("rx OK");
437        let _ = deser_s.to_field::<mina_curves::pasta::Fp>().unwrap();
438        println!("s OK");
439    }
440
441    use super::*;
442    use rsexp::Sexp;
443
444    #[test]
445    fn test_sexp_bigint() {
446        let hex_str = "0x248D179F4E92EA85C644CD99EF72187463B541D5F797943898C3D7A6CEEEC523";
447        let expected_array = [
448            0x98C3D7A6CEEEC523,
449            0x63B541D5F7979438,
450            0xC644CD99EF721874,
451            0x248D179F4E92EA85,
452        ];
453
454        let original_sexp = Sexp::Atom(hex_str.as_bytes().to_vec());
455
456        let result = BigInt::of_sexp(&original_sexp).expect("Failed to convert Sexp to BigInt");
457        let expected_result = BigInt(BigInteger256::from_64x4(expected_array));
458
459        assert_eq!(result, expected_result);
460
461        let produced_sexp = result.sexp_of();
462
463        assert_eq!(original_sexp, produced_sexp);
464    }
465}