Skip to main content

crypto_bigint/uint/
concat.rs

1use crate::{Concat, Uint};
2
3impl<const LIMBS: usize> Uint<LIMBS> {
4    /// Concatenate the two values, with `self` as least significant and `hi` as the most
5    /// significant, with both values having the same size.
6    #[must_use]
7    pub const fn concat<const WIDE_LIMBS: usize>(&self, hi: &Self) -> Uint<WIDE_LIMBS>
8    where
9        Self: Concat<LIMBS, Output = Uint<WIDE_LIMBS>>,
10    {
11        self.concat_resize(hi)
12    }
13
14    /// Concatenate the two values, with `self` as least significant and `hi`
15    /// as the most significant.
16    #[inline]
17    #[must_use]
18    pub const fn concat_mixed<const HI_LIMBS: usize, const WIDE_LIMBS: usize>(
19        &self,
20        hi: &Uint<HI_LIMBS>,
21    ) -> Uint<WIDE_LIMBS>
22    where
23        Self: Concat<HI_LIMBS, Output = Uint<WIDE_LIMBS>>,
24    {
25        self.concat_resize(hi)
26    }
27
28    /// Concatenate the two values, with `self` as least significant and `hi`
29    /// as the most significant. If `WIDE_LIMBS` is not equal to the sum of
30    /// `LIMBS` and `HI_LIMBS`, then `None` is returned.
31    #[inline(always)]
32    #[must_use]
33    pub const fn concat_checked<const HI_LIMBS: usize, const WIDE_LIMBS: usize>(
34        &self,
35        hi: &Uint<HI_LIMBS>,
36    ) -> Option<Uint<WIDE_LIMBS>> {
37        if LIMBS + HI_LIMBS == WIDE_LIMBS {
38            Some(self.concat_resize(hi))
39        } else {
40            None
41        }
42    }
43
44    /// Concatenate the two values, with `self` as least significant and `hi`
45    /// as the most significant. The resulting wide integer may be truncated or
46    /// extended with zeros depending upon whether its size is less than or greater
47    /// than the sum of `LIMBS` and `HI_LIMBS`.
48    #[inline(always)]
49    #[must_use]
50    pub const fn concat_resize<const HI_LIMBS: usize, const WIDE_LIMBS: usize>(
51        &self,
52        hi: &Uint<HI_LIMBS>,
53    ) -> Uint<WIDE_LIMBS> {
54        let mut res = Uint::ZERO;
55        let len = if LIMBS + HI_LIMBS <= WIDE_LIMBS {
56            LIMBS + HI_LIMBS
57        } else {
58            WIDE_LIMBS
59        };
60        let lo_len = if LIMBS <= len { LIMBS } else { len };
61        let hi_len = len - lo_len;
62        let (res_lo, res_hi) = res.as_mut_uint_ref().split_at_mut(lo_len);
63        res_lo.copy_from(self.as_uint_ref().leading(lo_len));
64        res_hi
65            .leading_mut(hi_len)
66            .copy_from(hi.as_uint_ref().leading(hi_len));
67        res
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use crate::{BitOps, U64, U128, U192, U256, Uint};
74
75    #[test]
76    fn concat() {
77        let hi = U64::from_u64(0x0011223344556677);
78        let lo = U64::from_u64(0x8899aabbccddeeff);
79        assert_eq!(
80            lo.concat(&hi),
81            U128::from_be_hex("00112233445566778899aabbccddeeff")
82        );
83    }
84
85    #[test]
86    fn concat_checked() {
87        let hi = U64::from_u64(0x0011223344556677);
88        let lo = U64::from_u64(0x8899aabbccddeeff);
89        let Some(wide) = lo.concat_checked(&hi) else {
90            panic!("invalid concat")
91        };
92        assert_eq!(wide, U128::from_u128(0x00112233445566778899aabbccddeeff));
93
94        assert!(lo.concat_checked::<{ U64::LIMBS }, 10>(&hi).is_none());
95    }
96
97    #[test]
98    fn concat_resize_small() {
99        let hi = U128::from_u64(0x0011223344556677);
100        let lo = U128::MAX;
101        assert_eq!(lo.concat_resize(&hi), U64::MAX);
102    }
103
104    #[test]
105    fn concat_resize_large() {
106        let hi = U64::from_u64(0x0011223344556677);
107        let lo = U64::from_u64(0x8899aabbccddeeff);
108        assert_eq!(
109            lo.concat_resize(&hi),
110            U256::from_u128(0x00112233445566778899aabbccddeeff)
111        );
112    }
113
114    #[test]
115    fn concat_mixed() {
116        let hi = U64::from_u64(0x0011223344556677);
117        let lo = U128::from_u128(0x8899aabbccddeeff_8899aabbccddeeff);
118        assert_eq!(
119            lo.concat_mixed(&hi),
120            U192::from_be_hex("00112233445566778899aabbccddeeff8899aabbccddeeff")
121        );
122        assert_eq!(
123            hi.concat_mixed(&lo),
124            U192::from_be_hex("8899aabbccddeeff8899aabbccddeeff0011223344556677")
125        );
126    }
127
128    #[test]
129    fn convert() {
130        let res: U128 = U64::ONE.widening_mul(&U64::ONE).into();
131        assert_eq!(res, U128::ONE);
132
133        let res: U128 = U64::ONE.widening_square().into();
134        assert_eq!(res, U128::ONE);
135    }
136
137    #[test]
138    fn infer_sizes() {
139        let wide = U64::ONE.concat(&Uint::ZERO);
140        assert_eq!(wide.bits_precision(), 128);
141        assert_eq!(wide, Uint::ONE);
142
143        let wide = U64::ONE.concat_mixed(&U128::ZERO);
144        assert_eq!(wide.bits_precision(), 192);
145        assert_eq!(wide, Uint::ONE);
146    }
147}