@@ -6,18 +6,17 @@ mod der;
66#[ cfg( feature = "rlp" ) ]
77mod rlp;
88
9+ use core:: fmt;
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,140 @@ 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+ }
207216}
208217
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" ) ;
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+ impl < const LIMBS : usize > Default for EncodedUint < LIMBS > {
227+ fn default ( ) -> Self {
228+ Self ( [ 0 ; LIMBS ] )
215229 }
230+ }
216231
217- let mut ret = [ 0u8 ; BYTES ] ;
218- let mut i = 0 ;
232+ impl < const LIMBS : usize > EncodedUint < LIMBS > {
233+ const fn new_le ( value : & Uint < LIMBS > ) -> Self {
234+ let mut buffer = [ 0 ; LIMBS ] ;
235+ let mut i = 0 ;
219236
220- while i < LIMBS {
221- let limb_bytes = uint. limbs [ LIMBS - i - 1 ] . 0 . to_be_bytes ( ) ;
222- let mut j = 0 ;
237+ while i < LIMBS {
238+ let src_bytes = & value. limbs [ i] . 0 . to_le_bytes ( ) ;
223239
224- while j < Limb :: BYTES {
225- ret[ i * Limb :: BYTES + j] = limb_bytes[ j] ;
226- j += 1 ;
240+ // We could cast the whole `buffer` to bytes at once,
241+ // but IndexMut does not work in const context.
242+ let dst_bytes: & mut [ u8 ] =
243+ bytemuck:: must_cast_slice_mut ( core:: slice:: from_mut ( & mut buffer[ i] ) ) ;
244+
245+ // `copy_from_slice` can be used here when MSRV moves past 1.87
246+ let mut j = 0 ;
247+ while j < Limb :: BYTES {
248+ dst_bytes[ j] = src_bytes[ j] ;
249+ j += 1 ;
250+ }
251+
252+ i += 1 ;
227253 }
254+ Self ( buffer)
255+ }
228256
229- i += 1 ;
257+ const fn new_be ( value : & Uint < LIMBS > ) -> Self {
258+ let mut buffer = [ 0 ; LIMBS ] ;
259+ let mut i = 0 ;
260+ while i < LIMBS {
261+ let src_bytes = & value. limbs [ i] . 0 . to_be_bytes ( ) ;
262+
263+ // We could cast the whole `buffer` to bytes at once,
264+ // but IndexMut does not work in const context.
265+ let dst_bytes: & mut [ u8 ] =
266+ bytemuck:: must_cast_slice_mut ( core:: slice:: from_mut ( & mut buffer[ LIMBS - 1 - i] ) ) ;
267+
268+ // `copy_from_slice` can be used here when MSRV moves past 1.87
269+ let mut j = 0 ;
270+ while j < Limb :: BYTES {
271+ dst_bytes[ j] = src_bytes[ j] ;
272+ j += 1 ;
273+ }
274+
275+ i += 1 ;
276+ }
277+ Self ( buffer)
230278 }
279+ }
231280
232- ret
281+ impl < const LIMBS : usize > AsRef < [ u8 ] > for EncodedUint < LIMBS > {
282+ fn as_ref ( & self ) -> & [ u8 ] {
283+ bytemuck:: must_cast_slice ( & self . 0 )
284+ }
233285}
234286
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" ) ;
287+ impl < const LIMBS : usize > AsMut < [ u8 ] > for EncodedUint < LIMBS > {
288+ fn as_mut ( & mut self ) -> & mut [ u8 ] {
289+ bytemuck:: must_cast_slice_mut ( & mut self . 0 )
241290 }
291+ }
242292
243- let mut ret = [ 0u8 ; BYTES ] ;
244- let mut i = 0 ;
293+ /// Returned if an object cannot be instantiated from the given byte slice.
294+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
295+ pub struct TryFromSliceError ;
245296
246- while i < LIMBS {
247- let limb_bytes = uint. limbs [ i] . 0 . to_le_bytes ( ) ;
248- let mut j = 0 ;
297+ impl fmt:: Display for TryFromSliceError {
298+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> Result < ( ) , fmt:: Error > {
299+ write ! ( f, "TryFromSliceError" )
300+ }
301+ }
249302
250- while j < Limb :: BYTES {
251- ret[ i * Limb :: BYTES + j] = limb_bytes[ j] ;
252- j += 1 ;
303+ impl core:: error:: Error for TryFromSliceError { }
304+
305+ impl < ' a , const LIMBS : usize > TryFrom < & ' a [ u8 ] > for EncodedUint < LIMBS > {
306+ type Error = TryFromSliceError ;
307+
308+ fn try_from ( bytes : & ' a [ u8 ] ) -> Result < Self , Self :: Error > {
309+ if bytes. len ( ) != Uint :: < LIMBS > :: BYTES {
310+ return Err ( TryFromSliceError ) ;
253311 }
312+ let mut result = Self :: default ( ) ;
313+ result. as_mut ( ) . copy_from_slice ( bytes) ;
314+ Ok ( result)
315+ }
316+ }
317+
318+ impl < const LIMBS : usize > Encoding for Uint < LIMBS > {
319+ type Repr = EncodedUint < LIMBS > ;
320+
321+ #[ inline]
322+ fn from_be_bytes ( bytes : Self :: Repr ) -> Self {
323+ Self :: from_be_slice ( bytes. as_ref ( ) )
324+ }
254325
255- i += 1 ;
326+ #[ inline]
327+ fn from_le_bytes ( bytes : Self :: Repr ) -> Self {
328+ Self :: from_le_slice ( bytes. as_ref ( ) )
329+ }
330+
331+ #[ inline]
332+ fn to_be_bytes ( & self ) -> Self :: Repr {
333+ self . to_be_bytes ( )
256334 }
257335
258- ret
336+ #[ inline]
337+ fn to_le_bytes ( & self ) -> Self :: Repr {
338+ self . to_le_bytes ( )
339+ }
259340}
260341
261342/// Decode a single nibble of upper or lower hex
@@ -1057,7 +1138,7 @@ mod tests {
10571138 let n = UintEx :: from_be_hex ( "0011223344556677" ) ;
10581139
10591140 let bytes = n. to_be_bytes ( ) ;
1060- assert_eq ! ( bytes, hex!( "0011223344556677" ) ) ;
1141+ assert_eq ! ( bytes. as_ref ( ) , hex!( "0011223344556677" ) ) ;
10611142
10621143 #[ cfg( feature = "der" ) ]
10631144 assert_eq ! ( super :: der:: count_der_be_bytes( & n. limbs) , 7 ) ;
@@ -1069,7 +1150,7 @@ mod tests {
10691150 let n = UintEx :: from_be_hex ( "00112233445566778899aabbccddeeff" ) ;
10701151
10711152 let bytes = n. to_be_bytes ( ) ;
1072- assert_eq ! ( bytes, hex!( "00112233445566778899aabbccddeeff" ) ) ;
1153+ assert_eq ! ( bytes. as_ref ( ) , hex!( "00112233445566778899aabbccddeeff" ) ) ;
10731154
10741155 #[ cfg( feature = "der" ) ]
10751156 assert_eq ! ( super :: der:: count_der_be_bytes( & n. limbs) , 15 ) ;
0 commit comments