1use 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#[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 pub const ZERO: Self = Self(Uint::ZERO); pub const ONE: Self = Self(Uint::ONE); pub const MINUS_ONE: Self = Self(Uint::MAX); pub const MIN: Self = Self::MAX.not(); pub const MAX: Self = Self(Uint::MAX.shr_vartime(1u32)); pub const SIGN_MASK: Self = Self::MIN; pub const BITS: u32 = Uint::<LIMBS>::BITS;
72
73 pub const BYTES: usize = Uint::<LIMBS>::BYTES;
75
76 pub const LIMBS: usize = LIMBS;
78
79 #[must_use]
81 pub const fn new(limbs: [Limb; LIMBS]) -> Self {
82 Self(Uint::new(limbs))
83 }
84
85 pub(crate) const fn from_bits(value: Uint<LIMBS>) -> Self {
91 Self(value)
92 }
93
94 #[inline]
97 #[must_use]
98 pub const fn from_words(arr: [Word; LIMBS]) -> Self {
99 Self(Uint::from_words(arr))
100 }
101
102 #[inline]
105 #[must_use]
106 pub const fn to_words(self) -> [Word; LIMBS] {
107 self.0.to_words()
108 }
109
110 #[must_use]
112 pub const fn as_words(&self) -> &[Word; LIMBS] {
113 self.0.as_words()
114 }
115
116 pub const fn as_mut_words(&mut self) -> &mut [Word; LIMBS] {
118 self.0.as_mut_words()
119 }
120
121 #[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 #[must_use]
129 pub const fn as_limbs(&self) -> &[Limb; LIMBS] {
130 self.0.as_limbs()
131 }
132
133 pub const fn as_mut_limbs(&mut self) -> &mut [Limb; LIMBS] {
135 self.0.as_mut_limbs()
136 }
137
138 #[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 #[must_use]
146 pub const fn to_limbs(self) -> [Limb; LIMBS] {
147 self.0.to_limbs()
148 }
149
150 #[must_use]
154 pub const fn to_nz(self) -> CtOption<NonZero<Self>> {
155 CtOption::new(NonZero(self), self.0.is_nonzero())
156 }
157
158 #[must_use]
162 pub const fn to_odd(self) -> CtOption<Odd<Self>> {
163 CtOption::new(Odd(self), self.0.is_odd())
164 }
165
166 #[must_use]
172 pub const fn as_uint(&self) -> &Uint<LIMBS> {
173 &self.0
174 }
175
176 #[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 #[must_use]
188 pub const fn is_min(&self) -> Choice {
189 Self::eq(self, &Self::MIN)
190 }
191
192 #[must_use]
194 pub const fn is_max(&self) -> Choice {
195 Self::eq(self, &Self::MAX)
196 }
197
198 #[must_use]
200 pub const fn is_zero(&self) -> Choice {
201 self.0.is_zero()
202 }
203
204 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}