11//! Random number generator support
22
3- use super :: { Uint , Word } ;
4- use crate :: { Encoding , Limb , NonZero , Random , RandomBits , RandomBitsError , RandomMod , Zero } ;
3+ use super :: Uint ;
4+ use crate :: { Encoding , Limb , NonZero , Random , RandomBits , RandomBitsError , RandomMod } ;
55use rand_core:: { RngCore , TryRngCore } ;
66use subtle:: ConstantTimeLess ;
77
@@ -26,45 +26,26 @@ impl<const LIMBS: usize> Random for Uint<LIMBS> {
2626/// `rng.fill_bytes(&mut bytes[..i]); rng.fill_bytes(&mut bytes[i..])` constructs the same `bytes`,
2727/// as long as `i` is a multiple of `X`.
2828/// Note that the `TryRngCore` trait does _not_ require this behaviour from `rng`.
29- pub ( crate ) fn random_bits_core < R : TryRngCore + ?Sized > (
29+ pub ( crate ) fn random_bits_core < T , R : TryRngCore + ?Sized > (
3030 rng : & mut R ,
31- zeroed_limbs : & mut [ Limb ] ,
32- bit_length : u32 ,
33- ) -> Result < ( ) , RandomBitsError < R :: Error > > {
34- if bit_length == 0 {
31+ x : & mut T ,
32+ n_bits : u32 ,
33+ ) -> Result < ( ) , R :: Error >
34+ where
35+ T : Encoding ,
36+ {
37+ if n_bits == 0 {
3538 return Ok ( ( ) ) ;
3639 }
3740
38- let buffer: Word = 0 ;
39- let mut buffer = buffer. to_be_bytes ( ) ;
40-
41- let nonzero_limbs = bit_length. div_ceil ( Limb :: BITS ) as usize ;
42- let partial_limb = bit_length % Limb :: BITS ;
43- let mask = Word :: MAX >> ( ( Word :: BITS - partial_limb) % Word :: BITS ) ;
44-
45- for i in 0 ..nonzero_limbs - 1 {
46- rng. try_fill_bytes ( & mut buffer)
47- . map_err ( RandomBitsError :: RandCore ) ?;
48- zeroed_limbs[ i] = Limb ( Word :: from_le_bytes ( buffer) ) ;
49- }
41+ let n_bytes = n_bits. div_ceil ( u8:: BITS ) as usize ;
42+ let hi_mask = u8:: MAX >> ( ( u8:: BITS - ( n_bits % u8:: BITS ) ) % u8:: BITS ) ;
5043
51- // This algorithm should sample the same number of random bytes, regardless of the pointer width
52- // of the target platform. To this end, special attention has to be paid to the case where
53- // bit_length - 1 < 32 mod 64. Bit strings of that size can be represented using `2X+1` 32-bit
54- // words or `X+1` 64-bit words. Note that 64*(X+1) - 32*(2X+1) = 32. Hence, if we sample full
55- // words only, a 64-bit platform will sample 32 bits more than a 32-bit platform. We prevent
56- // this by forcing both platforms to only sample 4 bytes for the last word in this case.
57- let slice = if partial_limb > 0 && partial_limb <= 32 {
58- // Note: we do not have to zeroize the second half of the buffer, as the mask will take
59- // care of this in the end.
60- & mut buffer[ 0 ..4 ]
61- } else {
62- buffer. as_mut_slice ( )
63- } ;
64-
65- rng. try_fill_bytes ( slice)
66- . map_err ( RandomBitsError :: RandCore ) ?;
67- zeroed_limbs[ nonzero_limbs - 1 ] = Limb ( Word :: from_le_bytes ( buffer) & mask) ;
44+ let mut buffer = x. to_le_bytes ( ) ;
45+ let slice = buffer. as_mut ( ) ;
46+ rng. try_fill_bytes ( & mut slice[ ..n_bytes] ) ?;
47+ slice[ n_bytes - 1 ] &= hi_mask;
48+ * x = T :: from_le_bytes ( buffer) ;
6849
6950 Ok ( ( ) )
7051}
@@ -94,72 +75,46 @@ impl<const LIMBS: usize> RandomBits for Uint<LIMBS> {
9475 bits_precision,
9576 } ) ;
9677 }
97- let mut limbs = [ Limb :: ZERO ; LIMBS ] ;
98- random_bits_core ( rng, & mut limbs , bit_length) ?;
99- Ok ( Self :: from ( limbs ) )
78+ let mut x = Self :: ZERO ;
79+ random_bits_core ( rng, & mut x , bit_length) . map_err ( RandomBitsError :: RandCore ) ?;
80+ Ok ( x )
10081 }
10182}
10283
10384impl < const LIMBS : usize > RandomMod for Uint < LIMBS > {
10485 fn random_mod < R : RngCore + ?Sized > ( rng : & mut R , modulus : & NonZero < Self > ) -> Self {
105- let mut n = Self :: ZERO ;
106- let Ok ( ( ) ) = random_mod_core ( rng, & mut n , modulus, modulus. bits_vartime ( ) ) ;
107- n
86+ let mut x = Self :: ZERO ;
87+ let Ok ( ( ) ) = random_mod_core ( rng, & mut x , modulus, modulus. bits_vartime ( ) ) ;
88+ x
10889 }
10990
11091 fn try_random_mod < R : TryRngCore + ?Sized > (
11192 rng : & mut R ,
11293 modulus : & NonZero < Self > ,
11394 ) -> Result < Self , R :: Error > {
114- let mut n = Self :: ZERO ;
115- random_mod_core ( rng, & mut n , modulus, modulus. bits_vartime ( ) ) ?;
116- Ok ( n )
95+ let mut x = Self :: ZERO ;
96+ random_mod_core ( rng, & mut x , modulus, modulus. bits_vartime ( ) ) ?;
97+ Ok ( x )
11798 }
11899}
119100
120101/// Generic implementation of `random_mod` which can be shared with `BoxedUint`.
121102// TODO(tarcieri): obtain `n_bits` via a trait like `Integer`
122103pub ( super ) fn random_mod_core < T , R : TryRngCore + ?Sized > (
123104 rng : & mut R ,
124- n : & mut T ,
105+ x : & mut T ,
125106 modulus : & NonZero < T > ,
126107 n_bits : u32 ,
127108) -> Result < ( ) , R :: Error >
128109where
129- T : AsMut < [ Limb ] > + AsRef < [ Limb ] > + ConstantTimeLess + Zero ,
110+ T : Encoding + ConstantTimeLess ,
130111{
131- #[ cfg( target_pointer_width = "64" ) ]
132- let mut next_word = || rng. try_next_u64 ( ) ;
133- #[ cfg( target_pointer_width = "32" ) ]
134- let mut next_word = || rng. try_next_u32 ( ) ;
135-
136- let n_limbs = n_bits. div_ceil ( Limb :: BITS ) as usize ;
137-
138- let hi_word_modulus = modulus. as_ref ( ) . as_ref ( ) [ n_limbs - 1 ] . 0 ;
139- let mask = !0 >> hi_word_modulus. leading_zeros ( ) ;
140- let mut hi_word = next_word ( ) ? & mask;
141-
142112 loop {
143- while hi_word > hi_word_modulus {
144- hi_word = next_word ( ) ? & mask;
113+ random_bits_core ( rng, x, n_bits) ?;
114+ if x. ct_lt ( modulus) . into ( ) {
115+ return Ok ( ( ) ) ;
145116 }
146- // Set high limb
147- n. as_mut ( ) [ n_limbs - 1 ] = Limb :: from_le_bytes ( hi_word. to_le_bytes ( ) ) ;
148- // Set low limbs
149- for i in 0 ..n_limbs - 1 {
150- // Need to deserialize from little-endian to make sure that two 32-bit limbs
151- // deserialized sequentially are equal to one 64-bit limb produced from the same
152- // byte stream.
153- n. as_mut ( ) [ i] = Limb :: from_le_bytes ( next_word ( ) ?. to_le_bytes ( ) ) ;
154- }
155- // If the high limb is equal to the modulus' high limb, it's still possible
156- // that the full uint is too big so we check and repeat if it is.
157- if n. ct_lt ( modulus) . into ( ) {
158- break ;
159- }
160- hi_word = next_word ( ) ? & mask;
161117 }
162- Ok ( ( ) )
163118}
164119
165120#[ cfg( test) ]
@@ -269,7 +224,7 @@ mod tests {
269224
270225 let bit_length = 989 ;
271226 let mut val = U1024 :: ZERO ;
272- random_bits_core ( & mut rng, val. as_mut_limbs ( ) , bit_length) . expect ( "safe" ) ;
227+ random_bits_core ( & mut rng, & mut val, bit_length) . expect ( "safe" ) ;
273228
274229 assert_eq ! (
275230 val,
@@ -298,7 +253,7 @@ mod tests {
298253 for val in & mut vals {
299254 * val = U256 :: random_mod ( & mut rng, & modulus) ;
300255 }
301- let expected = [ 55 , 2172 , 1657 , 4668 , 7688 ] ;
256+ let expected = [ 55 , 3378 , 2172 , 1657 , 5323 ] ;
302257 for ( want, got) in expected. into_iter ( ) . zip ( vals. into_iter ( ) ) {
303258 // assert_eq!(got.as_words()[0], want);
304259 assert_eq ! ( got, U256 :: from_u32( want) ) ;
@@ -309,7 +264,7 @@ mod tests {
309264 let val = U256 :: random_mod ( & mut rng, & modulus) ;
310265 assert_eq ! (
311266 val,
312- U256 :: from_be_hex( "C54302F2EB1E2F69C3B919AE0D16DF2259CD1A8A9B8EA8E0862878227D4B40A3 " )
267+ U256 :: from_be_hex( "E17653A37F1BCC44277FA208E6B31E08CDC4A23A7E88E660EF781C7DD2D368BA " )
313268 ) ;
314269
315270 let mut state = [ 0u8 ; 16 ] ;
@@ -318,7 +273,7 @@ mod tests {
318273 assert_eq ! (
319274 state,
320275 [
321- 71 , 204 , 238 , 147 , 198 , 196 , 132 , 164 , 240 , 211 , 223 , 12 , 36 , 189 , 139 , 48 ,
276+ 105 , 47 , 30 , 235 , 242 , 2 , 67 , 197 , 163 , 64 , 75 , 125 , 34 , 120 , 40 , 134 ,
322277 ] ,
323278 ) ;
324279 }
@@ -333,9 +288,8 @@ mod tests {
333288 let mut rng = get_four_sequential_rng ( ) ;
334289 let mut first = U1024 :: ZERO ;
335290 let mut second = U1024 :: ZERO ;
336- random_bits_core ( & mut rng, first. as_mut_limbs ( ) , bit_length) . expect ( "safe" ) ;
337- random_bits_core ( & mut rng, second. as_mut_limbs ( ) , U1024 :: BITS - bit_length)
338- . expect ( "safe" ) ;
291+ random_bits_core ( & mut rng, & mut first, bit_length) . expect ( "safe" ) ;
292+ random_bits_core ( & mut rng, & mut second, U1024 :: BITS - bit_length) . expect ( "safe" ) ;
339293 assert_eq ! ( second. shl( bit_length) . bitor( & first) , RANDOM_OUTPUT ) ;
340294 }
341295 }
0 commit comments