crypto_bigint/
int.rs

1//! Stack-allocated big signed integers.
2
3use core::fmt;
4
5use num_traits::ConstZero;
6#[cfg(feature = "serde")]
7use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer};
8use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
9
10#[cfg(feature = "serde")]
11use crate::Encoding;
12use crate::{Bounded, ConstChoice, ConstCtOption, Constants, Limb, NonZero, Odd, Uint, Word};
13
14mod add;
15mod bit_and;
16mod bit_not;
17mod bit_or;
18mod bit_xor;
19mod cmp;
20mod div;
21mod div_uint;
22mod encoding;
23mod from;
24mod gcd;
25mod inv_mod;
26mod mul;
27mod mul_uint;
28mod neg;
29mod resize;
30mod shl;
31mod shr;
32mod sign;
33mod sub;
34pub(crate) mod types;
35
36#[cfg(feature = "rand_core")]
37mod rand;
38
39/// Stack-allocated big _signed_ integer.
40/// See [`Uint`] for _unsigned_ integers.
41///
42/// Created as a [`Uint`] newtype.
43#[allow(clippy::derived_hash_with_manual_eq)]
44#[derive(Copy, Clone, Hash)]
45pub struct Int<const LIMBS: usize>(Uint<LIMBS>);
46
47impl<const LIMBS: usize> Int<LIMBS> {
48    /// The value `0`.
49    pub const ZERO: Self = Self(Uint::ZERO); // Bit sequence (be): 0000....0000
50
51    /// The value `1`.
52    pub const ONE: Self = Self(Uint::ONE); // Bit sequence (be): 0000....0001
53
54    /// The value `-1`
55    pub const MINUS_ONE: Self = Self::FULL_MASK; // Bit sequence (be): 1111....1111
56
57    /// Smallest value this [`Int`] can express.
58    pub const MIN: Self = Self(Uint::MAX.bitxor(&Uint::MAX.shr(1u32))); // Bit sequence (be): 1000....0000
59
60    /// Maximum value this [`Int`] can express.
61    pub const MAX: Self = Self(Uint::MAX.shr(1u32)); // Bit sequence (be): 0111....1111
62
63    /// Bit mask for the sign bit of this [`Int`].
64    pub const SIGN_MASK: Self = Self::MIN; // Bit sequence (be): 1000....0000
65
66    /// All-one bit mask.
67    pub const FULL_MASK: Self = Self(Uint::MAX); // Bit sequence (be): 1111...1111
68
69    /// Total size of the represented integer in bits.
70    pub const BITS: u32 = Uint::<LIMBS>::BITS;
71
72    /// Total size of the represented integer in bytes.
73    pub const BYTES: usize = Uint::<LIMBS>::BYTES;
74
75    /// The number of limbs used on this platform.
76    pub const LIMBS: usize = LIMBS;
77
78    /// Const-friendly [`Int`] constructor.
79    pub const fn new(limbs: [Limb; LIMBS]) -> Self {
80        Self(Uint::new(limbs))
81    }
82
83    /// Const-friendly [`Int`] constructor.
84    ///
85    /// Reinterprets the bits of a value of type [`Uint`] as an [`Int`].
86    /// For a proper conversion, see [`Int::new_from_abs_sign`];
87    /// the public interface of this function is available at [`Uint::as_int`].
88    pub(crate) const fn from_bits(value: Uint<LIMBS>) -> Self {
89        Self(value)
90    }
91
92    /// Create an [`Int`] from an array of [`Word`]s (i.e. word-sized unsigned
93    /// integers).
94    #[inline]
95    pub const fn from_words(arr: [Word; LIMBS]) -> Self {
96        Self(Uint::from_words(arr))
97    }
98
99    /// Create an array of [`Word`]s (i.e. word-sized unsigned integers) from
100    /// an [`Int`].
101    #[inline]
102    pub const fn to_words(self) -> [Word; LIMBS] {
103        self.0.to_words()
104    }
105
106    /// Borrow the inner limbs as an array of [`Word`]s.
107    pub const fn as_words(&self) -> &[Word; LIMBS] {
108        self.0.as_words()
109    }
110
111    /// Borrow the inner limbs as a mutable array of [`Word`]s.
112    pub fn as_words_mut(&mut self) -> &mut [Word; LIMBS] {
113        self.0.as_words_mut()
114    }
115
116    /// Borrow the limbs of this [`Int`].
117    pub const fn as_limbs(&self) -> &[Limb; LIMBS] {
118        self.0.as_limbs()
119    }
120
121    /// Borrow the limbs of this [`Int`] mutably.
122    pub const fn as_limbs_mut(&mut self) -> &mut [Limb; LIMBS] {
123        self.0.as_limbs_mut()
124    }
125
126    /// Convert this [`Int`] into its inner limbs.
127    pub const fn to_limbs(self) -> [Limb; LIMBS] {
128        self.0.to_limbs()
129    }
130
131    /// Convert to a [`NonZero<Int<LIMBS>>`].
132    ///
133    /// Returns some if the original value is non-zero, and false otherwise.
134    pub const fn to_nz(self) -> ConstCtOption<NonZero<Self>> {
135        ConstCtOption::new(NonZero(self), self.0.is_nonzero())
136    }
137
138    /// Convert to a [`Odd<Int<LIMBS>>`].
139    ///
140    /// Returns some if the original value is odd, and false otherwise.
141    pub const fn to_odd(self) -> ConstCtOption<Odd<Self>> {
142        ConstCtOption::new(Odd(self), self.0.is_odd())
143    }
144
145    /// Interpret the data in this type as a [`Uint`] instead.
146    pub const fn as_uint(&self) -> &Uint<LIMBS> {
147        &self.0
148    }
149
150    /// Whether this [`Int`] is equal to `Self::MIN`.
151    pub const fn is_min(&self) -> ConstChoice {
152        Self::eq(self, &Self::MIN)
153    }
154
155    /// Whether this [`Int`] is equal to `Self::MAX`.
156    pub fn is_max(&self) -> ConstChoice {
157        Self::eq(self, &Self::MAX)
158    }
159
160    /// Invert the most significant bit (msb) of this [`Int`]
161    const fn invert_msb(&self) -> Self {
162        Self(self.0.bitxor(&Self::SIGN_MASK.0))
163    }
164}
165
166impl<const LIMBS: usize> AsRef<[Word; LIMBS]> for Int<LIMBS> {
167    fn as_ref(&self) -> &[Word; LIMBS] {
168        self.as_words()
169    }
170}
171
172impl<const LIMBS: usize> AsMut<[Word; LIMBS]> for Int<LIMBS> {
173    fn as_mut(&mut self) -> &mut [Word; LIMBS] {
174        self.as_words_mut()
175    }
176}
177
178impl<const LIMBS: usize> AsRef<[Limb]> for Int<LIMBS> {
179    fn as_ref(&self) -> &[Limb] {
180        self.as_limbs()
181    }
182}
183
184impl<const LIMBS: usize> AsMut<[Limb]> for Int<LIMBS> {
185    fn as_mut(&mut self) -> &mut [Limb] {
186        self.as_limbs_mut()
187    }
188}
189
190impl<const LIMBS: usize> ConditionallySelectable for Int<LIMBS> {
191    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
192        Self(Uint::conditional_select(&a.0, &b.0, choice))
193    }
194}
195
196impl<const LIMBS: usize> Bounded for Int<LIMBS> {
197    const BITS: u32 = Self::BITS;
198    const BYTES: usize = Self::BYTES;
199}
200
201impl<const LIMBS: usize> Constants for Int<LIMBS> {
202    const ONE: Self = Self::ONE;
203    const MAX: Self = Self::MAX;
204}
205
206impl<const LIMBS: usize> Default for Int<LIMBS> {
207    fn default() -> Self {
208        Self::ZERO
209    }
210}
211
212// TODO: impl FixedInteger
213
214// TODO: impl Integer
215
216impl<const LIMBS: usize> ConstZero for Int<LIMBS> {
217    const ZERO: Self = Self::ZERO;
218}
219
220impl<const LIMBS: usize> num_traits::Zero for Int<LIMBS> {
221    fn zero() -> Self {
222        Self::ZERO
223    }
224
225    fn is_zero(&self) -> bool {
226        self.0.ct_eq(&Self::ZERO.0).into()
227    }
228}
229
230impl<const LIMBS: usize> num_traits::One for Int<LIMBS> {
231    fn one() -> Self {
232        Self::ONE
233    }
234
235    fn is_one(&self) -> bool {
236        self.0.ct_eq(&Self::ONE.0).into()
237    }
238}
239
240impl<const LIMBS: usize> fmt::Debug for Int<LIMBS> {
241    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242        write!(f, "Int(0x{self:X})")
243    }
244}
245
246impl<const LIMBS: usize> fmt::Binary for Int<LIMBS> {
247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248        fmt::Binary::fmt(&self.0, f)
249    }
250}
251
252impl<const LIMBS: usize> fmt::Display for Int<LIMBS> {
253    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254        fmt::UpperHex::fmt(self, f)
255    }
256}
257
258impl<const LIMBS: usize> fmt::LowerHex for Int<LIMBS> {
259    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260        fmt::LowerHex::fmt(&self.0, f)
261    }
262}
263
264impl<const LIMBS: usize> fmt::UpperHex for Int<LIMBS> {
265    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266        fmt::UpperHex::fmt(&self.0, f)
267    }
268}
269
270#[cfg(feature = "serde")]
271impl<'de, const LIMBS: usize> Deserialize<'de> for Int<LIMBS>
272where
273    Int<LIMBS>: Encoding,
274{
275    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
276    where
277        D: Deserializer<'de>,
278    {
279        let mut buffer = Self::ZERO.to_le_bytes();
280        serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
281        Ok(Self::from_le_bytes(buffer))
282    }
283}
284
285#[cfg(feature = "serde")]
286impl<const LIMBS: usize> Serialize for Int<LIMBS>
287where
288    Int<LIMBS>: Encoding,
289{
290    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
291    where
292        S: Serializer,
293    {
294        serdect::array::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
295    }
296}
297
298#[cfg(test)]
299#[allow(clippy::unwrap_used)]
300mod tests {
301    use subtle::ConditionallySelectable;
302
303    use crate::{ConstChoice, I128, U128};
304
305    #[cfg(target_pointer_width = "64")]
306    #[test]
307    fn as_words() {
308        let n = I128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
309        assert_eq!(n.as_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
310    }
311
312    #[cfg(target_pointer_width = "64")]
313    #[test]
314    fn as_words_mut() {
315        let mut n = I128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
316        assert_eq!(n.as_words_mut(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
317    }
318
319    #[cfg(feature = "alloc")]
320    #[test]
321    fn debug() {
322        let n = I128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
323
324        assert_eq!(
325            format!("{:?}", n),
326            "Int(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)"
327        );
328    }
329
330    #[cfg(feature = "alloc")]
331    #[test]
332    fn display() {
333        let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
334        let n = I128::from_be_hex(hex);
335
336        use alloc::string::ToString;
337        assert_eq!(hex, n.to_string());
338
339        let hex = "AAAAAAAABBBBBBBB0000000000000000";
340        let n = I128::from_be_hex(hex);
341        assert_eq!(hex, n.to_string());
342
343        let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
344        let n = I128::from_be_hex(hex);
345        assert_eq!(hex, n.to_string());
346
347        let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
348        let n = I128::from_be_hex(hex);
349        assert_eq!(hex, n.to_string());
350    }
351
352    #[test]
353    fn conditional_select() {
354        let a = I128::from_be_hex("00002222444466668888AAAACCCCEEEE");
355        let b = I128::from_be_hex("11113333555577779999BBBBDDDDFFFF");
356
357        let select_0 = I128::conditional_select(&a, &b, 0.into());
358        assert_eq!(a, select_0);
359
360        let select_1 = I128::conditional_select(&a, &b, 1.into());
361        assert_eq!(b, select_1);
362    }
363
364    #[test]
365    fn is_minimal() {
366        let min = I128::from_be_hex("80000000000000000000000000000000");
367        assert_eq!(min.is_min(), ConstChoice::TRUE);
368
369        let random = I128::from_be_hex("11113333555577779999BBBBDDDDFFFF");
370        assert_eq!(random.is_min(), ConstChoice::FALSE);
371    }
372
373    #[test]
374    fn is_maximal() {
375        let max = I128::from_be_hex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
376        assert_eq!(max.is_max(), ConstChoice::TRUE);
377
378        let random = I128::from_be_hex("11113333555577779999BBBBDDDDFFFF");
379        assert_eq!(random.is_max(), ConstChoice::FALSE);
380    }
381
382    #[test]
383    fn as_uint() {
384        assert_eq!(*I128::MIN.as_uint(), U128::ONE << 127);
385        assert_eq!(*I128::MINUS_ONE.as_uint(), U128::MAX);
386        assert_eq!(*I128::ZERO.as_uint(), U128::ZERO);
387        assert_eq!(*I128::ONE.as_uint(), U128::ONE);
388        assert_eq!(*I128::MAX.as_uint(), U128::MAX >> 1);
389    }
390}