@@ -10,14 +10,11 @@ mod rlp;
1010use alloc:: { string:: String , vec:: Vec } ;
1111
1212use super :: Uint ;
13- use crate :: { DecodeError , Limb , Word } ;
13+ use crate :: { DecodeError , Encoding , Limb , Word } ;
1414
1515#[ cfg( feature = "alloc" ) ]
1616use crate :: { ConstChoice , NonZero , Reciprocal , UintRef , WideWord } ;
1717
18- #[ cfg( feature = "hybrid-array" ) ]
19- use crate :: Encoding ;
20-
2118#[ cfg( feature = "alloc" ) ]
2219const RADIX_ENCODING_LIMBS_LARGE : usize = 16 ;
2320#[ cfg( feature = "alloc" ) ]
@@ -204,58 +201,132 @@ impl<const LIMBS: usize> Uint<LIMBS> {
204201 let mut buf = * self ;
205202 radix_encode_limbs_mut_to_string ( radix, buf. as_mut_uint_ref ( ) )
206203 }
204+
205+ /// Serialize as big endian bytes.
206+ pub const fn to_be_bytes ( & self ) -> EncodedUint < LIMBS > {
207+ EncodedUint :: new_be ( self )
208+ }
209+
210+ /// Serialize as little endian bytes.
211+ pub const fn to_le_bytes ( & self ) -> EncodedUint < LIMBS > {
212+ EncodedUint :: new_le ( self )
213+ }
207214}
208215
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" ) ;
216+ /// [`Uint`] encoded as bytes.
217+ // Until const generic expressions are stable, we cannot statically declare a `u8` array
218+ // of the size `LIMBS * Limb::BYTES`.
219+ // So instead we use the array of words, and treat it as an array of bytes.
220+ // It's a little hacky, but it works, because the array is guaranteed to be contiguous.
221+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
222+ pub struct EncodedUint < const LIMBS : usize > ( [ Word ; LIMBS ] ) ;
223+
224+ impl < const LIMBS : usize > Default for EncodedUint < LIMBS > {
225+ fn default ( ) -> Self {
226+ Self ( [ 0 ; LIMBS ] )
215227 }
228+ }
216229
217- let mut ret = [ 0u8 ; BYTES ] ;
218- let mut i = 0 ;
230+ impl < const LIMBS : usize > EncodedUint < LIMBS > {
231+ const fn new_le ( value : & Uint < LIMBS > ) -> Self {
232+ let mut buffer = [ 0 ; LIMBS ] ;
233+ let mut i = 0 ;
219234
220- while i < LIMBS {
221- let limb_bytes = uint. limbs [ LIMBS - i - 1 ] . 0 . to_be_bytes ( ) ;
222- let mut j = 0 ;
235+ while i < LIMBS {
236+ let src_bytes = & value. limbs [ i] . 0 . to_le_bytes ( ) ;
223237
224- while j < Limb :: BYTES {
225- ret[ i * Limb :: BYTES + j] = limb_bytes[ j] ;
226- j += 1 ;
238+ // We could cast the whole `buffer` to bytes at once,
239+ // but IndexMut does not work in const context.
240+ let dst_bytes: & mut [ u8 ] =
241+ bytemuck:: must_cast_slice_mut ( core:: slice:: from_mut ( & mut buffer[ i] ) ) ;
242+
243+ // `copy_from_slice` can be used here when MSRV moves past 1.87
244+ let mut j = 0 ;
245+ while j < Limb :: BYTES {
246+ dst_bytes[ j] = src_bytes[ j] ;
247+ j += 1 ;
248+ }
249+
250+ i += 1 ;
227251 }
252+ Self ( buffer)
253+ }
254+
255+ const fn new_be ( value : & Uint < LIMBS > ) -> Self {
256+ let mut buffer = [ 0 ; LIMBS ] ;
257+ let mut i = 0 ;
258+ while i < LIMBS {
259+ let src_bytes = & value. limbs [ i] . 0 . to_be_bytes ( ) ;
260+
261+ // We could cast the whole `buffer` to bytes at once,
262+ // but IndexMut does not work in const context.
263+ let dst_bytes: & mut [ u8 ] =
264+ bytemuck:: must_cast_slice_mut ( core:: slice:: from_mut ( & mut buffer[ LIMBS - 1 - i] ) ) ;
265+
266+ // `copy_from_slice` can be used here when MSRV moves past 1.87
267+ let mut j = 0 ;
268+ while j < Limb :: BYTES {
269+ dst_bytes[ j] = src_bytes[ j] ;
270+ j += 1 ;
271+ }
228272
229- i += 1 ;
273+ i += 1 ;
274+ }
275+ Self ( buffer)
230276 }
277+ }
231278
232- ret
279+ impl < const LIMBS : usize > AsRef < [ u8 ] > for EncodedUint < LIMBS > {
280+ fn as_ref ( & self ) -> & [ u8 ] {
281+ bytemuck:: must_cast_slice ( & self . 0 )
282+ }
233283}
234284
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" ) ;
285+ impl < const LIMBS : usize > AsMut < [ u8 ] > for EncodedUint < LIMBS > {
286+ fn as_mut ( & mut self ) -> & mut [ u8 ] {
287+ bytemuck:: must_cast_slice_mut ( & mut self . 0 )
241288 }
289+ }
242290
243- let mut ret = [ 0u8 ; BYTES ] ;
244- let mut i = 0 ;
291+ /// Returned if an object cannot be instantiated from the given byte slice.
292+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
293+ pub struct TryFromSliceError ;
245294
246- while i < LIMBS {
247- let limb_bytes = uint. limbs [ i] . 0 . to_le_bytes ( ) ;
248- let mut j = 0 ;
295+ impl < ' a , const LIMBS : usize > TryFrom < & ' a [ u8 ] > for EncodedUint < LIMBS > {
296+ type Error = TryFromSliceError ;
249297
250- while j < Limb :: BYTES {
251- ret [ i * Limb :: BYTES + j ] = limb_bytes [ j ] ;
252- j += 1 ;
298+ fn try_from ( bytes : & ' a [ u8 ] ) -> Result < Self , Self :: Error > {
299+ if bytes . len ( ) != Uint :: < LIMBS > :: BYTES {
300+ return Err ( TryFromSliceError ) ;
253301 }
302+ let mut result = Self :: default ( ) ;
303+ result. as_mut ( ) . copy_from_slice ( bytes) ;
304+ Ok ( result)
305+ }
306+ }
307+
308+ impl < const LIMBS : usize > Encoding for Uint < LIMBS > {
309+ type Repr = EncodedUint < LIMBS > ;
310+
311+ #[ inline]
312+ fn from_be_bytes ( bytes : Self :: Repr ) -> Self {
313+ Self :: from_be_slice ( bytes. as_ref ( ) )
314+ }
254315
255- i += 1 ;
316+ #[ inline]
317+ fn from_le_bytes ( bytes : Self :: Repr ) -> Self {
318+ Self :: from_le_slice ( bytes. as_ref ( ) )
256319 }
257320
258- ret
321+ #[ inline]
322+ fn to_be_bytes ( & self ) -> Self :: Repr {
323+ self . to_be_bytes ( )
324+ }
325+
326+ #[ inline]
327+ fn to_le_bytes ( & self ) -> Self :: Repr {
328+ self . to_le_bytes ( )
329+ }
259330}
260331
261332/// Decode a single nibble of upper or lower hex
@@ -1057,7 +1128,7 @@ mod tests {
10571128 let n = UintEx :: from_be_hex ( "0011223344556677" ) ;
10581129
10591130 let bytes = n. to_be_bytes ( ) ;
1060- assert_eq ! ( bytes, hex!( "0011223344556677" ) ) ;
1131+ assert_eq ! ( bytes. as_ref ( ) , hex!( "0011223344556677" ) ) ;
10611132
10621133 #[ cfg( feature = "der" ) ]
10631134 assert_eq ! ( super :: der:: count_der_be_bytes( & n. limbs) , 7 ) ;
@@ -1069,7 +1140,7 @@ mod tests {
10691140 let n = UintEx :: from_be_hex ( "00112233445566778899aabbccddeeff" ) ;
10701141
10711142 let bytes = n. to_be_bytes ( ) ;
1072- assert_eq ! ( bytes, hex!( "00112233445566778899aabbccddeeff" ) ) ;
1143+ assert_eq ! ( bytes. as_ref ( ) , hex!( "00112233445566778899aabbccddeeff" ) ) ;
10731144
10741145 #[ cfg( feature = "der" ) ]
10751146 assert_eq ! ( super :: der:: count_der_be_bytes( & n. limbs) , 15 ) ;
0 commit comments