Skip to main content

crypto_bigint/
non_zero.rs

1//! Wrapper type for non-zero integers.
2
3use crate::{
4    Bounded, Choice, ConstOne, Constants, CtAssign, CtEq, CtOption, CtSelect, Encoding, Int, Limb,
5    Mul, Odd, One, ToUnsigned, Uint, UintRef, Zero,
6};
7use core::{
8    fmt,
9    num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128},
10    ops::Deref,
11    ptr,
12};
13use ctutils::{CtAssignSlice, CtEqSlice};
14
15#[cfg(feature = "alloc")]
16use crate::BoxedUint;
17
18#[cfg(feature = "hybrid-array")]
19use crate::{ArrayEncoding, ByteArray};
20
21#[cfg(feature = "rand_core")]
22use {crate::Random, rand_core::TryRng};
23
24#[cfg(feature = "serde")]
25use serdect::serde::{
26    Deserialize, Deserializer, Serialize, Serializer,
27    de::{Error, Unexpected},
28};
29
30/// Non-zero limb.
31pub type NonZeroLimb = NonZero<Limb>;
32
33/// Non-zero unsigned integer.
34pub type NonZeroUint<const LIMBS: usize> = NonZero<Uint<LIMBS>>;
35
36/// Non-zero unsigned integer reference.
37pub type NonZeroUintRef = NonZero<UintRef>;
38
39/// Non-zero signed integer.
40pub type NonZeroInt<const LIMBS: usize> = NonZero<Int<LIMBS>>;
41
42/// Non-zero boxed unsigned integer.
43#[cfg(feature = "alloc")]
44pub type NonZeroBoxedUint = NonZero<BoxedUint>;
45
46/// Wrapper type for non-zero integers.
47#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
48#[repr(transparent)]
49pub struct NonZero<T: ?Sized>(T);
50
51impl<T> NonZero<T> {
52    /// Create a new non-zero integer.
53    #[inline]
54    pub fn new(mut n: T) -> CtOption<Self>
55    where
56        T: Zero + One + CtAssign,
57    {
58        let is_zero = n.is_zero();
59
60        // Use one as a placeholder in the event zero is provided, so functions that operate on
61        // `NonZero` values really can expect the value to never be zero, even in the case
62        // `CtOption::is_some` is false.
63        n.ct_assign(&T::one_like(&n), is_zero);
64        CtOption::new(Self(n), !is_zero)
65    }
66
67    /// Create a new [`NonZero<T>`] without first checking that the contained value is non-zero.
68    ///
69    /// Use with care! This method bypasses invariant checks.
70    ///
71    /// # Warning: Panics
72    /// We don't explicitly flag this function as `unsafe` because it doesn't have a memory safety
73    /// impact, however functions called with `NonZero` arguments assume this value is non-zero
74    /// and may panic if given a zero value.
75    #[inline]
76    #[must_use]
77    pub(crate) const fn new_unchecked(n: T) -> NonZero<T> {
78        Self(n)
79    }
80
81    /// Returns the inner value.
82    #[inline]
83    pub fn get(self) -> T {
84        self.0
85    }
86
87    /// Returns a copy of the inner value for `Copy` types.
88    ///
89    /// This allows the function to be `const fn`, since `Copy` is implicitly `!Drop`, which avoids
90    /// problems around `const fn` destructors.
91    #[inline]
92    pub const fn get_copy(self) -> T
93    where
94        T: Copy,
95    {
96        self.0
97    }
98}
99
100impl<T: ?Sized> NonZero<T> {
101    /// Provides access to the contents of `NonZero` in a `const` context.
102    #[inline]
103    pub const fn as_ref(&self) -> &T {
104        &self.0
105    }
106
107    /// Cast a reference to [`NonZero`] without first checking that the referenced value is non-zero.
108    ///
109    /// Use with care! This method bypasses invariant checks.
110    ///
111    /// # Warning: Panics
112    /// We don't explicitly flag this function as `unsafe` because it doesn't have a memory safety
113    /// impact, however functions called with `NonZero` arguments assume this value is non-zero
114    /// and may panic if given a zero value.
115    #[inline]
116    #[must_use]
117    #[allow(unsafe_code)]
118    pub(crate) const fn new_ref_unchecked(refval: &T) -> &NonZero<T> {
119        // SAFETY: `NonZero` is a `repr(transparent)` newtype
120        unsafe { &*(ptr::from_ref(refval) as *const NonZero<T>) }
121    }
122}
123
124impl<T> NonZero<T>
125where
126    T: Bounded + ?Sized,
127{
128    /// Total size of the represented integer in bits.
129    pub const BITS: u32 = T::BITS;
130
131    /// Total size of the represented integer in bytes.
132    pub const BYTES: usize = T::BYTES;
133}
134
135impl<T> NonZero<T>
136where
137    T: Constants,
138{
139    /// The value `1`.
140    pub const ONE: Self = Self(T::ONE);
141
142    /// Maximum value this integer can express.
143    pub const MAX: Self = Self(T::MAX);
144}
145
146impl<T> NonZero<T>
147where
148    T: Zero + One + CtAssign + Encoding,
149{
150    /// Decode from big endian bytes.
151    pub fn from_be_bytes(bytes: T::Repr) -> CtOption<Self> {
152        Self::new(T::from_be_bytes(bytes))
153    }
154
155    /// Decode from little endian bytes.
156    pub fn from_le_bytes(bytes: T::Repr) -> CtOption<Self> {
157        Self::new(T::from_le_bytes(bytes))
158    }
159}
160
161impl<T> ConstOne for NonZero<T>
162where
163    T: ConstOne + One,
164{
165    const ONE: Self = Self(T::ONE);
166}
167
168impl<T> One for NonZero<T>
169where
170    T: One,
171    Self: CtEq,
172{
173    #[inline]
174    fn one() -> Self {
175        Self(T::one())
176    }
177}
178
179impl<T> num_traits::One for NonZero<T>
180where
181    T: One + Mul<T, Output = T>,
182{
183    #[inline]
184    fn one() -> Self {
185        Self(T::one())
186    }
187
188    fn is_one(&self) -> bool {
189        self.0.is_one().into()
190    }
191}
192
193/// Any non-zero integer multiplied by another non-zero integer is definitionally non-zero.
194impl<T> Mul<Self> for NonZero<T>
195where
196    T: Mul<T, Output = T>,
197{
198    type Output = Self;
199
200    fn mul(self, rhs: Self) -> Self {
201        Self(self.0 * rhs.0)
202    }
203}
204
205impl NonZero<Limb> {
206    /// Creates a new non-zero limb in a const context.
207    ///
208    /// # Panics
209    /// - if the value is zero.
210    ///
211    /// # Note
212    /// In future versions of Rust it should be possible to replace this with
213    /// `NonZero::new(…).unwrap()`
214    // TODO: Remove when `Self::new` and `CtOption::unwrap` support `const fn`
215    #[inline]
216    #[must_use]
217    #[track_caller]
218    pub const fn new_unwrap(n: Limb) -> Self {
219        assert!(n.is_nonzero().to_bool_vartime(), "invalid value: zero");
220        Self(n)
221    }
222
223    /// Create a [`NonZero<Limb>`] from a [`NonZeroU8`] (const-friendly)
224    // TODO(tarcieri): replace with `const impl From<NonZeroU8>` when stable
225    #[must_use]
226    pub const fn from_u8(n: NonZeroU8) -> Self {
227        Self(Limb::from_u8(n.get()))
228    }
229
230    /// Create a [`NonZero<Limb>`] from a [`NonZeroU16`] (const-friendly)
231    // TODO(tarcieri): replace with `const impl From<NonZeroU16>` when stable
232    #[must_use]
233    pub const fn from_u16(n: NonZeroU16) -> Self {
234        Self(Limb::from_u16(n.get()))
235    }
236
237    /// Create a [`NonZero<Limb>`] from a [`NonZeroU32`] (const-friendly)
238    // TODO(tarcieri): replace with `const impl From<NonZeroU32>` when stable
239    #[must_use]
240    pub const fn from_u32(n: NonZeroU32) -> Self {
241        Self(Limb::from_u32(n.get()))
242    }
243
244    cpubits::cpubits! {
245        64 => {
246            /// Create a [`NonZero<Limb>`] from a [`NonZeroU64`] (const-friendly)
247            // TODO(tarcieri): replace with `const impl From<NonZeroU64>` when stable
248            #[must_use]
249            pub const fn from_u64(n: NonZeroU64) -> Self {
250                Self(Limb::from_u64(n.get()))
251            }
252        }
253    }
254}
255
256impl<const LIMBS: usize> NonZeroUint<LIMBS> {
257    /// Creates a new non-zero integer in a const context.
258    ///
259    /// In future versions of Rust it should be possible to replace this with
260    /// `NonZero::new(…).unwrap()`
261    ///
262    /// # Panics
263    /// - if the value is zero.
264    // TODO: Remove when `Self::new` and `CtOption::unwrap` support `const fn`
265    #[inline]
266    #[track_caller]
267    #[must_use]
268    pub const fn new_unwrap(n: Uint<LIMBS>) -> Self {
269        assert!(n.is_nonzero().to_bool_vartime(), "invalid value: zero");
270        Self(n)
271    }
272
273    /// Create a new [`NonZero<Uint>`] from the provided big endian hex string.
274    ///
275    /// # Panics
276    /// - if the hex is zero, malformed, or not zero-padded accordingly for the size.
277    #[track_caller]
278    #[must_use]
279    pub const fn from_be_hex(hex: &str) -> Self {
280        Self::new_unwrap(Uint::from_be_hex(hex))
281    }
282
283    /// Create a new [`NonZero<Uint>`] from the provided little endian hex string.
284    ///
285    /// # Panics
286    /// - if the hex is zero, malformed, or not zero-padded accordingly for the size.
287    #[track_caller]
288    #[must_use]
289    pub const fn from_le_hex(hex: &str) -> Self {
290        Self::new_unwrap(Uint::from_le_hex(hex))
291    }
292
293    /// Create a [`NonZeroUint`] from a [`NonZeroU8`] (const-friendly)
294    // TODO(tarcieri): replace with `const impl From<NonZeroU8>` when stable
295    #[must_use]
296    pub const fn from_u8(n: NonZeroU8) -> Self {
297        Self(Uint::from_u8(n.get()))
298    }
299
300    /// Create a [`NonZeroUint`] from a [`NonZeroU16`] (const-friendly)
301    // TODO(tarcieri): replace with `const impl From<NonZeroU16>` when stable
302    #[must_use]
303    pub const fn from_u16(n: NonZeroU16) -> Self {
304        Self(Uint::from_u16(n.get()))
305    }
306
307    /// Create a [`NonZeroUint`] from a [`NonZeroU32`] (const-friendly)
308    // TODO(tarcieri): replace with `const impl From<NonZeroU32>` when stable
309    #[must_use]
310    pub const fn from_u32(n: NonZeroU32) -> Self {
311        Self(Uint::from_u32(n.get()))
312    }
313
314    /// Create a [`NonZeroUint`] from a [`NonZeroU64`] (const-friendly)
315    // TODO(tarcieri): replace with `const impl From<NonZeroU64>` when stable
316    #[must_use]
317    pub const fn from_u64(n: NonZeroU64) -> Self {
318        Self(Uint::from_u64(n.get()))
319    }
320
321    /// Create a [`NonZeroUint`] from a [`NonZeroU128`] (const-friendly)
322    // TODO(tarcieri): replace with `const impl From<NonZeroU128>` when stable
323    #[must_use]
324    pub const fn from_u128(n: NonZeroU128) -> Self {
325        Self(Uint::from_u128(n.get()))
326    }
327
328    /// Borrow this `NonZero<Uint>` as a `&NonZeroUintRef`.
329    #[inline]
330    #[must_use]
331    pub const fn as_uint_ref(&self) -> &NonZeroUintRef {
332        NonZero::new_ref_unchecked(self.0.as_uint_ref())
333    }
334}
335
336impl<const LIMBS: usize> AsRef<NonZeroUintRef> for NonZeroUint<LIMBS> {
337    fn as_ref(&self) -> &NonZeroUintRef {
338        self.as_uint_ref()
339    }
340}
341
342impl<const LIMBS: usize> NonZeroInt<LIMBS> {
343    /// Creates a new non-zero integer in a const context.
344    ///
345    /// # Panics
346    /// - if the value is zero.
347    ///
348    /// # Note
349    /// In future versions of Rust it should be possible to replace this with
350    /// `NonZero::new(…).unwrap()`
351    // TODO: Remove when `Self::new` and `CtOption::unwrap` support `const fn`
352    #[inline]
353    #[must_use]
354    #[track_caller]
355    pub const fn new_unwrap(n: Int<LIMBS>) -> Self {
356        assert!(n.is_nonzero().to_bool_vartime(), "invalid value: zero");
357        Self(n)
358    }
359
360    /// The sign and magnitude of this [`NonZeroInt`].
361    #[must_use]
362    pub const fn abs_sign(&self) -> (NonZero<Uint<LIMBS>>, Choice) {
363        let (abs, sign) = self.0.abs_sign();
364        // Absolute value of a non-zero value is non-zero
365        (NonZero(abs), sign)
366    }
367
368    /// The magnitude of this [`NonZeroInt`].
369    #[must_use]
370    pub const fn abs(&self) -> NonZero<Uint<LIMBS>> {
371        self.abs_sign().0
372    }
373}
374
375#[cfg(feature = "alloc")]
376impl NonZeroBoxedUint {
377    /// Borrow this `NonZeroBoxedUint` as a `&NonZeroUintRef`.
378    #[inline]
379    #[must_use]
380    pub const fn as_uint_ref(&self) -> &NonZeroUintRef {
381        NonZero::new_ref_unchecked(self.0.as_uint_ref())
382    }
383}
384
385#[cfg(feature = "alloc")]
386impl AsRef<NonZeroUintRef> for NonZeroBoxedUint {
387    fn as_ref(&self) -> &NonZeroUintRef {
388        self.as_uint_ref()
389    }
390}
391
392#[cfg(feature = "alloc")]
393impl<T: AsRef<UintRef> + ?Sized> NonZero<T> {
394    /// Get the least significant limb as a [`NonZeroLimb`].
395    pub(crate) fn lower_limb(&self) -> NonZeroLimb {
396        NonZero(self.0.as_ref().limbs[0])
397    }
398
399    /// Convert to a [`NonZeroBoxedUint`].
400    pub(crate) fn to_boxed(&self) -> NonZeroBoxedUint {
401        NonZero(BoxedUint::from(self.0.as_ref()))
402    }
403}
404
405impl<T: ToUnsigned + ?Sized> NonZero<T> {
406    /// Convert from a reference into an owned `NonZero<T: Unsigned>`.
407    pub fn to_unsigned(&self) -> NonZero<T::Unsigned> {
408        NonZero(self.0.to_unsigned())
409    }
410}
411
412#[cfg(feature = "hybrid-array")]
413impl<T> NonZero<T>
414where
415    T: ArrayEncoding + Zero + One + CtAssign,
416{
417    /// Decode a non-zero integer from big endian bytes.
418    pub fn from_be_byte_array(bytes: ByteArray<T>) -> CtOption<Self> {
419        Self::new(T::from_be_byte_array(bytes))
420    }
421
422    /// Decode a non-zero integer from little endian bytes.
423    pub fn from_le_byte_array(bytes: ByteArray<T>) -> CtOption<Self> {
424        Self::new(T::from_le_byte_array(bytes))
425    }
426}
427
428impl<T: ?Sized> AsRef<T> for NonZero<T> {
429    fn as_ref(&self) -> &T {
430        &self.0
431    }
432}
433
434impl<T> CtAssign for NonZero<T>
435where
436    T: CtAssign,
437{
438    #[inline]
439    fn ct_assign(&mut self, other: &Self, choice: Choice) {
440        self.0.ct_assign(&other.0, choice);
441    }
442}
443impl<T> CtAssignSlice for NonZero<T> where T: CtAssign {}
444
445impl<T> CtEq for NonZero<T>
446where
447    T: CtEq + ?Sized,
448{
449    #[inline]
450    fn ct_eq(&self, other: &Self) -> Choice {
451        CtEq::ct_eq(&self.0, &other.0)
452    }
453}
454impl<T> CtEqSlice for NonZero<T> where T: CtEq {}
455
456impl<T> CtSelect for NonZero<T>
457where
458    T: CtSelect,
459{
460    #[inline]
461    fn ct_select(&self, other: &Self, choice: Choice) -> Self {
462        Self(self.0.ct_select(&other.0, choice))
463    }
464}
465
466impl<T> Default for NonZero<T>
467where
468    T: One,
469{
470    #[inline]
471    fn default() -> Self {
472        Self(T::one())
473    }
474}
475
476impl<T: ?Sized> Deref for NonZero<T> {
477    type Target = T;
478
479    fn deref(&self) -> &T {
480        &self.0
481    }
482}
483
484#[cfg(feature = "rand_core")]
485impl<T> Random for NonZero<T>
486where
487    T: Random + Zero + One + CtAssign,
488{
489    /// This uses rejection sampling to avoid zero.
490    ///
491    /// As a result, it runs in variable time. If the generator `rng` is
492    /// cryptographically secure (for example, it implements `CryptoRng`),
493    /// then this is guaranteed not to leak anything about the output value.
494    fn try_random_from_rng<R: TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
495        loop {
496            if let Some(result) = Self::new(T::try_random_from_rng(rng)?).into() {
497                break Ok(result);
498            }
499        }
500    }
501}
502
503impl From<NonZeroU8> for NonZero<Limb> {
504    fn from(integer: NonZeroU8) -> Self {
505        Self::from_u8(integer)
506    }
507}
508
509impl From<NonZeroU16> for NonZero<Limb> {
510    fn from(integer: NonZeroU16) -> Self {
511        Self::from_u16(integer)
512    }
513}
514
515impl From<NonZeroU32> for NonZero<Limb> {
516    fn from(integer: NonZeroU32) -> Self {
517        Self::from_u32(integer)
518    }
519}
520
521cpubits::cpubits! {
522    64 => {
523        impl From<NonZeroU64> for NonZero<Limb> {
524            fn from(integer: NonZeroU64) -> Self {
525                Self::from_u64(integer)
526            }
527        }
528    }
529}
530
531impl<const LIMBS: usize> From<NonZeroU8> for NonZero<Uint<LIMBS>> {
532    fn from(integer: NonZeroU8) -> Self {
533        Self::from_u8(integer)
534    }
535}
536
537impl<const LIMBS: usize> From<NonZeroU16> for NonZero<Uint<LIMBS>> {
538    fn from(integer: NonZeroU16) -> Self {
539        Self::from_u16(integer)
540    }
541}
542
543impl<const LIMBS: usize> From<NonZeroU32> for NonZero<Uint<LIMBS>> {
544    fn from(integer: NonZeroU32) -> Self {
545        Self::from_u32(integer)
546    }
547}
548
549impl<const LIMBS: usize> From<NonZeroU64> for NonZero<Uint<LIMBS>> {
550    fn from(integer: NonZeroU64) -> Self {
551        Self::from_u64(integer)
552    }
553}
554
555impl<const LIMBS: usize> From<NonZeroU128> for NonZero<Uint<LIMBS>> {
556    fn from(integer: NonZeroU128) -> Self {
557        Self::from_u128(integer)
558    }
559}
560
561impl<T> From<Odd<T>> for NonZero<T> {
562    fn from(odd: Odd<T>) -> NonZero<T> {
563        NonZero(odd.get())
564    }
565}
566
567impl<T> fmt::Display for NonZero<T>
568where
569    T: fmt::Display + ?Sized,
570{
571    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
572        fmt::Display::fmt(&self.0, f)
573    }
574}
575
576impl<T> fmt::Binary for NonZero<T>
577where
578    T: fmt::Binary + ?Sized,
579{
580    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
581        fmt::Binary::fmt(&self.0, f)
582    }
583}
584
585impl<T> fmt::Octal for NonZero<T>
586where
587    T: fmt::Octal + ?Sized,
588{
589    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590        fmt::Octal::fmt(&self.0, f)
591    }
592}
593
594impl<T> fmt::LowerHex for NonZero<T>
595where
596    T: fmt::LowerHex + ?Sized,
597{
598    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
599        fmt::LowerHex::fmt(&self.0, f)
600    }
601}
602
603impl<T> fmt::UpperHex for NonZero<T>
604where
605    T: fmt::UpperHex + ?Sized,
606{
607    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
608        fmt::UpperHex::fmt(&self.0, f)
609    }
610}
611
612#[cfg(feature = "serde")]
613impl<'de, T: Deserialize<'de> + Zero> Deserialize<'de> for NonZero<T> {
614    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
615    where
616        D: Deserializer<'de>,
617    {
618        let value: T = T::deserialize(deserializer)?;
619
620        if bool::from(value.is_zero()) {
621            Err(D::Error::invalid_value(
622                Unexpected::Other("zero"),
623                &"a non-zero value",
624            ))
625        } else {
626            Ok(Self(value))
627        }
628    }
629}
630
631#[cfg(feature = "serde")]
632impl<T: Serialize + Zero> Serialize for NonZero<T> {
633    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
634    where
635        S: Serializer,
636    {
637        self.0.serialize(serializer)
638    }
639}
640
641#[cfg(feature = "subtle")]
642impl<T> subtle::ConditionallySelectable for NonZero<T>
643where
644    T: Copy,
645    Self: CtSelect,
646{
647    fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
648        CtSelect::ct_select(a, b, choice.into())
649    }
650}
651
652#[cfg(feature = "subtle")]
653impl<T> subtle::ConstantTimeEq for NonZero<T>
654where
655    T: ?Sized,
656    Self: CtEq,
657{
658    #[inline]
659    fn ct_eq(&self, other: &Self) -> subtle::Choice {
660        CtEq::ct_eq(self, other).into()
661    }
662}
663
664#[cfg(feature = "zeroize")]
665impl<T: zeroize::Zeroize + One> zeroize::Zeroize for NonZero<T> {
666    fn zeroize(&mut self) {
667        self.0.zeroize();
668        self.0 = T::one_like(&self.0);
669    }
670}
671
672#[cfg(test)]
673mod tests {
674    use super::NonZero;
675    use crate::{I128, One, U128};
676    use hex_literal::hex;
677
678    #[cfg(all(feature = "alloc", feature = "zeroize"))]
679    use crate::BoxedUint;
680
681    #[cfg(feature = "zeroize")]
682    use zeroize::Zeroize;
683
684    #[test]
685    fn default() {
686        assert!(!NonZero::<U128>::default().is_zero().to_bool());
687    }
688
689    #[test]
690    fn from_be_bytes() {
691        assert_eq!(
692            NonZero::<U128>::from_be_bytes(hex!("00000000000000000000000000000001").into())
693                .unwrap(),
694            NonZero::<U128>::ONE
695        );
696
697        assert_eq!(
698            NonZero::<U128>::from_be_bytes(hex!("00000000000000000000000000000000").into())
699                .into_option(),
700            None
701        );
702    }
703
704    #[test]
705    fn from_le_bytes() {
706        assert_eq!(
707            NonZero::<U128>::from_le_bytes(hex!("01000000000000000000000000000000").into())
708                .unwrap(),
709            NonZero::<U128>::ONE
710        );
711
712        assert_eq!(
713            NonZero::<U128>::from_le_bytes(hex!("00000000000000000000000000000000").into())
714                .into_option(),
715            None
716        );
717    }
718
719    #[cfg(feature = "zeroize")]
720    #[test]
721    fn zeroize_preserves_invariant() {
722        let mut value = NonZero::new(U128::from(0x1234u64)).unwrap();
723
724        value.zeroize();
725
726        assert_eq!(*value.as_ref(), U128::ONE);
727    }
728
729    #[cfg(all(feature = "alloc", feature = "zeroize"))]
730    #[test]
731    fn boxed_zeroize_preserves_invariant_and_precision() {
732        let mut value =
733            NonZero::new(BoxedUint::from_be_slice(&[0x12, 0x34], 128).unwrap()).unwrap();
734
735        value.zeroize();
736
737        assert_eq!(value.as_ref(), &BoxedUint::one_with_precision(128));
738        assert_eq!(value.bits_precision(), 128);
739    }
740
741    #[test]
742    fn from_be_hex_when_nonzero() {
743        assert_eq!(
744            NonZero::<U128>::from_be_hex("00000000000000000000000000000001"),
745            NonZero::<U128>::ONE
746        );
747    }
748
749    #[test]
750    #[should_panic]
751    fn from_be_hex_when_zero() {
752        let _ = NonZero::<U128>::from_be_hex("00000000000000000000000000000000");
753    }
754
755    #[test]
756    fn from_le_hex_when_nonzero() {
757        assert_eq!(
758            NonZero::<U128>::from_le_hex("01000000000000000000000000000000"),
759            NonZero::<U128>::ONE
760        );
761    }
762
763    #[test]
764    #[should_panic]
765    fn from_le_hex_when_zero() {
766        let _ = NonZero::<U128>::from_le_hex("00000000000000000000000000000000");
767    }
768
769    #[test]
770    fn int_abs_sign() {
771        let x = I128::from(-55).to_nz().unwrap();
772        let (abs, sgn) = x.abs_sign();
773        assert_eq!(abs, U128::from(55u32).to_nz().unwrap());
774        assert!(sgn.to_bool());
775    }
776
777    #[test]
778    fn one() {
779        assert_eq!(
780            NonZero::<U128>::from_le_bytes(hex!("01000000000000000000000000000000").into())
781                .unwrap(),
782            NonZero::<U128>::one()
783        );
784    }
785
786    #[cfg(feature = "hybrid-array")]
787    #[test]
788    fn from_le_byte_array() {
789        assert_eq!(
790            NonZero::<U128>::from_le_byte_array(hex!("01000000000000000000000000000000").into())
791                .unwrap(),
792            NonZero::<U128>::ONE
793        );
794    }
795}