Skip to main content

crypto_bigint/
int.rs

1//! Stack-allocated big signed integers.
2
3use crate::{
4    Bounded, Choice, ConstOne, ConstZero, Constants, CtEq, CtOption, FixedInteger, Integer, Limb,
5    NonZero, Odd, One, Signed, Uint, Word, Zero,
6};
7use core::fmt;
8
9#[cfg(feature = "serde")]
10use crate::Encoding;
11#[cfg(feature = "serde")]
12use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer};
13
14mod add;
15mod bit_and;
16mod bit_not;
17mod bit_or;
18mod bit_xor;
19mod cmp;
20mod ct;
21mod div;
22mod div_unsigned;
23mod encoding;
24mod from;
25mod gcd;
26mod invert_mod;
27mod mod_symbol;
28mod mul;
29mod mul_unsigned;
30mod neg;
31mod resize;
32mod shl;
33mod shr;
34mod sign;
35mod sqrt;
36mod sub;
37pub(crate) mod types;
38
39#[cfg(feature = "rand_core")]
40mod rand;
41
42/// Stack-allocated big _signed_ integer.
43/// See [`Uint`] for _unsigned_ integers.
44///
45/// Created as a [`Uint`] newtype.
46#[allow(clippy::derived_hash_with_manual_eq)]
47#[derive(Copy, Clone, Hash)]
48#[repr(transparent)]
49pub struct Int<const LIMBS: usize>(Uint<LIMBS>);
50
51impl<const LIMBS: usize> Int<LIMBS> {
52    /// The value `0`.
53    pub const ZERO: Self = Self(Uint::ZERO); // Bit sequence (be): 0000....0000
54
55    /// The value `1`.
56    pub const ONE: Self = Self(Uint::ONE); // Bit sequence (be): 0000....0001
57
58    /// The value `-1`
59    pub const MINUS_ONE: Self = Self(Uint::MAX); // Bit sequence (be): 1111....1111
60
61    /// Smallest value this [`Int`] can express.
62    pub const MIN: Self = Self::MAX.not(); // Bit sequence (be): 1000....0000
63
64    /// Maximum value this [`Int`] can express.
65    pub const MAX: Self = Self(Uint::MAX.shr_vartime(1u32)); // Bit sequence (be): 0111....1111
66
67    /// Bit mask for the sign bit of this [`Int`].
68    pub const SIGN_MASK: Self = Self::MIN; // Bit sequence (be): 1000....0000
69
70    /// Total size of the represented integer in bits.
71    pub const BITS: u32 = Uint::<LIMBS>::BITS;
72
73    /// Total size of the represented integer in bytes.
74    pub const BYTES: usize = Uint::<LIMBS>::BYTES;
75
76    /// The number of limbs used on this platform.
77    pub const LIMBS: usize = LIMBS;
78
79    /// Const-friendly [`Int`] constructor.
80    #[must_use]
81    pub const fn new(limbs: [Limb; LIMBS]) -> Self {
82        Self(Uint::new(limbs))
83    }
84
85    /// Const-friendly [`Int`] constructor.
86    ///
87    /// Reinterprets the bits of a value of type [`Uint`] as an [`Int`].
88    /// For a proper conversion, see [`Int::new_from_abs_sign`];
89    /// the public interface of this function is available at [`Uint::as_int`].
90    pub(crate) const fn from_bits(value: Uint<LIMBS>) -> Self {
91        Self(value)
92    }
93
94    /// Create an [`Int`] from an array of [`Word`]s (i.e. word-sized unsigned
95    /// integers).
96    #[inline]
97    #[must_use]
98    pub const fn from_words(arr: [Word; LIMBS]) -> Self {
99        Self(Uint::from_words(arr))
100    }
101
102    /// Create an array of [`Word`]s (i.e. word-sized unsigned integers) from
103    /// an [`Int`].
104    #[inline]
105    #[must_use]
106    pub const fn to_words(self) -> [Word; LIMBS] {
107        self.0.to_words()
108    }
109
110    /// Borrow the inner limbs as an array of [`Word`]s.
111    #[must_use]
112    pub const fn as_words(&self) -> &[Word; LIMBS] {
113        self.0.as_words()
114    }
115
116    /// Borrow the inner limbs as a mutable array of [`Word`]s.
117    pub const fn as_mut_words(&mut self) -> &mut [Word; LIMBS] {
118        self.0.as_mut_words()
119    }
120
121    /// Borrow the inner limbs as a mutable slice of [`Word`]s.
122    #[deprecated(since = "0.7.0", note = "please use `as_mut_words` instead")]
123    pub fn as_words_mut(&mut self) -> &mut [Word] {
124        self.as_mut_words()
125    }
126
127    /// Borrow the limbs of this [`Int`].
128    #[must_use]
129    pub const fn as_limbs(&self) -> &[Limb; LIMBS] {
130        self.0.as_limbs()
131    }
132
133    /// Borrow the limbs of this [`Int`] mutably.
134    pub const fn as_mut_limbs(&mut self) -> &mut [Limb; LIMBS] {
135        self.0.as_mut_limbs()
136    }
137
138    /// Borrow the limbs of this [`Int`] mutably.
139    #[deprecated(since = "0.7.0", note = "please use `as_mut_limbs` instead")]
140    pub const fn as_limbs_mut(&mut self) -> &mut [Limb] {
141        self.as_mut_limbs()
142    }
143
144    /// Convert this [`Int`] into its inner limbs.
145    #[must_use]
146    pub const fn to_limbs(self) -> [Limb; LIMBS] {
147        self.0.to_limbs()
148    }
149
150    /// Convert to a [`NonZero<Int<LIMBS>>`].
151    ///
152    /// Returns some if the original value is non-zero, and false otherwise.
153    #[must_use]
154    pub const fn to_nz(self) -> CtOption<NonZero<Self>> {
155        CtOption::new(NonZero(self), self.0.is_nonzero())
156    }
157
158    /// Convert to a [`Odd<Int<LIMBS>>`].
159    ///
160    /// Returns some if the original value is odd, and false otherwise.
161    #[must_use]
162    pub const fn to_odd(self) -> CtOption<Odd<Self>> {
163        CtOption::new(Odd(self), self.0.is_odd())
164    }
165
166    /// Interpret the data in this object as a [`Uint`] instead.
167    ///
168    /// Note: this is a casting operation. See
169    /// - [`Self::try_into_uint`] for the checked equivalent, and
170    /// - [`Self::abs`] to obtain the absolute value of `self`.
171    #[must_use]
172    pub const fn as_uint(&self) -> &Uint<LIMBS> {
173        &self.0
174    }
175
176    /// Get a [`Uint`] equivalent of this value; returns `None` if `self` is negative.
177    ///
178    /// Note: this is a checked conversion operation. See
179    /// - [`Self::as_uint`] for the unchecked equivalent, and
180    /// - [`Self::abs`] to obtain the absolute value of `self`.
181    #[must_use]
182    pub const fn try_into_uint(self) -> CtOption<Uint<LIMBS>> {
183        CtOption::new(self.0, self.is_negative().not())
184    }
185
186    /// Whether this [`Int`] is equal to `Self::MIN`.
187    #[must_use]
188    pub const fn is_min(&self) -> Choice {
189        Self::eq(self, &Self::MIN)
190    }
191
192    /// Whether this [`Int`] is equal to `Self::MAX`.
193    #[must_use]
194    pub const fn is_max(&self) -> Choice {
195        Self::eq(self, &Self::MAX)
196    }
197
198    /// Is this [`Int`] equal to zero?
199    #[must_use]
200    pub const fn is_zero(&self) -> Choice {
201        self.0.is_zero()
202    }
203
204    /// Invert the most significant bit (msb) of this [`Int`]
205    const fn invert_msb(&self) -> Self {
206        Self(self.0.bitxor(&Self::SIGN_MASK.0))
207    }
208}
209
210impl<const LIMBS: usize> AsRef<[Word; LIMBS]> for Int<LIMBS> {
211    fn as_ref(&self) -> &[Word; LIMBS] {
212        self.as_words()
213    }
214}
215
216impl<const LIMBS: usize> AsMut<[Word; LIMBS]> for Int<LIMBS> {
217    fn as_mut(&mut self) -> &mut [Word; LIMBS] {
218        self.as_mut_words()
219    }
220}
221
222impl<const LIMBS: usize> AsRef<[Limb]> for Int<LIMBS> {
223    fn as_ref(&self) -> &[Limb] {
224        self.as_limbs()
225    }
226}
227
228impl<const LIMBS: usize> AsMut<[Limb]> for Int<LIMBS> {
229    fn as_mut(&mut self) -> &mut [Limb] {
230        self.as_mut_limbs()
231    }
232}
233
234impl<const LIMBS: usize> Bounded for Int<LIMBS> {
235    const BITS: u32 = Self::BITS;
236    const BYTES: usize = Self::BYTES;
237}
238
239impl<const LIMBS: usize> Constants for Int<LIMBS> {
240    const MAX: Self = Self::MAX;
241}
242
243impl<const LIMBS: usize> Default for Int<LIMBS> {
244    fn default() -> Self {
245        Self::ZERO
246    }
247}
248
249impl<const LIMBS: usize> FixedInteger for Int<LIMBS> {
250    const LIMBS: usize = LIMBS;
251}
252
253impl<const LIMBS: usize> Integer for Int<LIMBS> {
254    fn as_limbs(&self) -> &[Limb] {
255        self.0.as_limbs()
256    }
257
258    fn as_mut_limbs(&mut self) -> &mut [Limb] {
259        self.0.as_mut_limbs()
260    }
261
262    fn nlimbs(&self) -> usize {
263        self.0.nlimbs()
264    }
265}
266
267impl<const LIMBS: usize> Signed for Int<LIMBS> {
268    type Unsigned = Uint<LIMBS>;
269
270    fn abs_sign(&self) -> (Uint<LIMBS>, Choice) {
271        self.abs_sign()
272    }
273
274    fn is_negative(&self) -> Choice {
275        self.is_negative()
276    }
277
278    fn is_positive(&self) -> Choice {
279        self.is_positive()
280    }
281}
282
283impl<const LIMBS: usize> ConstZero for Int<LIMBS> {
284    const ZERO: Self = Self::ZERO;
285}
286
287impl<const LIMBS: usize> ConstOne for Int<LIMBS> {
288    const ONE: Self = Self::ONE;
289}
290
291impl<const LIMBS: usize> Zero for Int<LIMBS> {
292    #[inline(always)]
293    fn zero() -> Self {
294        Self::ZERO
295    }
296}
297
298impl<const LIMBS: usize> One for Int<LIMBS> {
299    #[inline(always)]
300    fn one() -> Self {
301        Self::ONE
302    }
303}
304
305impl<const LIMBS: usize> num_traits::Zero for Int<LIMBS> {
306    #[inline(always)]
307    fn zero() -> Self {
308        Self::ZERO
309    }
310
311    fn is_zero(&self) -> bool {
312        self.0.ct_eq(&Self::ZERO.0).into()
313    }
314}
315
316impl<const LIMBS: usize> num_traits::One for Int<LIMBS> {
317    #[inline(always)]
318    fn one() -> Self {
319        Self::ONE
320    }
321
322    fn is_one(&self) -> bool {
323        self.0.ct_eq(&Self::ONE.0).into()
324    }
325}
326
327impl<const LIMBS: usize> fmt::Debug for Int<LIMBS> {
328    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
329        write!(f, "Int(0x{self:X})")
330    }
331}
332
333impl<const LIMBS: usize> fmt::Binary for Int<LIMBS> {
334    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335        fmt::Binary::fmt(&self.0, f)
336    }
337}
338
339impl<const LIMBS: usize> fmt::Display for Int<LIMBS> {
340    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341        fmt::UpperHex::fmt(self, f)
342    }
343}
344
345impl<const LIMBS: usize> fmt::LowerHex for Int<LIMBS> {
346    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347        fmt::LowerHex::fmt(&self.0, f)
348    }
349}
350
351impl<const LIMBS: usize> fmt::UpperHex for Int<LIMBS> {
352    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353        fmt::UpperHex::fmt(&self.0, f)
354    }
355}
356
357#[cfg(feature = "serde")]
358impl<'de, const LIMBS: usize> Deserialize<'de> for Int<LIMBS>
359where
360    Int<LIMBS>: Encoding,
361{
362    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
363    where
364        D: Deserializer<'de>,
365    {
366        let mut buffer = Self::ZERO.to_le_bytes();
367        serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
368        Ok(Self::from_le_bytes(buffer))
369    }
370}
371
372#[cfg(feature = "serde")]
373impl<const LIMBS: usize> Serialize for Int<LIMBS>
374where
375    Int<LIMBS>: Encoding,
376{
377    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
378    where
379        S: Serializer,
380    {
381        serdect::array::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
382    }
383}
384
385#[cfg(test)]
386#[allow(clippy::unwrap_used)]
387mod tests {
388    use crate::{I128, U128};
389
390    cpubits::cpubits! {
391        64 => {
392            #[test]
393            fn as_words() {
394                let n = I128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
395                assert_eq!(n.as_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
396            }
397
398            #[test]
399            fn as_words_mut() {
400                let mut n = I128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
401                assert_eq!(n.as_mut_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
402            }
403        }
404    }
405
406    #[cfg(feature = "alloc")]
407    #[test]
408    fn debug() {
409        let n = I128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
410
411        assert_eq!(format!("{n:?}"), "Int(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)");
412    }
413
414    #[cfg(feature = "alloc")]
415    #[test]
416    fn display() {
417        let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
418        let n = I128::from_be_hex(hex);
419
420        use alloc::string::ToString;
421        assert_eq!(hex, n.to_string());
422
423        let hex = "AAAAAAAABBBBBBBB0000000000000000";
424        let n = I128::from_be_hex(hex);
425        assert_eq!(hex, n.to_string());
426
427        let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
428        let n = I128::from_be_hex(hex);
429        assert_eq!(hex, n.to_string());
430
431        let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
432        let n = I128::from_be_hex(hex);
433        assert_eq!(hex, n.to_string());
434    }
435
436    #[cfg(feature = "alloc")]
437    #[test]
438    fn fmt_lower_hex() {
439        let n = I128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
440        assert_eq!(format!("{n:x}"), "aaaaaaaabbbbbbbbccccccccdddddddd");
441        assert_eq!(format!("{n:#x}"), "0xaaaaaaaabbbbbbbbccccccccdddddddd");
442    }
443
444    #[cfg(feature = "alloc")]
445    #[test]
446    fn fmt_upper_hex() {
447        let n = I128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
448        assert_eq!(format!("{n:X}"), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
449        assert_eq!(format!("{n:#X}"), "0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
450    }
451
452    #[cfg(feature = "alloc")]
453    #[test]
454    fn fmt_binary() {
455        let n = I128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
456        assert_eq!(
457            format!("{n:b}"),
458            "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
459        );
460        assert_eq!(
461            format!("{n:#b}"),
462            "0b10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
463        );
464    }
465
466    #[test]
467    fn is_minimal() {
468        let min = I128::from_be_hex("80000000000000000000000000000000");
469        assert!(min.is_min().to_bool());
470
471        let random = I128::from_be_hex("11113333555577779999BBBBDDDDFFFF");
472        assert!(!random.is_min().to_bool());
473    }
474
475    #[test]
476    fn is_maximal() {
477        let max = I128::from_be_hex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
478        assert!(max.is_max().to_bool());
479
480        let random = I128::from_be_hex("11113333555577779999BBBBDDDDFFFF");
481        assert!(!random.is_max().to_bool());
482    }
483
484    #[test]
485    fn as_uint() {
486        assert_eq!(*I128::MIN.as_uint(), U128::ONE << 127);
487        assert_eq!(*I128::MINUS_ONE.as_uint(), U128::MAX);
488        assert_eq!(*I128::ZERO.as_uint(), U128::ZERO);
489        assert_eq!(*I128::ONE.as_uint(), U128::ONE);
490        assert_eq!(*I128::MAX.as_uint(), U128::MAX >> 1);
491    }
492
493    #[test]
494    fn to_uint() {
495        assert!(bool::from(I128::MIN.try_into_uint().is_none()));
496        assert!(bool::from(I128::MINUS_ONE.try_into_uint().is_none()));
497        assert_eq!(I128::ZERO.try_into_uint().unwrap(), U128::ZERO);
498        assert_eq!(I128::ONE.try_into_uint().unwrap(), U128::ONE);
499        assert_eq!(I128::MAX.try_into_uint().unwrap(), U128::MAX >> 1);
500    }
501
502    #[test]
503    fn test_signed() {
504        crate::traits::tests::test_signed(I128::MIN, I128::MAX);
505    }
506}