Skip to main content

crypto_bigint/uint/
from.rs

1//! `From`-like conversions for [`Uint`].
2
3use crate::{Concat, Limb, Split, U64, U128, Uint, WideWord, Word};
4
5macro_rules! check_limbs {
6    ($limbs:expr) => {
7        check_limbs!($limbs, 1)
8    };
9    ($limbs:expr, $min:expr) => {
10        const {
11            assert!($limbs >= 1, "number of limbs too small of supplied type");
12        }
13    };
14}
15
16impl<const LIMBS: usize> Uint<LIMBS> {
17    /// Create a [`Uint`] from a `u8` (const-friendly)
18    // TODO(tarcieri): replace with `const impl From<u8>` when stable
19    #[inline]
20    #[must_use]
21    pub const fn from_u8(n: u8) -> Self {
22        check_limbs!(LIMBS);
23        let mut limbs = [Limb::ZERO; LIMBS];
24        limbs[0].0 = n as Word;
25        Self { limbs }
26    }
27
28    /// Create a [`Uint`] from a `u16` (const-friendly)
29    // TODO(tarcieri): replace with `const impl From<u16>` when stable
30    #[inline]
31    #[must_use]
32    pub const fn from_u16(n: u16) -> Self {
33        check_limbs!(LIMBS);
34        let mut limbs = [Limb::ZERO; LIMBS];
35        limbs[0].0 = n as Word;
36        Self { limbs }
37    }
38
39    /// Create a [`Uint`] from a `u32` (const-friendly)
40    // TODO(tarcieri): replace with `const impl From<u32>` when stable
41    #[allow(trivial_numeric_casts)]
42    #[inline]
43    #[must_use]
44    pub const fn from_u32(n: u32) -> Self {
45        check_limbs!(LIMBS);
46        let mut limbs = [Limb::ZERO; LIMBS];
47        limbs[0].0 = n as Word;
48        Self { limbs }
49    }
50
51    cpubits::cpubits! {
52        32 => {
53            /// Create a [`Uint`] from a `u64` (const-friendly)
54            // TODO(tarcieri): replace with `const impl From<u64>` when stable
55            #[inline]
56            pub const fn from_u64(n: u64) -> Self {
57                check_limbs!(LIMBS, 2);
58                let mut limbs = [Limb::ZERO; LIMBS];
59                limbs[0].0 = (n & 0xFFFFFFFF) as u32;
60                limbs[1].0 = (n >> 32) as u32;
61                Self { limbs }
62            }
63        }
64        64 => {
65            /// Create a [`Uint`] from a `u64` (const-friendly)
66            // TODO(tarcieri): replace with `const impl From<u64>` when stable
67            #[inline]
68            #[must_use]
69            pub const fn from_u64(n: u64) -> Self {
70                check_limbs!(LIMBS);
71                let mut limbs = [Limb::ZERO; LIMBS];
72                limbs[0].0 = n;
73                Self { limbs }
74            }
75        }
76    }
77
78    /// Create a [`Uint`] from a `u128` (const-friendly)
79    // TODO(tarcieri): replace with `const impl From<u128>` when stable
80    #[inline]
81    #[must_use]
82    pub const fn from_u128(n: u128) -> Self {
83        check_limbs!(LIMBS, 16 / Limb::BYTES);
84        let lo = U64::from_u64((n & 0xffff_ffff_ffff_ffff) as u64);
85        let hi = U64::from_u64((n >> 64) as u64);
86
87        let mut limbs = [Limb::ZERO; LIMBS];
88
89        let mut i = 0;
90        while i < lo.limbs.len() {
91            limbs[i] = lo.limbs[i];
92            i += 1;
93        }
94
95        let mut j = 0;
96        while j < hi.limbs.len() {
97            limbs[i + j] = hi.limbs[j];
98            j += 1;
99        }
100
101        Self { limbs }
102    }
103
104    /// Create a [`Uint`] from a `Word` (const-friendly)
105    // TODO(tarcieri): replace with `const impl From<Word>` when stable
106    #[inline]
107    #[must_use]
108    pub const fn from_word(n: Word) -> Self {
109        check_limbs!(LIMBS);
110        let mut limbs = [Limb::ZERO; LIMBS];
111        limbs[0].0 = n;
112        Self { limbs }
113    }
114
115    /// Create a [`Uint`] from a `WideWord` (const-friendly)
116    // TODO(tarcieri): replace with `const impl From<WideWord>` when stable
117    #[inline]
118    #[must_use]
119    #[allow(clippy::cast_possible_truncation)]
120    pub const fn from_wide_word(n: WideWord) -> Self {
121        check_limbs!(LIMBS, 2);
122        let mut limbs = [Limb::ZERO; LIMBS];
123        limbs[0].0 = n as Word;
124        limbs[1].0 = (n >> Limb::BITS) as Word;
125        Self { limbs }
126    }
127}
128
129impl<const LIMBS: usize> From<u8> for Uint<LIMBS> {
130    #[inline]
131    fn from(n: u8) -> Self {
132        check_limbs!(LIMBS);
133        Self::from_u8(n)
134    }
135}
136
137impl<const LIMBS: usize> From<u16> for Uint<LIMBS> {
138    #[inline]
139    fn from(n: u16) -> Self {
140        check_limbs!(LIMBS);
141        Self::from_u16(n)
142    }
143}
144
145impl<const LIMBS: usize> From<u32> for Uint<LIMBS> {
146    #[inline]
147    fn from(n: u32) -> Self {
148        check_limbs!(LIMBS);
149        Self::from_u32(n)
150    }
151}
152
153impl<const LIMBS: usize> From<u64> for Uint<LIMBS> {
154    #[inline]
155    fn from(n: u64) -> Self {
156        check_limbs!(LIMBS, 8 / Limb::BYTES);
157        Self::from_u64(n)
158    }
159}
160
161impl<const LIMBS: usize> From<u128> for Uint<LIMBS> {
162    #[inline]
163    fn from(n: u128) -> Self {
164        check_limbs!(LIMBS, 16 / Limb::BYTES);
165        Self::from_u128(n)
166    }
167}
168
169cpubits::cpubits! {
170    32 => {
171        impl From<U64> for u64 {
172            #[inline]
173            fn from(n: U64) -> u64 {
174                (n.limbs[0].0 as u64) | ((n.limbs[1].0 as u64) << 32)
175            }
176        }
177    }
178    64 => {
179        impl From<U64> for u64 {
180            #[inline]
181            fn from(n: U64) -> u64 {
182                n.limbs[0].into()
183            }
184        }
185    }
186}
187
188impl From<U128> for u128 {
189    #[inline]
190    fn from(n: U128) -> u128 {
191        let mut i = U128::LIMBS - 1;
192        let mut res = u128::from(n.limbs[i].0);
193        while i > 0 {
194            i -= 1;
195            res = (res << Limb::BITS) | u128::from(n.limbs[i].0);
196        }
197        res
198    }
199}
200
201impl<const LIMBS: usize> From<[Word; LIMBS]> for Uint<LIMBS> {
202    #[inline]
203    fn from(arr: [Word; LIMBS]) -> Self {
204        Self::from_words(arr)
205    }
206}
207
208impl<const LIMBS: usize> From<Uint<LIMBS>> for [Word; LIMBS] {
209    #[inline]
210    fn from(n: Uint<LIMBS>) -> [Word; LIMBS] {
211        *n.as_ref()
212    }
213}
214
215impl<const LIMBS: usize> From<[Limb; LIMBS]> for Uint<LIMBS> {
216    #[inline]
217    fn from(limbs: [Limb; LIMBS]) -> Self {
218        Self { limbs }
219    }
220}
221
222impl<const LIMBS: usize> From<Uint<LIMBS>> for [Limb; LIMBS] {
223    #[inline]
224    fn from(n: Uint<LIMBS>) -> [Limb; LIMBS] {
225        n.limbs
226    }
227}
228
229impl<const LIMBS: usize> From<Limb> for Uint<LIMBS> {
230    #[inline]
231    fn from(limb: Limb) -> Self {
232        limb.0.into()
233    }
234}
235
236impl<const LO_LIMBS: usize, const HI_LIMBS: usize, const WIDE_LIMBS: usize>
237    From<(Uint<LO_LIMBS>, Uint<HI_LIMBS>)> for Uint<WIDE_LIMBS>
238where
239    Uint<LO_LIMBS>: Concat<HI_LIMBS, Output = Uint<WIDE_LIMBS>>,
240{
241    #[inline]
242    fn from(nums: (Uint<LO_LIMBS>, Uint<HI_LIMBS>)) -> Uint<WIDE_LIMBS> {
243        nums.0.concat_mixed(&nums.1)
244    }
245}
246
247impl<const LO_LIMBS: usize, const HI_LIMBS: usize, const WIDE_LIMBS: usize>
248    From<&(Uint<LO_LIMBS>, Uint<HI_LIMBS>)> for Uint<WIDE_LIMBS>
249where
250    Uint<LO_LIMBS>: Concat<HI_LIMBS, Output = Uint<WIDE_LIMBS>>,
251{
252    #[inline]
253    fn from(nums: &(Uint<LO_LIMBS>, Uint<HI_LIMBS>)) -> Uint<WIDE_LIMBS> {
254        nums.0.concat_mixed(&nums.1)
255    }
256}
257
258impl<const LO_LIMBS: usize, const HI_LIMBS: usize, const WIDE_LIMBS: usize> From<Uint<WIDE_LIMBS>>
259    for (Uint<LO_LIMBS>, Uint<HI_LIMBS>)
260where
261    Uint<WIDE_LIMBS>: Split<LO_LIMBS, Output = Uint<HI_LIMBS>>,
262{
263    #[inline]
264    fn from(num: Uint<WIDE_LIMBS>) -> (Uint<LO_LIMBS>, Uint<HI_LIMBS>) {
265        num.split_mixed()
266    }
267}
268
269impl<const LO_LIMBS: usize, const HI_LIMBS: usize, const WIDE_LIMBS: usize> From<&Uint<WIDE_LIMBS>>
270    for (Uint<LO_LIMBS>, Uint<HI_LIMBS>)
271where
272    Uint<WIDE_LIMBS>: Split<LO_LIMBS, Output = Uint<HI_LIMBS>>,
273{
274    #[inline]
275    fn from(num: &Uint<WIDE_LIMBS>) -> (Uint<LO_LIMBS>, Uint<HI_LIMBS>) {
276        num.split_mixed()
277    }
278}
279
280impl<const LIMBS: usize, const LIMBS2: usize> From<&Uint<LIMBS>> for Uint<LIMBS2> {
281    #[inline]
282    fn from(num: &Uint<LIMBS>) -> Uint<LIMBS2> {
283        num.resize()
284    }
285}
286
287#[cfg(test)]
288mod tests {
289    use crate::{Limb, U64, U128, Word};
290
291    cpubits::cpubits! {
292        32 => { use crate::U64 as UintEx; }
293        64 => { use crate::U128 as UintEx; }
294    }
295
296    #[test]
297    fn from_u8() {
298        let n = UintEx::from(42u8);
299        assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]);
300    }
301
302    #[test]
303    fn from_u16() {
304        let n = UintEx::from(42u16);
305        assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]);
306    }
307
308    #[test]
309    fn from_u64() {
310        let n = UintEx::from(42u64);
311        assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]);
312    }
313
314    #[test]
315    fn from_u128() {
316        let n = U128::from(42u128);
317        assert_eq!(&n.as_limbs()[..2], &[Limb(42), Limb(0)]);
318        assert_eq!(u128::from(n), 42u128);
319    }
320
321    #[test]
322    fn concat_mixed() {
323        let wide: U128 = (U64::ONE, U64::ZERO).into();
324        assert_eq!(wide, U128::ONE);
325
326        let wide: U128 = (&(U64::MAX, U64::MAX)).into();
327        assert_eq!(wide, U128::MAX);
328    }
329
330    #[test]
331    fn split_mixed() {
332        let lo_hi: (U64, _) = U128::ONE.into();
333        assert_eq!(lo_hi, (U64::ONE, U64::ZERO));
334
335        let lo_hi: (U64, _) = (&U128::MAX).into();
336        assert_eq!(lo_hi, (U64::MAX, U64::MAX));
337    }
338
339    #[test]
340    fn array_round_trip() {
341        let arr1 = [1, 2];
342        let n = UintEx::from(arr1);
343        let arr2: [Word; 2] = n.into();
344        assert_eq!(arr1, arr2);
345    }
346}