1use crate::error::{BigIntError, Result};
9use crate::limbs::{Limb, canonicalize, is_zero};
10use crate::types::{BigInt, BigIntCore};
11
12#[cfg(feature = "alloc")]
13pub fn encode(bi: &BigInt) -> alloc::vec::Vec<u8> {
17 let limbs = bi.limbs();
18 let canonical_limbs = {
19 let mut limbs_copy = limbs.to_vec();
20 let len = canonicalize(&mut limbs_copy);
21 limbs_copy.truncate(len);
22 limbs_copy
23 };
24
25 let limb_count = canonical_limbs.len() as u32;
26 let sign_byte = if bi.sign() { 1u8 } else { 0u8 };
27
28 let mut result = alloc::vec::Vec::with_capacity(1 + 4 + (8 * canonical_limbs.len()));
30
31 result.push(sign_byte);
33
34 result.extend_from_slice(&limb_count.to_le_bytes());
36
37 for &limb in &canonical_limbs {
39 result.extend_from_slice(&limb.to_le_bytes());
40 }
41
42 result
43}
44
45#[cfg(feature = "alloc")]
46pub fn decode(data: &[u8]) -> Result<BigInt> {
53 if data.len() < 5 {
54 return Err(BigIntError::InvalidEncoding);
55 }
56
57 let sign_byte = data[0];
59 if sign_byte > 1 {
60 return Err(BigIntError::InvalidEncoding);
61 }
62 let sign = sign_byte != 0;
63
64 let limb_count_bytes = data[1..5]
66 .try_into()
67 .map_err(|_| BigIntError::InvalidEncoding)?;
68 let limb_count = u32::from_le_bytes(limb_count_bytes) as usize;
69
70 if limb_count == 0 || limb_count > crate::gas::MAX_LIMBS {
72 return Err(BigIntError::InvalidEncoding);
73 }
74
75 let expected_len = 1 + 4 + (8 * limb_count);
77 if data.len() < expected_len {
78 return Err(BigIntError::InvalidEncoding);
79 }
80
81 let mut limbs = alloc::vec::Vec::with_capacity(limb_count);
83 for i in 0..limb_count {
84 let offset = 5 + (i * 8);
85 let limb_bytes = data[offset..offset + 8]
86 .try_into()
87 .map_err(|_| BigIntError::InvalidEncoding)?;
88 let limb = Limb::from_le_bytes(limb_bytes);
89 limbs.push(limb);
90 }
91
92 let is_zero_value = is_zero(&limbs);
95 if is_zero_value {
96 if sign {
97 return Err(BigIntError::InvalidEncoding); }
99 if limb_count != 1 || limbs[0] != 0 {
100 return Err(BigIntError::InvalidEncoding);
101 }
102 } else {
103 if limbs[limb_count - 1] == 0 {
105 return Err(BigIntError::InvalidEncoding);
106 }
107
108 }
112
113 let max_limbs = limb_count.max(crate::gas::MAX_LIMBS);
115 let mut result = BigInt::from_limbs(&limbs, max_limbs)?;
116 result.set_sign(sign);
117
118 result.canonicalize()?;
120
121 Ok(result)
122}
123
124#[cfg(all(test, feature = "alloc"))]
125mod tests {
126 use super::*;
127 use alloc::vec;
128
129 #[test]
130 fn test_encode_zero() {
131 let bi = BigInt::from_u64(0, 10);
132 let encoded = encode(&bi);
133 assert_eq!(encoded[0], 0); assert_eq!(u32::from_le_bytes(encoded[1..5].try_into().unwrap()), 1); assert_eq!(u64::from_le_bytes(encoded[5..13].try_into().unwrap()), 0); }
137
138 #[test]
139 fn test_encode_decode_roundtrip() {
140 let bi = BigInt::from_u64(42, 10);
141 let encoded = encode(&bi);
142 let decoded = decode(&encoded).unwrap();
143 assert_eq!(decoded.limbs()[0], 42);
144 assert_eq!(decoded.sign(), bi.sign());
145 }
146
147 #[test]
148 fn test_decode_invalid_negative_zero() {
149 let mut invalid = vec![1u8]; invalid.extend_from_slice(&1u32.to_le_bytes()); invalid.extend_from_slice(&0u64.to_le_bytes()); assert!(decode(&invalid).is_err());
154 }
155
156 #[test]
157 fn test_decode_invalid_leading_zeros() {
158 let mut invalid = vec![0u8]; invalid.extend_from_slice(&2u32.to_le_bytes()); invalid.extend_from_slice(&42u64.to_le_bytes()); invalid.extend_from_slice(&0u64.to_le_bytes()); assert!(decode(&invalid).is_err());
164 }
165}