@@ -6,18 +6,17 @@ mod der;
66#[ cfg( feature = "rlp" ) ]
77mod rlp;
88
9+ use core:: { fmt, ops:: Deref } ;
10+
911#[ cfg( feature = "alloc" ) ]
1012use alloc:: { string:: String , vec:: Vec } ;
1113
1214use super :: Uint ;
13- use crate :: { DecodeError , Limb , Word } ;
15+ use crate :: { DecodeError , Encoding , Limb , Word } ;
1416
1517#[ cfg( feature = "alloc" ) ]
1618use crate :: { ConstChoice , NonZero , Reciprocal , UintRef , WideWord } ;
1719
18- #[ cfg( feature = "hybrid-array" ) ]
19- use crate :: Encoding ;
20-
2120#[ cfg( feature = "alloc" ) ]
2221const RADIX_ENCODING_LIMBS_LARGE : usize = 16 ;
2322#[ cfg( feature = "alloc" ) ]
@@ -204,58 +203,158 @@ impl<const LIMBS: usize> Uint<LIMBS> {
204203 let mut buf = * self ;
205204 radix_encode_limbs_mut_to_string ( radix, buf. as_mut_uint_ref ( ) )
206205 }
206+
207+ /// Serialize as big endian bytes.
208+ pub const fn to_be_bytes ( & self ) -> EncodedUint < LIMBS > {
209+ EncodedUint :: new_be ( self )
210+ }
211+
212+ /// Serialize as little endian bytes.
213+ pub const fn to_le_bytes ( & self ) -> EncodedUint < LIMBS > {
214+ EncodedUint :: new_le ( self )
215+ }
216+ }
217+
218+ /// [`Uint`] encoded as bytes.
219+ // Until const generic expressions are stable, we cannot statically declare a `u8` array
220+ // of the size `LIMBS * Limb::BYTES`.
221+ // So instead we use the array of words, and treat it as an array of bytes.
222+ // It's a little hacky, but it works, because the array is guaranteed to be contiguous.
223+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
224+ pub struct EncodedUint < const LIMBS : usize > ( [ Word ; LIMBS ] ) ;
225+
226+ #[ allow( unsafe_code) ]
227+ const fn cast_slice ( limbs : & [ Word ] ) -> & [ u8 ] {
228+ let new_len = size_of_val ( limbs) ;
229+ unsafe { core:: slice:: from_raw_parts ( limbs. as_ptr ( ) as * mut u8 , new_len) }
207230}
208231
209- /// Encode a [`Uint`] to a big endian byte array of the given size.
210- pub ( crate ) const fn uint_to_be_bytes < const LIMBS : usize , const BYTES : usize > (
211- uint : & Uint < LIMBS > ,
212- ) -> [ u8 ; BYTES ] {
213- if BYTES != LIMBS * Limb :: BYTES {
214- panic ! ( "BYTES != LIMBS * Limb::BYTES" ) ;
232+ #[ allow( unsafe_code) ]
233+ const fn cast_slice_mut ( limbs : & mut [ Word ] ) -> & mut [ u8 ] {
234+ let new_len = size_of_val ( limbs) ;
235+ unsafe { core:: slice:: from_raw_parts_mut ( limbs. as_mut_ptr ( ) as * mut u8 , new_len) }
236+ }
237+
238+ impl < const LIMBS : usize > EncodedUint < LIMBS > {
239+ const fn new_le ( value : & Uint < LIMBS > ) -> Self {
240+ let mut buffer = [ 0 ; LIMBS ] ;
241+ let mut i = 0 ;
242+
243+ while i < LIMBS {
244+ let src_bytes = & value. limbs [ i] . 0 . to_le_bytes ( ) ;
245+
246+ // We could cast the whole `buffer` to bytes at once,
247+ // but IndexMut does not work in const context.
248+ let dst_bytes: & mut [ u8 ] = cast_slice_mut ( core:: slice:: from_mut ( & mut buffer[ i] ) ) ;
249+
250+ // `copy_from_slice` can be used here when MSRV moves past 1.87
251+ let mut j = 0 ;
252+ while j < Limb :: BYTES {
253+ dst_bytes[ j] = src_bytes[ j] ;
254+ j += 1 ;
255+ }
256+
257+ i += 1 ;
258+ }
259+ Self ( buffer)
215260 }
216261
217- let mut ret = [ 0u8 ; BYTES ] ;
218- let mut i = 0 ;
262+ const fn new_be ( value : & Uint < LIMBS > ) -> Self {
263+ let mut buffer = [ 0 ; LIMBS ] ;
264+ let mut i = 0 ;
265+ while i < LIMBS {
266+ let src_bytes = & value. limbs [ i] . 0 . to_be_bytes ( ) ;
219267
220- while i < LIMBS {
221- let limb_bytes = uint. limbs [ LIMBS - i - 1 ] . 0 . to_be_bytes ( ) ;
222- let mut j = 0 ;
268+ // We could cast the whole `buffer` to bytes at once,
269+ // but IndexMut does not work in const context.
270+ let dst_bytes: & mut [ u8 ] =
271+ cast_slice_mut ( core:: slice:: from_mut ( & mut buffer[ LIMBS - 1 - i] ) ) ;
223272
224- while j < Limb :: BYTES {
225- ret[ i * Limb :: BYTES + j] = limb_bytes[ j] ;
226- j += 1 ;
273+ // `copy_from_slice` can be used here when MSRV moves past 1.87
274+ let mut j = 0 ;
275+ while j < Limb :: BYTES {
276+ dst_bytes[ j] = src_bytes[ j] ;
277+ j += 1 ;
278+ }
279+
280+ i += 1 ;
227281 }
282+ Self ( buffer)
283+ }
284+ }
228285
229- i += 1 ;
286+ impl < const LIMBS : usize > Default for EncodedUint < LIMBS > {
287+ fn default ( ) -> Self {
288+ Self ( [ 0 ; LIMBS ] )
230289 }
290+ }
231291
232- ret
292+ impl < const LIMBS : usize > AsRef < [ u8 ] > for EncodedUint < LIMBS > {
293+ fn as_ref ( & self ) -> & [ u8 ] {
294+ cast_slice ( & self . 0 )
295+ }
233296}
234297
235- /// Encode a [`Uint`] to a little endian byte array of the given size.
236- pub ( crate ) const fn uint_to_le_bytes < const LIMBS : usize , const BYTES : usize > (
237- uint : & Uint < LIMBS > ,
238- ) -> [ u8 ; BYTES ] {
239- if BYTES != LIMBS * Limb :: BYTES {
240- panic ! ( "BYTES != LIMBS * Limb::BYTES" ) ;
298+ impl < const LIMBS : usize > AsMut < [ u8 ] > for EncodedUint < LIMBS > {
299+ fn as_mut ( & mut self ) -> & mut [ u8 ] {
300+ cast_slice_mut ( & mut self . 0 )
241301 }
302+ }
242303
243- let mut ret = [ 0u8 ; BYTES ] ;
244- let mut i = 0 ;
304+ impl < const LIMBS : usize > Deref for EncodedUint < LIMBS > {
305+ type Target = [ u8 ] ;
306+ fn deref ( & self ) -> & Self :: Target {
307+ self . as_ref ( )
308+ }
309+ }
245310
246- while i < LIMBS {
247- let limb_bytes = uint . limbs [ i ] . 0 . to_le_bytes ( ) ;
248- let mut j = 0 ;
311+ /// Returned if an object cannot be instantiated from the given byte slice.
312+ # [ derive ( Clone , Copy , Debug , PartialEq , Eq ) ]
313+ pub struct TryFromSliceError ;
249314
250- while j < Limb :: BYTES {
251- ret[ i * Limb :: BYTES + j] = limb_bytes[ j] ;
252- j += 1 ;
315+ impl fmt:: Display for TryFromSliceError {
316+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> Result < ( ) , fmt:: Error > {
317+ write ! ( f, "TryFromSliceError" )
318+ }
319+ }
320+
321+ impl core:: error:: Error for TryFromSliceError { }
322+
323+ impl < ' a , const LIMBS : usize > TryFrom < & ' a [ u8 ] > for EncodedUint < LIMBS > {
324+ type Error = TryFromSliceError ;
325+
326+ fn try_from ( bytes : & ' a [ u8 ] ) -> Result < Self , Self :: Error > {
327+ if bytes. len ( ) != Uint :: < LIMBS > :: BYTES {
328+ return Err ( TryFromSliceError ) ;
253329 }
330+ let mut result = Self :: default ( ) ;
331+ result. as_mut ( ) . copy_from_slice ( bytes) ;
332+ Ok ( result)
333+ }
334+ }
335+
336+ impl < const LIMBS : usize > Encoding for Uint < LIMBS > {
337+ type Repr = EncodedUint < LIMBS > ;
338+
339+ #[ inline]
340+ fn from_be_bytes ( bytes : Self :: Repr ) -> Self {
341+ Self :: from_be_slice ( bytes. as_ref ( ) )
342+ }
254343
255- i += 1 ;
344+ #[ inline]
345+ fn from_le_bytes ( bytes : Self :: Repr ) -> Self {
346+ Self :: from_le_slice ( bytes. as_ref ( ) )
256347 }
257348
258- ret
349+ #[ inline]
350+ fn to_be_bytes ( & self ) -> Self :: Repr {
351+ self . to_be_bytes ( )
352+ }
353+
354+ #[ inline]
355+ fn to_le_bytes ( & self ) -> Self :: Repr {
356+ self . to_le_bytes ( )
357+ }
259358}
260359
261360/// Decode a single nibble of upper or lower hex
@@ -1057,7 +1156,7 @@ mod tests {
10571156 let n = UintEx :: from_be_hex ( "0011223344556677" ) ;
10581157
10591158 let bytes = n. to_be_bytes ( ) ;
1060- assert_eq ! ( bytes, hex!( "0011223344556677" ) ) ;
1159+ assert_eq ! ( bytes. as_ref ( ) , hex!( "0011223344556677" ) ) ;
10611160
10621161 #[ cfg( feature = "der" ) ]
10631162 assert_eq ! ( super :: der:: count_der_be_bytes( & n. limbs) , 7 ) ;
@@ -1069,7 +1168,7 @@ mod tests {
10691168 let n = UintEx :: from_be_hex ( "00112233445566778899aabbccddeeff" ) ;
10701169
10711170 let bytes = n. to_be_bytes ( ) ;
1072- assert_eq ! ( bytes, hex!( "00112233445566778899aabbccddeeff" ) ) ;
1171+ assert_eq ! ( bytes. as_ref ( ) , hex!( "00112233445566778899aabbccddeeff" ) ) ;
10731172
10741173 #[ cfg( feature = "der" ) ]
10751174 assert_eq ! ( super :: der:: count_der_be_bytes( & n. limbs) , 15 ) ;
0 commit comments