Skip to main content

crypto_bigint/uint/
split.rs

1use crate::{Split, SplitEven, Uint};
2
3impl<const LIMBS: usize> Uint<LIMBS> {
4    /// Split this number in half into low and high components.
5    #[must_use]
6    pub const fn split<const HALF_LIMBS: usize>(&self) -> (Uint<HALF_LIMBS>, Uint<HALF_LIMBS>)
7    where
8        Self: SplitEven<Output = Uint<HALF_LIMBS>>,
9    {
10        self.split_resize()
11    }
12
13    /// Split this number into low and high components respectively.
14    #[inline]
15    #[must_use]
16    pub const fn split_mixed<const LO_LIMBS: usize, const HI_LIMBS: usize>(
17        &self,
18    ) -> (Uint<LO_LIMBS>, Uint<HI_LIMBS>)
19    where
20        Self: Split<LO_LIMBS, Output = Uint<HI_LIMBS>>,
21    {
22        self.split_resize()
23    }
24
25    /// Split this integer into low and high components. If `LIMBS` is not equal to
26    /// the sum of `LIMBS` and `HI_LIMBS`, then `None` is returned.
27    #[inline(always)]
28    #[must_use]
29    pub const fn split_checked<const LO_LIMBS: usize, const HI_LIMBS: usize>(
30        &self,
31    ) -> Option<(Uint<LO_LIMBS>, Uint<HI_LIMBS>)> {
32        if LO_LIMBS + HI_LIMBS == LIMBS {
33            Some(self.split_resize())
34        } else {
35            None
36        }
37    }
38
39    /// Split this integer into low and high components. The resulting values may be
40    /// truncated or extended with zeros depending upon whether `LIMBS` is greater or
41    /// less than the sum of `LO_LIMBS` and `HI_LIMBS`.
42    #[inline(always)]
43    #[must_use]
44    pub const fn split_resize<const LO_LIMBS: usize, const HI_LIMBS: usize>(
45        &self,
46    ) -> (Uint<LO_LIMBS>, Uint<HI_LIMBS>) {
47        let lo_len = if LO_LIMBS <= LIMBS { LO_LIMBS } else { LIMBS };
48        let (src_lo, src_hi) = self.as_uint_ref().split_at(lo_len);
49        (src_lo.to_uint_resize(), src_hi.to_uint_resize())
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use crate::{BitOps, U64, U128, U192, U256, Uint};
56
57    #[test]
58    fn split() {
59        let (lo, hi) = U128::from_be_hex("00112233445566778899aabbccddeeff").split();
60        assert_eq!(lo, U64::from_u64(0x8899aabbccddeeff));
61        assert_eq!(hi, U64::from_u64(0x0011223344556677));
62    }
63
64    #[test]
65    fn split_checked() {
66        let Some((lo, hi)) = U128::from_be_hex("00112233445566778899aabbccddeeff").split_checked()
67        else {
68            panic!("invalid split")
69        };
70        assert_eq!(lo, U64::from_u64(0x8899aabbccddeeff));
71        assert_eq!(hi, U64::from_u64(0x0011223344556677));
72
73        assert!(
74            U128::from_be_hex("00112233445566778899aabbccddeeff")
75                .split_checked::<8, 10>()
76                .is_none()
77        );
78    }
79
80    #[test]
81    fn split_resize_small() {
82        let (lo, hi) = U256::MAX.split_resize();
83        assert_eq!(lo, U64::MAX);
84        assert_eq!(hi, U64::MAX);
85    }
86
87    #[test]
88    fn split_resize_large() {
89        let (lo, hi) = U128::from_be_hex("00112233445566778899aabbccddeeff").split_resize();
90        assert_eq!(lo, U64::from_u64(0x8899aabbccddeeff));
91        assert_eq!(hi, U128::from_u64(0x0011223344556677));
92    }
93
94    #[test]
95    fn infer_sizes() {
96        let (lo, hi) = U128::ONE.split();
97        assert_eq!(lo.bits_precision(), 64);
98        assert_eq!(lo, Uint::ONE);
99        assert_eq!(hi.bits_precision(), 64);
100        assert_eq!(hi, Uint::ZERO);
101
102        let (lo, hi) = U192::ONE.split_mixed();
103        assert_eq!(lo, U64::ONE);
104        assert_eq!(hi.bits_precision(), 128);
105        assert_eq!(hi, Uint::ZERO);
106    }
107}