Skip to main content

crypto_bigint/uint/
array.rs

1//! `hybrid-array` integration with `Uint`.
2// TODO(tarcieri): completely phase out `hybrid-array` when const generics are powerful enough
3
4use crate::{ArrayDecoding, ArrayEncoding, ByteArray, EncodedUint, Limb};
5use hybrid_array::{Array, ArrayN, typenum};
6
7macro_rules! impl_uint_array_encoding {
8    ($(($uint:ident, $bytes:path)),+) => {
9        $(
10            use crate::$uint;
11
12            impl ArrayEncoding for $uint {
13                type ByteSize = $bytes;
14
15                #[inline]
16                fn from_be_byte_array(bytes: ByteArray<Self>) -> Self {
17                    Self::from_be_slice(&bytes)
18                }
19
20                #[inline]
21                fn from_le_byte_array(bytes: ByteArray<Self>) -> Self {
22                    Self::from_le_slice(&bytes)
23                }
24
25                #[inline]
26                fn to_be_byte_array(&self) -> ByteArray<Self> {
27                    let mut result = Array::default();
28                    self.write_be_bytes(&mut result);
29                    result
30                }
31
32                #[inline]
33                fn to_le_byte_array(&self) -> ByteArray<Self> {
34                    let mut result = Array::default();
35                    self.write_le_bytes(&mut result);
36                    result
37                }
38            }
39
40            impl ArrayDecoding for Array<u8, $bytes> {
41                type Output = $uint;
42
43                fn into_uint_be(self) -> Self::Output {
44                    Self::Output::from_be_byte_array(self)
45                }
46
47                fn into_uint_le(self) -> Self::Output {
48                    Self::Output::from_le_byte_array(self)
49                }
50            }
51
52            impl From<EncodedUint<{ $uint::LIMBS }>> for ArrayN<u8, { $uint::LIMBS * Limb::BYTES }> {
53                #[inline]
54                fn from(input: EncodedUint<{ $uint::LIMBS }>) -> Self {
55                    let mut output = Self::default();
56                    output.as_mut_slice().copy_from_slice(input.as_ref());
57                    output
58                }
59            }
60
61            impl From<ArrayN<u8, { $uint::LIMBS * Limb::BYTES }>> for EncodedUint< { $uint::LIMBS }> {
62                #[inline]
63                fn from(input: ArrayN<u8, { $uint::LIMBS * Limb::BYTES }>) -> Self {
64                    let mut output = Self::default();
65                    output.as_mut().copy_from_slice(input.as_ref());
66                    output
67                }
68            }
69        )+
70     };
71}
72
73// TODO(tarcieri): use `generic_const_exprs` when stable to make generic around bits.
74impl_uint_array_encoding! {
75    (U64, typenum::U8),
76    (U128, typenum::U16),
77    (U192, typenum::U24),
78    (U256, typenum::U32),
79    (U384, typenum::U48),
80    (U448, typenum::U56),
81    (U512, typenum::U64),
82    (U576, typenum::U72),
83    (U768, typenum::U96),
84    (U832, typenum::U104),
85    (U896, typenum::U112),
86    (U1024, typenum::U128),
87    (U1536, typenum::U192),
88    (U1792, typenum::U224),
89    (U2048, typenum::U256),
90    (U3072, typenum::U384),
91    (U3584, typenum::U448),
92    (U4096, typenum::U512),
93    (U6144, typenum::U768),
94    (U8192, typenum::U1024)
95}
96
97cpubits::cpubits! {
98    32 => {
99        impl_uint_array_encoding! {
100            (U224, typenum::U28), // For NIST P-224
101            (U544, typenum::U68)  // For NIST P-521
102        }
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use crate::{ArrayDecoding, ArrayEncoding, Limb};
109    use hex_literal::hex;
110
111    cpubits::cpubits! {
112        32 => { use crate::U64 as UintEx; }
113        64 => { use crate::U128 as UintEx; }
114    }
115
116    /// Byte array that corresponds to `UintEx`
117    type ByteArray = crate::ByteArray<UintEx>;
118
119    cpubits::cpubits! {
120        32 => {
121            #[test]
122            fn from_be_byte_array() {
123                let n = UintEx::from_be_byte_array(hex!("0011223344556677").into());
124                assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]);
125            }
126
127            #[test]
128            fn from_le_byte_array() {
129                let n = UintEx::from_le_byte_array(hex!("7766554433221100").into());
130                assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]);
131            }
132
133            #[test]
134            fn to_be_byte_array() {
135                let expected_bytes = ByteArray::from(hex!("0011223344556677"));
136                let actual_bytes = UintEx::from_be_byte_array(expected_bytes).to_be_byte_array();
137                assert_eq!(expected_bytes, actual_bytes);
138            }
139
140            #[test]
141            fn to_le_byte_array() {
142                let expected_bytes = ByteArray::from(hex!("7766554433221100"));
143                let actual_bytes = UintEx::from_le_byte_array(expected_bytes).to_le_byte_array();
144                assert_eq!(expected_bytes, actual_bytes);
145            }
146
147            #[test]
148            fn into_uint_be() {
149                let expected_bytes = ByteArray::from(hex!("0011223344556677"));
150                let actual_bytes = expected_bytes.into_uint_be().to_be_byte_array();
151                assert_eq!(expected_bytes, actual_bytes);
152            }
153
154            #[test]
155            fn into_uint_le() {
156                let expected_bytes = ByteArray::from(hex!("7766554433221100"));
157                let actual_bytes = expected_bytes.into_uint_le().to_le_byte_array();
158                assert_eq!(expected_bytes, actual_bytes);
159            }
160        }
161        64 => {
162            #[test]
163            fn from_be_byte_array() {
164                let n = UintEx::from_be_byte_array(hex!("00112233445566778899aabbccddeeff").into());
165                assert_eq!(
166                    n.as_limbs(),
167                    &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
168                );
169            }
170
171            #[test]
172            fn from_le_byte_array() {
173                let n = UintEx::from_le_byte_array(hex!("ffeeddccbbaa99887766554433221100").into());
174                assert_eq!(
175                    n.as_limbs(),
176                    &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
177                );
178            }
179
180            #[test]
181            fn to_be_byte_array() {
182                let expected_bytes = ByteArray::from(hex!("00112233445566778899aabbccddeeff"));
183                let actual_bytes = UintEx::from_be_byte_array(expected_bytes).to_be_byte_array();
184                assert_eq!(expected_bytes, actual_bytes);
185            }
186
187            #[test]
188            fn to_le_byte_array() {
189                let expected_bytes = ByteArray::from(hex!("ffeeddccbbaa99887766554433221100"));
190                let actual_bytes = UintEx::from_le_byte_array(expected_bytes).to_le_byte_array();
191                assert_eq!(expected_bytes, actual_bytes);
192            }
193
194            #[test]
195            fn into_uint_be() {
196                let expected_bytes = ByteArray::from(hex!("00112233445566778899aabbccddeeff"));
197                let actual_bytes = expected_bytes.into_uint_be().to_be_byte_array();
198                assert_eq!(expected_bytes, actual_bytes);
199            }
200
201            #[test]
202            fn into_uint_le() {
203                let expected_bytes = ByteArray::from(hex!("ffeeddccbbaa99887766554433221100"));
204                let actual_bytes = expected_bytes.into_uint_le().to_le_byte_array();
205                assert_eq!(expected_bytes, actual_bytes);
206            }
207        }
208    }
209
210    #[allow(clippy::cast_possible_truncation)]
211    mod encoded_uint {
212        const LIMBS: usize = 4;
213        const BYTES: usize = crate::Limb::BYTES * LIMBS;
214
215        type Array = hybrid_array::ArrayN<u8, { BYTES }>;
216        type EncodedUint = crate::EncodedUint<LIMBS>;
217
218        const ARRAY: Array = {
219            let mut i = 0;
220            let mut ret = [0u8; BYTES];
221            while i < BYTES {
222                ret[i] = i as u8;
223                i += 1;
224            }
225            hybrid_array::Array(ret)
226        };
227
228        #[test]
229        fn from_impls_for_encoded_uint() {
230            let encoded_uint = EncodedUint::from(ARRAY);
231            assert_eq!(encoded_uint.as_ref(), ARRAY.as_slice());
232
233            let array = Array::from(encoded_uint);
234            assert_eq!(array, ARRAY);
235        }
236    }
237}