cardano_serialization_lib/serialization/numeric/
big_int.rs

1use crate::*;
2use crate::serialization::utils::read_nint;
3
4impl Serialize for BigInt {
5    fn serialize<'se, W: Write>(
6        &self,
7        serializer: &'se mut Serializer<W>,
8    ) -> cbor_event::Result<&'se mut Serializer<W>> {
9        let (sign, u64_digits) = self.0.to_u64_digits();
10        match u64_digits.len() {
11            0 => serializer.write_unsigned_integer(0),
12            // we use the uint/nint encodings to use a minimum of space
13            1 => match sign {
14                // uint
15                num_bigint::Sign::Plus | num_bigint::Sign::NoSign => {
16                    serializer.write_unsigned_integer(*u64_digits.first().unwrap())
17                }
18                // nint
19                num_bigint::Sign::Minus => serializer
20                    .write_negative_integer(-(*u64_digits.first().unwrap() as i128) as i64),
21            },
22            _ => {
23                // Small edge case: nint's minimum is -18446744073709551616 but in this bigint lib
24                // that takes 2 u64 bytes so we put that as a special case here:
25                if sign == num_bigint::Sign::Minus && u64_digits == vec![0, 1] {
26                    serializer.write_negative_integer(-18446744073709551616i128 as i64)
27                } else {
28                    let (sign, bytes) = self.0.to_bytes_be();
29                    match sign {
30                        // positive bigint
31                        num_bigint::Sign::Plus | num_bigint::Sign::NoSign => {
32                            serializer.write_tag(2u64)?;
33                            write_bounded_bytes(serializer, &bytes)
34                        }
35                        // negative bigint
36                        num_bigint::Sign::Minus => {
37                            serializer.write_tag(3u64)?;
38                            use std::ops::Neg;
39                            // CBOR RFC defines this as the bytes of -n -1
40                            let adjusted = self
41                                .0
42                                .clone()
43                                .neg()
44                                .checked_sub(&num_bigint::BigInt::from(1u32))
45                                .unwrap()
46                                .to_biguint()
47                                .unwrap();
48                            write_bounded_bytes(serializer, &adjusted.to_bytes_be())
49                        }
50                    }
51                }
52            }
53        }
54    }
55}
56
57impl Deserialize for BigInt {
58    fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
59        (|| -> Result<_, DeserializeError> {
60            match raw.cbor_type()? {
61                // bigint
62                CBORType::Tag => {
63                    let tag = raw.tag()?;
64                    let bytes = read_bounded_bytes(raw)?;
65                    match tag {
66                        // positive bigint
67                        2 => Ok(Self(num_bigint::BigInt::from_bytes_be(
68                            num_bigint::Sign::Plus,
69                            &bytes,
70                        ))),
71                        // negative bigint
72                        3 => {
73                            // CBOR RFC defines this as the bytes of -n -1
74                            let initial =
75                                num_bigint::BigInt::from_bytes_be(num_bigint::Sign::Plus, &bytes);
76                            use std::ops::Neg;
77                            let adjusted = initial
78                                .checked_add(&num_bigint::BigInt::from(1u32))
79                                .unwrap()
80                                .neg();
81                            Ok(Self(adjusted))
82                        }
83                        _ => {
84                            return Err(DeserializeFailure::TagMismatch {
85                                found: tag,
86                                expected: 2,
87                            }
88                                .into());
89                        }
90                    }
91                }
92                // uint
93                CBORType::UnsignedInteger => {
94                    Ok(Self(num_bigint::BigInt::from(raw.unsigned_integer()?)))
95                }
96                // nint
97                CBORType::NegativeInteger => Ok(Self(num_bigint::BigInt::from(read_nint(raw)?))),
98                _ => return Err(DeserializeFailure::NoVariantMatched.into()),
99            }
100        })()
101            .map_err(|e| e.annotate("BigInt"))
102    }
103}