Skip to main content

crypto_bigint/uint/
boxed.rs

1//! Heap-allocated big unsigned integers.
2
3mod add;
4mod add_mod;
5mod bit_and;
6mod bit_not;
7mod bit_or;
8mod bit_xor;
9mod bits;
10mod cmp;
11mod ct;
12pub(crate) mod div;
13pub(crate) mod encoding;
14mod from;
15mod gcd;
16mod invert_mod;
17mod mul;
18mod mul_mod;
19mod neg;
20mod neg_mod;
21mod pow;
22mod pow_mod;
23mod shl;
24mod shr;
25mod sqrt;
26mod sub;
27mod sub_mod;
28
29#[cfg(feature = "rand_core")]
30mod rand;
31
32use crate::{
33    Choice, CtAssign, CtEq, CtOption, Integer, Limb, NonZero, Odd, One, Resize, UintRef, Unsigned,
34    UnsignedWithMontyForm, Word, Zero, modular::BoxedMontyForm,
35};
36use alloc::{boxed::Box, vec, vec::Vec};
37use core::{
38    borrow::{Borrow, BorrowMut},
39    fmt,
40    iter::repeat,
41};
42
43#[cfg(feature = "zeroize")]
44use zeroize::Zeroize;
45
46/// Fixed-precision heap-allocated big unsigned integer.
47///
48/// Alternative to the stack-allocated [`Uint`][`crate::Uint`] but with a
49/// fixed precision chosen at runtime instead of compile time.
50///
51/// Unlike many other heap-allocated big integer libraries, this type is not
52/// arbitrary precision and will wrap at its fixed-precision rather than
53/// automatically growing.
54#[derive(Clone)]
55pub struct BoxedUint {
56    /// Boxed slice containing limbs.
57    ///
58    /// Stored from least significant to most significant.
59    pub(crate) limbs: Box<[Limb]>,
60}
61
62impl BoxedUint {
63    fn limbs_for_precision(at_least_bits_precision: u32) -> usize {
64        at_least_bits_precision.div_ceil(Limb::BITS) as usize
65    }
66
67    /// Get the value `0` represented as succinctly as possible.
68    #[must_use]
69    pub fn zero() -> Self {
70        Self {
71            limbs: vec![Limb::ZERO; 1].into(),
72        }
73    }
74
75    /// Get the value `0` with the given number of bits of precision.
76    ///
77    /// `at_least_bits_precision` is rounded up to a multiple of [`Limb::BITS`].
78    #[must_use]
79    pub fn zero_with_precision(at_least_bits_precision: u32) -> Self {
80        vec![Limb::ZERO; Self::limbs_for_precision(at_least_bits_precision)].into()
81    }
82
83    /// Get the value `1`, represented as succinctly as possible.
84    #[must_use]
85    pub fn one() -> Self {
86        Self {
87            limbs: vec![Limb::ONE; 1].into(),
88        }
89    }
90
91    /// Get the value `1` with the given number of bits of precision.
92    ///
93    /// `at_least_bits_precision` is rounded up to a multiple of [`Limb::BITS`].
94    #[must_use]
95    pub fn one_with_precision(at_least_bits_precision: u32) -> Self {
96        let mut ret = Self::zero_with_precision(at_least_bits_precision);
97        ret.limbs[0] = Limb::ONE;
98        ret
99    }
100
101    /// Is this [`BoxedUint`] equal to zero?
102    #[must_use]
103    pub fn is_zero(&self) -> Choice {
104        self.limbs
105            .iter()
106            .fold(Choice::TRUE, |acc, limb| acc & limb.is_zero())
107    }
108
109    /// Is this [`BoxedUint`] *NOT* equal to zero?
110    #[inline]
111    #[must_use]
112    pub fn is_nonzero(&self) -> Choice {
113        !self.is_zero()
114    }
115
116    /// Is this [`BoxedUint`] equal to one?
117    #[must_use]
118    pub fn is_one(&self) -> Choice {
119        let mut iter = self.limbs.iter();
120        let choice = iter.next().copied().unwrap_or(Limb::ZERO).ct_eq(&Limb::ONE);
121        iter.fold(choice, |acc, limb| acc & limb.is_zero())
122    }
123
124    /// Get the maximum value for a `BoxedUint` created with `at_least_bits_precision`
125    /// precision bits requested.
126    ///
127    /// That is, returns the value `2^self.bits_precision() - 1`.
128    #[must_use]
129    pub fn max(at_least_bits_precision: u32) -> Self {
130        vec![Limb::MAX; Self::limbs_for_precision(at_least_bits_precision)].into()
131    }
132
133    /// Create a [`BoxedUint`] from an array of [`Word`]s (i.e. word-sized unsigned
134    /// integers).
135    #[inline]
136    pub fn from_words(words: impl IntoIterator<Item = Word>) -> Self {
137        Self {
138            limbs: words.into_iter().map(Into::into).collect(),
139        }
140    }
141
142    /// Create a [`BoxedUint`] from an array of [`Word`]s (i.e. word-sized unsigned
143    /// integers), specifying the precision of the result. Any words above the given
144    /// precision will be dropped.
145    #[inline]
146    pub fn from_words_with_precision(
147        words: impl IntoIterator<Item = Word>,
148        at_least_bits_precision: u32,
149    ) -> Self {
150        let size = Self::limbs_for_precision(at_least_bits_precision);
151        Self {
152            limbs: words
153                .into_iter()
154                .map(Into::into)
155                .chain(repeat(Limb::ZERO))
156                .take(size)
157                .collect(),
158        }
159    }
160
161    /// Create a boxed slice of [`Word`]s (i.e. word-sized unsigned integers) from
162    /// a [`BoxedUint`].
163    #[inline]
164    pub fn to_words(&self) -> Box<[Word]> {
165        self.limbs.iter().copied().map(Into::into).collect()
166    }
167
168    /// Borrow the inner limbs as a slice of [`Word`]s.
169    #[must_use]
170    pub fn as_words(&self) -> &[Word] {
171        self.as_uint_ref().as_words()
172    }
173
174    /// Borrow the inner limbs as a mutable slice of [`Word`]s.
175    pub fn as_mut_words(&mut self) -> &mut [Word] {
176        self.as_mut_uint_ref().as_mut_words()
177    }
178
179    /// Borrow the inner limbs as a mutable slice of [`Word`]s.
180    #[deprecated(since = "0.7.0", note = "please use `as_mut_words` instead")]
181    pub fn as_words_mut(&mut self) -> &mut [Word] {
182        self.as_mut_words()
183    }
184
185    /// Borrow the limbs of this [`BoxedUint`].
186    #[must_use]
187    pub fn as_limbs(&self) -> &[Limb] {
188        self.limbs.as_ref()
189    }
190
191    /// Borrow the limbs of this [`BoxedUint`] mutably.
192    pub fn as_mut_limbs(&mut self) -> &mut [Limb] {
193        self.limbs.as_mut()
194    }
195
196    /// Borrow the limbs of this [`BoxedUint`] mutably.
197    #[deprecated(since = "0.7.0", note = "please use `as_mut_limbs` instead")]
198    pub fn as_limbs_mut(&mut self) -> &mut [Limb] {
199        self.as_mut_limbs()
200    }
201
202    /// Convert this [`BoxedUint`] into its inner limbs.
203    #[must_use]
204    pub fn to_limbs(&self) -> Box<[Limb]> {
205        self.limbs.clone()
206    }
207
208    /// Convert this [`BoxedUint`] into its inner limbs.
209    #[must_use]
210    pub fn into_limbs(self) -> Box<[Limb]> {
211        self.limbs
212    }
213
214    /// Borrow the limbs of this [`BoxedUint`] as a [`UintRef`].
215    #[inline]
216    #[must_use]
217    pub const fn as_uint_ref(&self) -> &UintRef {
218        UintRef::new(&self.limbs)
219    }
220
221    /// Mutably borrow the limbs of this [`BoxedUint`] as a [`UintRef`].
222    #[inline]
223    #[must_use]
224    pub const fn as_mut_uint_ref(&mut self) -> &mut UintRef {
225        UintRef::new_mut(&mut self.limbs)
226    }
227
228    /// Get the number of limbs in this [`BoxedUint`].
229    #[must_use]
230    pub fn nlimbs(&self) -> usize {
231        self.limbs.len()
232    }
233
234    /// Convert to a [`NonZero<BoxedUint>`].
235    ///
236    /// Returns some if the original value is non-zero, and false otherwise.
237    #[must_use]
238    pub fn to_nz(&self) -> CtOption<NonZero<Self>> {
239        self.clone().into_nz()
240    }
241
242    /// Convert to an [`Odd<BoxedUint>`].
243    ///
244    /// Returns some if the original value is odd, and false otherwise.
245    #[must_use]
246    pub fn to_odd(&self) -> CtOption<Odd<Self>> {
247        self.clone().into_odd()
248    }
249
250    /// Convert to a [`NonZero<BoxedUint>`].
251    ///
252    /// Returns some if the original value is non-zero, and false otherwise.
253    #[must_use]
254    pub fn into_nz(mut self) -> CtOption<NonZero<Self>> {
255        let is_nz = self.is_nonzero();
256
257        // Ensure the `NonZero` we construct is actually non-zero, even if the `CtOption` is none
258        self.limbs[0].ct_assign(&Limb::ONE, !is_nz);
259        CtOption::new(NonZero(self), is_nz)
260    }
261
262    /// Convert to an [`Odd<BoxedUint>`].
263    ///
264    /// Returns some if the original value is odd, and false otherwise.
265    #[must_use]
266    pub fn into_odd(mut self) -> CtOption<Odd<Self>> {
267        let is_odd = self.is_odd();
268
269        // Ensure the `Odd` we construct is actually odd, even if the `CtOption` is none
270        self.limbs[0].ct_assign(&Limb::ONE, !is_odd);
271        CtOption::new(Odd(self.clone()), is_odd)
272    }
273
274    /// Widen this type's precision to the given number of bits.
275    ///
276    /// # Panics
277    /// - if `at_least_bits_precision` is smaller than the current precision.
278    #[must_use]
279    #[deprecated(since = "0.7.0", note = "please use `resize` instead")]
280    pub fn widen(&self, at_least_bits_precision: u32) -> BoxedUint {
281        assert!(at_least_bits_precision >= self.bits_precision());
282
283        let mut ret = BoxedUint::zero_with_precision(at_least_bits_precision);
284        ret.limbs[..self.nlimbs()].copy_from_slice(&self.limbs);
285        ret
286    }
287
288    /// Shortens this type's precision to the given number of bits.
289    ///
290    /// # Panics
291    /// - if `at_least_bits_precision` is larger than the current precision.
292    #[must_use]
293    #[deprecated(since = "0.7.0", note = "please use `resize` instead")]
294    pub fn shorten(&self, at_least_bits_precision: u32) -> BoxedUint {
295        assert!(at_least_bits_precision <= self.bits_precision());
296        let mut ret = BoxedUint::zero_with_precision(at_least_bits_precision);
297        let nlimbs = ret.nlimbs();
298        ret.limbs.copy_from_slice(&self.limbs[..nlimbs]);
299        ret
300    }
301
302    /// Iterate over the limbs of the inputs, applying the given function, and
303    /// constructing a result from the returned values.
304    #[inline]
305    fn map_limbs<F>(lhs: &Self, rhs: &Self, f: F) -> Self
306    where
307        F: Fn(Limb, Limb) -> Limb,
308    {
309        let nlimbs = cmp::max(lhs.nlimbs(), rhs.nlimbs());
310        let mut limbs = Vec::with_capacity(nlimbs);
311
312        for i in 0..nlimbs {
313            let &a = lhs.limbs.get(i).unwrap_or(&Limb::ZERO);
314            let &b = rhs.limbs.get(i).unwrap_or(&Limb::ZERO);
315            limbs.push(f(a, b));
316        }
317
318        limbs.into()
319    }
320
321    /// Returns `true` if the integer's bit size is smaller or equal to `bits`.
322    pub(crate) fn is_within_bits(&self, bits: u32) -> bool {
323        bits >= self.bits_precision() || bits >= self.bits()
324    }
325}
326
327impl Resize for BoxedUint {
328    type Output = BoxedUint;
329
330    fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output {
331        let new_len = Self::limbs_for_precision(at_least_bits_precision);
332        if new_len == self.limbs.len() {
333            self
334        } else {
335            let mut limbs = self.limbs.into_vec();
336            limbs.resize(new_len, Limb::ZERO);
337            Self::from(limbs)
338        }
339    }
340
341    fn try_resize(self, at_least_bits_precision: u32) -> Option<BoxedUint> {
342        if self.is_within_bits(at_least_bits_precision) {
343            Some(self.resize_unchecked(at_least_bits_precision))
344        } else {
345            None
346        }
347    }
348}
349
350impl Resize for &BoxedUint {
351    type Output = BoxedUint;
352
353    fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output {
354        let mut ret = BoxedUint::zero_with_precision(at_least_bits_precision);
355        let num_limbs_to_copy = core::cmp::min(ret.limbs.len(), self.limbs.len());
356        ret.limbs[..num_limbs_to_copy].copy_from_slice(&self.limbs[..num_limbs_to_copy]);
357        ret
358    }
359
360    fn try_resize(self, at_least_bits_precision: u32) -> Option<BoxedUint> {
361        if self.is_within_bits(at_least_bits_precision) {
362            Some(self.resize_unchecked(at_least_bits_precision))
363        } else {
364            None
365        }
366    }
367}
368
369impl Resize for NonZero<BoxedUint> {
370    type Output = Self;
371
372    fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output {
373        NonZero(self.0.resize_unchecked(at_least_bits_precision))
374    }
375
376    fn try_resize(self, at_least_bits_precision: u32) -> Option<Self::Output> {
377        self.0.try_resize(at_least_bits_precision).map(NonZero)
378    }
379}
380
381impl Resize for &NonZero<BoxedUint> {
382    type Output = NonZero<BoxedUint>;
383
384    fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output {
385        NonZero((&self.0).resize_unchecked(at_least_bits_precision))
386    }
387
388    fn try_resize(self, at_least_bits_precision: u32) -> Option<Self::Output> {
389        (&self.0).try_resize(at_least_bits_precision).map(NonZero)
390    }
391}
392
393impl AsRef<[Word]> for BoxedUint {
394    fn as_ref(&self) -> &[Word] {
395        self.as_words()
396    }
397}
398
399impl AsMut<[Word]> for BoxedUint {
400    fn as_mut(&mut self) -> &mut [Word] {
401        self.as_mut_words()
402    }
403}
404
405impl AsRef<[Limb]> for BoxedUint {
406    fn as_ref(&self) -> &[Limb] {
407        self.as_limbs()
408    }
409}
410
411impl AsMut<[Limb]> for BoxedUint {
412    fn as_mut(&mut self) -> &mut [Limb] {
413        self.as_mut_limbs()
414    }
415}
416
417impl AsRef<UintRef> for BoxedUint {
418    fn as_ref(&self) -> &UintRef {
419        self.as_uint_ref()
420    }
421}
422
423impl AsMut<UintRef> for BoxedUint {
424    fn as_mut(&mut self) -> &mut UintRef {
425        self.as_mut_uint_ref()
426    }
427}
428
429impl Borrow<UintRef> for BoxedUint {
430    fn borrow(&self) -> &UintRef {
431        self.as_uint_ref()
432    }
433}
434
435impl BorrowMut<UintRef> for BoxedUint {
436    fn borrow_mut(&mut self) -> &mut UintRef {
437        self.as_mut_uint_ref()
438    }
439}
440
441impl Default for BoxedUint {
442    fn default() -> Self {
443        Self::zero()
444    }
445}
446
447impl Integer for BoxedUint {
448    fn as_limbs(&self) -> &[Limb] {
449        &self.limbs
450    }
451
452    fn as_mut_limbs(&mut self) -> &mut [Limb] {
453        &mut self.limbs
454    }
455
456    fn nlimbs(&self) -> usize {
457        self.nlimbs()
458    }
459}
460
461impl Unsigned for BoxedUint {
462    fn as_uint_ref(&self) -> &UintRef {
463        self.as_uint_ref()
464    }
465
466    fn as_mut_uint_ref(&mut self) -> &mut UintRef {
467        self.as_mut_uint_ref()
468    }
469
470    fn from_limb_like(limb: Limb, other: &Self) -> Self {
471        let mut ret = Self::zero_with_precision(other.bits_precision());
472        ret.limbs[0] = limb;
473        ret
474    }
475}
476
477impl UnsignedWithMontyForm for BoxedUint {
478    type MontyForm = BoxedMontyForm;
479}
480
481impl Zero for BoxedUint {
482    fn zero() -> Self {
483        Self::zero()
484    }
485
486    fn is_zero(&self) -> Choice {
487        self.is_zero()
488    }
489
490    fn set_zero(&mut self) {
491        self.limbs.as_mut().fill(Limb::ZERO);
492    }
493}
494
495impl One for BoxedUint {
496    fn one() -> Self {
497        Self::one()
498    }
499
500    fn one_like(other: &Self) -> Self {
501        let mut ret = other.clone();
502        ret.set_one();
503        ret
504    }
505
506    fn is_one(&self) -> Choice {
507        self.is_one()
508    }
509
510    fn set_one(&mut self) {
511        self.limbs.as_mut().fill(Limb::ZERO);
512        self.limbs[0] = Limb::ONE;
513    }
514}
515
516impl num_traits::Zero for BoxedUint {
517    fn zero() -> Self {
518        Self::zero()
519    }
520
521    fn is_zero(&self) -> bool {
522        self.is_zero().into()
523    }
524
525    fn set_zero(&mut self) {
526        Zero::set_zero(self);
527    }
528}
529
530impl num_traits::One for BoxedUint {
531    fn one() -> Self {
532        Self::one()
533    }
534
535    fn is_one(&self) -> bool {
536        self.is_one().into()
537    }
538
539    fn set_one(&mut self) {
540        One::set_one(self);
541    }
542}
543
544#[cfg(feature = "zeroize")]
545impl Zeroize for BoxedUint {
546    fn zeroize(&mut self) {
547        self.limbs.zeroize();
548    }
549}
550
551impl fmt::Debug for BoxedUint {
552    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553        write!(f, "BoxedUint(0x{:X})", self.as_uint_ref())
554    }
555}
556
557impl fmt::Display for BoxedUint {
558    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
559        fmt::UpperHex::fmt(self, f)
560    }
561}
562
563impl fmt::Binary for BoxedUint {
564    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
565        fmt::Binary::fmt(self.as_uint_ref(), f)
566    }
567}
568
569impl fmt::LowerHex for BoxedUint {
570    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
571        fmt::LowerHex::fmt(self.as_uint_ref(), f)
572    }
573}
574
575impl fmt::UpperHex for BoxedUint {
576    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
577        fmt::UpperHex::fmt(self.as_uint_ref(), f)
578    }
579}
580
581#[cfg(test)]
582mod tests {
583    use super::BoxedUint;
584    use crate::Word;
585    use alloc::vec::Vec;
586
587    #[test]
588    fn from_word_vec() {
589        let words: &[Word] = &[0, 1, 2, 3];
590        let uint = BoxedUint::from(Vec::from(words));
591        assert_eq!(uint.nlimbs(), 4);
592        assert_eq!(uint.as_words(), words);
593    }
594
595    #[test]
596    fn fmt_lower_hex() {
597        let n = BoxedUint::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD", 128).unwrap();
598        assert_eq!(format!("{n:x}"), "aaaaaaaabbbbbbbbccccccccdddddddd");
599        assert_eq!(format!("{n:#x}"), "0xaaaaaaaabbbbbbbbccccccccdddddddd");
600    }
601
602    #[test]
603    fn fmt_upper_hex() {
604        let n = BoxedUint::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd", 128).unwrap();
605        assert_eq!(format!("{n:X}"), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
606        assert_eq!(format!("{n:#X}"), "0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
607    }
608
609    #[test]
610    fn fmt_binary() {
611        let n = BoxedUint::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd", 128).unwrap();
612        assert_eq!(
613            format!("{n:b}"),
614            "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
615        );
616        assert_eq!(
617            format!("{n:#b}"),
618            "0b10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
619        );
620    }
621
622    #[test]
623    fn test_unsigned() {
624        crate::traits::tests::test_unsigned(
625            BoxedUint::zero_with_precision(128),
626            BoxedUint::max(128),
627        );
628    }
629}