1use crate::error::{BigIntError, Result};
7use crate::limbs::{Limb, canonicalize, is_zero};
8
9pub trait BigIntCore {
14 fn limb_count(&self) -> usize;
16
17 fn limbs(&self) -> &[Limb];
19
20 fn limbs_mut(&mut self) -> &mut [Limb];
22
23 fn sign(&self) -> bool;
25
26 fn set_sign(&mut self, sign: bool);
28
29 fn is_zero(&self) -> bool {
31 is_zero(self.limbs())
32 }
33
34 fn canonicalize(&mut self) -> Result<()>;
39}
40
41#[cfg(feature = "alloc")]
42#[derive(Clone, Debug)]
47pub struct BigInt {
48 sign: bool,
50 limbs: alloc::vec::Vec<Limb>,
52 max_limbs: usize,
54}
55
56#[cfg(feature = "alloc")]
57impl BigInt {
58 pub fn new(max_limbs: usize) -> Self {
60 Self {
61 sign: false,
62 limbs: alloc::vec![0],
63 max_limbs,
64 }
65 }
66
67 pub fn from_u64(value: u64, max_limbs: usize) -> Self {
69 if value == 0 {
70 Self {
71 sign: false,
72 limbs: alloc::vec![0],
73 max_limbs,
74 }
75 } else {
76 Self {
77 sign: false,
78 limbs: alloc::vec![value],
79 max_limbs,
80 }
81 }
82 }
83
84 pub fn from_limbs(limbs: &[Limb], max_limbs: usize) -> Result<Self> {
88 if limbs.is_empty() {
89 return Ok(Self {
90 sign: false,
91 limbs: alloc::vec![0],
92 max_limbs,
93 });
94 }
95
96 if limbs.len() > max_limbs {
97 return Err(BigIntError::Overflow);
98 }
99
100 let mut limbs_vec = limbs.to_vec();
101 let len = canonicalize(&mut limbs_vec);
102 limbs_vec.truncate(len);
103
104 let is_zero = is_zero(&limbs_vec[..len]);
106 let sign = if is_zero { false } else { false }; Ok(Self {
109 sign,
110 limbs: limbs_vec,
111 max_limbs,
112 })
113 }
114
115 pub fn max_limbs(&self) -> usize {
117 self.max_limbs
118 }
119
120 pub fn ensure_capacity(&mut self, n: usize) -> Result<()> {
122 if n > self.max_limbs {
123 return Err(BigIntError::Overflow);
124 }
125 if self.limbs.len() < n {
126 self.limbs.resize(n, 0);
127 }
128 Ok(())
129 }
130}
131
132#[cfg(feature = "alloc")]
133impl BigIntCore for BigInt {
134 fn limb_count(&self) -> usize {
135 self.limbs.len()
136 }
137
138 fn limbs(&self) -> &[Limb] {
139 &self.limbs
140 }
141
142 fn limbs_mut(&mut self) -> &mut [Limb] {
143 &mut self.limbs
144 }
145
146 fn sign(&self) -> bool {
147 self.sign
148 }
149
150 fn set_sign(&mut self, sign: bool) {
151 if self.is_zero() {
153 self.sign = false;
154 } else {
155 self.sign = sign;
156 }
157 }
158
159 fn canonicalize(&mut self) -> Result<()> {
160 let len = canonicalize(&mut self.limbs);
161 self.limbs.truncate(len);
162
163 if self.is_zero() {
165 self.sign = false;
166 }
167
168 Ok(())
169 }
170}
171
172#[derive(Clone, Copy, Debug)]
177pub struct BigIntFixed<const L: usize> {
178 sign: bool,
180 limbs: [Limb; L],
182}
183
184impl<const L: usize> BigIntFixed<L> {
185 pub const fn zero() -> Self {
187 Self {
188 sign: false,
189 limbs: [0; L],
190 }
191 }
192
193 pub fn from_u64(value: u64) -> Self {
195 let mut limbs = [0u64; L];
196 if value != 0 {
197 limbs[0] = value;
198 }
199 Self { sign: false, limbs }
200 }
201
202 pub fn from_limbs(limbs: &[Limb]) -> Result<Self> {
207 let mut result_limbs = [0u64; L];
208 let copy_len = limbs.len().min(L);
209 result_limbs[..copy_len].copy_from_slice(&limbs[..copy_len]);
210
211 if limbs.len() > L {
213 if limbs[L..].iter().any(|&x| x != 0) {
215 return Err(BigIntError::Overflow);
216 }
217 }
218
219 Ok(Self {
220 sign: false,
221 limbs: result_limbs,
222 })
223 }
224
225 pub fn as_limbs(&self) -> &[Limb; L] {
227 &self.limbs
228 }
229
230 pub fn as_limbs_mut(&mut self) -> &mut [Limb; L] {
232 &mut self.limbs
233 }
234}
235
236impl<const L: usize> BigIntCore for BigIntFixed<L> {
237 fn limb_count(&self) -> usize {
238 L
239 }
240
241 fn limbs(&self) -> &[Limb] {
242 &self.limbs
243 }
244
245 fn limbs_mut(&mut self) -> &mut [Limb] {
246 &mut self.limbs
247 }
248
249 fn sign(&self) -> bool {
250 self.sign
251 }
252
253 fn set_sign(&mut self, sign: bool) {
254 if self.is_zero() {
256 self.sign = false;
257 } else {
258 self.sign = sign;
259 }
260 }
261
262 fn canonicalize(&mut self) -> Result<()> {
263 if self.is_zero() {
266 self.sign = false;
267 }
268 Ok(())
269 }
270}
271
272pub type U256 = BigIntFixed<4>;
274
275pub type U512 = BigIntFixed<8>;
277
278pub type U1024 = BigIntFixed<16>;
280
281pub type U2048 = BigIntFixed<32>;
283
284#[cfg(test)]
285mod tests {
286 use super::*;
287
288 #[test]
289 fn test_bigint_from_u64() {
290 let bi = BigInt::from_u64(42, 10);
291 assert_eq!(bi.limbs(), &[42]);
292 assert!(!bi.sign());
293 assert!(!bi.is_zero());
294 }
295
296 #[test]
297 fn test_bigint_zero() {
298 let bi = BigInt::from_u64(0, 10);
299 assert_eq!(bi.limbs(), &[0]);
300 assert!(!bi.sign());
301 assert!(bi.is_zero());
302 }
303
304 #[test]
305 fn test_bigint_fixed_from_u64() {
306 let bi = U256::from_u64(42);
307 assert_eq!(bi.limbs()[0], 42);
308 assert!(!bi.sign());
309 }
310
311 #[test]
312 fn test_bigint_fixed_zero() {
313 let bi = U256::zero();
314 assert!(bi.is_zero());
315 assert!(!bi.sign());
316 }
317
318 #[test]
319 fn test_canonicalize_zero_sign() {
320 let mut bi = BigInt::from_u64(0, 10);
321 bi.set_sign(true); bi.canonicalize().unwrap();
323 assert!(!bi.sign()); }
325}