crypto_bigint/uint/
from.rs

1//! `From`-like conversions for [`Uint`].
2
3use crate::{ConcatMixed, Limb, SplitMixed, Uint, WideWord, Word, U128, U64};
4
5impl<const LIMBS: usize> Uint<LIMBS> {
6    /// Create a [`Uint`] from a `u8` (const-friendly)
7    // TODO(tarcieri): replace with `const impl From<u8>` when stable
8    pub const fn from_u8(n: u8) -> Self {
9        assert!(LIMBS >= 1, "number of limbs must be greater than zero");
10        let mut limbs = [Limb::ZERO; LIMBS];
11        limbs[0].0 = n as Word;
12        Self { limbs }
13    }
14
15    /// Create a [`Uint`] from a `u16` (const-friendly)
16    // TODO(tarcieri): replace with `const impl From<u16>` when stable
17    pub const fn from_u16(n: u16) -> Self {
18        assert!(LIMBS >= 1, "number of limbs must be greater than zero");
19        let mut limbs = [Limb::ZERO; LIMBS];
20        limbs[0].0 = n as Word;
21        Self { limbs }
22    }
23
24    /// Create a [`Uint`] from a `u32` (const-friendly)
25    // TODO(tarcieri): replace with `const impl From<u32>` when stable
26    #[allow(trivial_numeric_casts)]
27    pub const fn from_u32(n: u32) -> Self {
28        assert!(LIMBS >= 1, "number of limbs must be greater than zero");
29        let mut limbs = [Limb::ZERO; LIMBS];
30        limbs[0].0 = n as Word;
31        Self { limbs }
32    }
33
34    /// Create a [`Uint`] from a `u64` (const-friendly)
35    // TODO(tarcieri): replace with `const impl From<u64>` when stable
36    #[cfg(target_pointer_width = "32")]
37    pub const fn from_u64(n: u64) -> Self {
38        assert!(LIMBS >= 2, "number of limbs must be two or greater");
39        let mut limbs = [Limb::ZERO; LIMBS];
40        limbs[0].0 = (n & 0xFFFFFFFF) as u32;
41        limbs[1].0 = (n >> 32) as u32;
42        Self { limbs }
43    }
44
45    /// Create a [`Uint`] from a `u64` (const-friendly)
46    // TODO(tarcieri): replace with `const impl From<u64>` when stable
47    #[cfg(target_pointer_width = "64")]
48    pub const fn from_u64(n: u64) -> Self {
49        assert!(LIMBS >= 1, "number of limbs must be greater than zero");
50        let mut limbs = [Limb::ZERO; LIMBS];
51        limbs[0].0 = n;
52        Self { limbs }
53    }
54
55    /// Create a [`Uint`] from a `u128` (const-friendly)
56    // TODO(tarcieri): replace with `const impl From<u128>` when stable
57    pub const fn from_u128(n: u128) -> Self {
58        assert!(
59            LIMBS >= 16 / Limb::BYTES,
60            "number of limbs must be greater than zero"
61        );
62
63        let lo = U64::from_u64((n & 0xffff_ffff_ffff_ffff) as u64);
64        let hi = U64::from_u64((n >> 64) as u64);
65
66        let mut limbs = [Limb::ZERO; LIMBS];
67
68        let mut i = 0;
69        while i < lo.limbs.len() {
70            limbs[i] = lo.limbs[i];
71            i += 1;
72        }
73
74        let mut j = 0;
75        while j < hi.limbs.len() {
76            limbs[i + j] = hi.limbs[j];
77            j += 1;
78        }
79
80        Self { limbs }
81    }
82
83    /// Create a [`Uint`] from a `Word` (const-friendly)
84    // TODO(tarcieri): replace with `const impl From<Word>` when stable
85    pub const fn from_word(n: Word) -> Self {
86        assert!(LIMBS >= 1, "number of limbs must be greater than zero");
87        let mut limbs = [Limb::ZERO; LIMBS];
88        limbs[0].0 = n;
89        Self { limbs }
90    }
91
92    /// Create a [`Uint`] from a `WideWord` (const-friendly)
93    // TODO(tarcieri): replace with `const impl From<WideWord>` when stable
94    pub const fn from_wide_word(n: WideWord) -> Self {
95        assert!(LIMBS >= 2, "number of limbs must be two or greater");
96        let mut limbs = [Limb::ZERO; LIMBS];
97        limbs[0].0 = n as Word;
98        limbs[1].0 = (n >> Limb::BITS) as Word;
99        Self { limbs }
100    }
101}
102
103impl<const LIMBS: usize> From<u8> for Uint<LIMBS> {
104    fn from(n: u8) -> Self {
105        // TODO(tarcieri): const where clause when possible
106        debug_assert!(LIMBS > 0, "limbs must be non-zero");
107        Self::from_u8(n)
108    }
109}
110
111impl<const LIMBS: usize> From<u16> for Uint<LIMBS> {
112    fn from(n: u16) -> Self {
113        // TODO(tarcieri): const where clause when possible
114        debug_assert!(LIMBS > 0, "limbs must be non-zero");
115        Self::from_u16(n)
116    }
117}
118
119impl<const LIMBS: usize> From<u32> for Uint<LIMBS> {
120    fn from(n: u32) -> Self {
121        // TODO(tarcieri): const where clause when possible
122        debug_assert!(LIMBS > 0, "limbs must be non-zero");
123        Self::from_u32(n)
124    }
125}
126
127impl<const LIMBS: usize> From<u64> for Uint<LIMBS> {
128    fn from(n: u64) -> Self {
129        // TODO(tarcieri): const where clause when possible
130        debug_assert!(LIMBS >= 8 / Limb::BYTES, "not enough limbs");
131        Self::from_u64(n)
132    }
133}
134
135impl<const LIMBS: usize> From<u128> for Uint<LIMBS> {
136    fn from(n: u128) -> Self {
137        // TODO(tarcieri): const where clause when possible
138        debug_assert!(LIMBS >= 16 / Limb::BYTES, "not enough limbs");
139        Self::from_u128(n)
140    }
141}
142
143#[cfg(target_pointer_width = "32")]
144impl From<U64> for u64 {
145    fn from(n: U64) -> u64 {
146        (n.limbs[0].0 as u64) | ((n.limbs[1].0 as u64) << 32)
147    }
148}
149
150#[cfg(target_pointer_width = "64")]
151impl From<U64> for u64 {
152    fn from(n: U64) -> u64 {
153        n.limbs[0].into()
154    }
155}
156
157impl From<U128> for u128 {
158    fn from(n: U128) -> u128 {
159        let mut i = U128::LIMBS - 1;
160        let mut res = n.limbs[i].0 as u128;
161        while i > 0 {
162            i -= 1;
163            res = (res << Limb::BITS) | (n.limbs[i].0 as u128);
164        }
165        res
166    }
167}
168
169impl<const LIMBS: usize> From<[Word; LIMBS]> for Uint<LIMBS> {
170    fn from(arr: [Word; LIMBS]) -> Self {
171        Self::from_words(arr)
172    }
173}
174
175impl<const LIMBS: usize> From<Uint<LIMBS>> for [Word; LIMBS] {
176    fn from(n: Uint<LIMBS>) -> [Word; LIMBS] {
177        *n.as_ref()
178    }
179}
180
181impl<const LIMBS: usize> From<[Limb; LIMBS]> for Uint<LIMBS> {
182    fn from(limbs: [Limb; LIMBS]) -> Self {
183        Self { limbs }
184    }
185}
186
187impl<const LIMBS: usize> From<Uint<LIMBS>> for [Limb; LIMBS] {
188    fn from(n: Uint<LIMBS>) -> [Limb; LIMBS] {
189        n.limbs
190    }
191}
192
193impl<const LIMBS: usize> From<Limb> for Uint<LIMBS> {
194    fn from(limb: Limb) -> Self {
195        limb.0.into()
196    }
197}
198
199impl<const L: usize, const H: usize, const LIMBS: usize> From<(Uint<L>, Uint<H>)> for Uint<LIMBS>
200where
201    Uint<L>: ConcatMixed<Uint<H>, MixedOutput = Uint<LIMBS>>,
202{
203    fn from(nums: (Uint<L>, Uint<H>)) -> Uint<LIMBS> {
204        nums.0.concat_mixed(&nums.1)
205    }
206}
207
208impl<const L: usize, const H: usize, const LIMBS: usize> From<&(Uint<L>, Uint<H>)> for Uint<LIMBS>
209where
210    Uint<L>: ConcatMixed<Uint<H>, MixedOutput = Uint<LIMBS>>,
211{
212    fn from(nums: &(Uint<L>, Uint<H>)) -> Uint<LIMBS> {
213        nums.0.concat_mixed(&nums.1)
214    }
215}
216
217impl<const L: usize, const H: usize, const LIMBS: usize> From<Uint<LIMBS>> for (Uint<L>, Uint<H>)
218where
219    Uint<LIMBS>: SplitMixed<Uint<L>, Uint<H>>,
220{
221    fn from(num: Uint<LIMBS>) -> (Uint<L>, Uint<H>) {
222        num.split_mixed()
223    }
224}
225
226impl<const LIMBS: usize, const LIMBS2: usize> From<&Uint<LIMBS>> for Uint<LIMBS2> {
227    fn from(num: &Uint<LIMBS>) -> Uint<LIMBS2> {
228        num.resize()
229    }
230}
231
232#[cfg(test)]
233mod tests {
234    use crate::{Limb, Word, U128};
235
236    #[cfg(target_pointer_width = "32")]
237    use crate::U64 as UintEx;
238
239    #[cfg(target_pointer_width = "64")]
240    use crate::U128 as UintEx;
241
242    #[test]
243    fn from_u8() {
244        let n = UintEx::from(42u8);
245        assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]);
246    }
247
248    #[test]
249    fn from_u16() {
250        let n = UintEx::from(42u16);
251        assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]);
252    }
253
254    #[test]
255    fn from_u64() {
256        let n = UintEx::from(42u64);
257        assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]);
258    }
259
260    #[test]
261    fn from_u128() {
262        let n = U128::from(42u128);
263        assert_eq!(&n.as_limbs()[..2], &[Limb(42), Limb(0)]);
264        assert_eq!(u128::from(n), 42u128);
265    }
266
267    #[test]
268    fn array_round_trip() {
269        let arr1 = [1, 2];
270        let n = UintEx::from(arr1);
271        let arr2: [Word; 2] = n.into();
272        assert_eq!(arr1, arr2);
273    }
274}