11//! Random number generator support
22
33use super :: { Uint , Word } ;
4- use crate :: { Encoding , Limb , NonZero , Random , RandomBits , RandomBitsError , RandomMod , Zero } ;
4+ use crate :: { Limb , NonZero , Random , RandomBits , RandomBitsError , RandomMod } ;
55use rand_core:: { RngCore , TryRngCore } ;
6- use subtle:: ConstantTimeLess ;
76
87impl < const LIMBS : usize > Random for Uint < LIMBS > {
98 fn try_random < R : TryRngCore + ?Sized > ( rng : & mut R ) -> Result < Self , R :: Error > {
@@ -30,7 +29,7 @@ pub(crate) fn random_bits_core<R: TryRngCore + ?Sized>(
3029 rng : & mut R ,
3130 zeroed_limbs : & mut [ Limb ] ,
3231 bit_length : u32 ,
33- ) -> Result < ( ) , RandomBitsError < R :: Error > > {
32+ ) -> Result < ( ) , R :: Error > {
3433 if bit_length == 0 {
3534 return Ok ( ( ) ) ;
3635 }
@@ -43,8 +42,7 @@ pub(crate) fn random_bits_core<R: TryRngCore + ?Sized>(
4342 let mask = Word :: MAX >> ( ( Word :: BITS - partial_limb) % Word :: BITS ) ;
4443
4544 for i in 0 ..nonzero_limbs - 1 {
46- rng. try_fill_bytes ( & mut buffer)
47- . map_err ( RandomBitsError :: RandCore ) ?;
45+ rng. try_fill_bytes ( & mut buffer) ?;
4846 zeroed_limbs[ i] = Limb ( Word :: from_le_bytes ( buffer) ) ;
4947 }
5048
@@ -62,8 +60,7 @@ pub(crate) fn random_bits_core<R: TryRngCore + ?Sized>(
6260 buffer. as_mut_slice ( )
6361 } ;
6462
65- rng. try_fill_bytes ( slice)
66- . map_err ( RandomBitsError :: RandCore ) ?;
63+ rng. try_fill_bytes ( slice) ?;
6764 zeroed_limbs[ nonzero_limbs - 1 ] = Limb ( Word :: from_le_bytes ( buffer) & mask) ;
6865
6966 Ok ( ( ) )
@@ -95,71 +92,38 @@ impl<const LIMBS: usize> RandomBits for Uint<LIMBS> {
9592 } ) ;
9693 }
9794 let mut limbs = [ Limb :: ZERO ; LIMBS ] ;
98- random_bits_core ( rng, & mut limbs, bit_length) ?;
95+ random_bits_core ( rng, & mut limbs, bit_length) . map_err ( RandomBitsError :: RandCore ) ?;
9996 Ok ( Self :: from ( limbs) )
10097 }
10198}
10299
103100impl < const LIMBS : usize > RandomMod for Uint < LIMBS > {
104101 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
102+ let n_bits = modulus. bits_vartime ( ) ;
103+ loop {
104+ let n = Self :: random_bits ( rng, n_bits) ;
105+ if & n < modulus. as_ref ( ) {
106+ return n;
107+ }
108+ }
108109 }
109110
110111 fn try_random_mod < R : TryRngCore + ?Sized > (
111112 rng : & mut R ,
112113 modulus : & NonZero < Self > ,
113114 ) -> Result < Self , R :: Error > {
114- let mut n = Self :: ZERO ;
115- random_mod_core ( rng, & mut n, modulus, modulus. bits_vartime ( ) ) ?;
116- Ok ( n)
117- }
118- }
119-
120- /// Generic implementation of `random_mod` which can be shared with `BoxedUint`.
121- // TODO(tarcieri): obtain `n_bits` via a trait like `Integer`
122- pub ( super ) fn random_mod_core < T , R : TryRngCore + ?Sized > (
123- rng : & mut R ,
124- n : & mut T ,
125- modulus : & NonZero < T > ,
126- n_bits : u32 ,
127- ) -> Result < ( ) , R :: Error >
128- where
129- T : AsMut < [ Limb ] > + AsRef < [ Limb ] > + ConstantTimeLess + Zero ,
130- {
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-
142- loop {
143- while hi_word > hi_word_modulus {
144- hi_word = next_word ( ) ? & mask;
145- }
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 ( ) ) ;
115+ let n_bits = modulus. bits_vartime ( ) ;
116+ loop {
117+ let n = match Self :: try_random_bits ( rng, n_bits) {
118+ Ok ( n) => n,
119+ Err ( RandomBitsError :: RandCore ( e) ) => return Err ( e) ,
120+ _ => unreachable ! ( ) ,
121+ } ;
122+ if & n < modulus. as_ref ( ) {
123+ return Ok ( n) ;
124+ }
154125 }
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;
161126 }
162- Ok ( ( ) )
163127}
164128
165129#[ cfg( test) ]
@@ -288,6 +252,32 @@ mod tests {
288252 ) ;
289253 }
290254
255+ /// Make sure random_mod output is consistent across platforms
256+ #[ test]
257+ fn random_mod_platform_independence ( ) {
258+ let mut rng = get_four_sequential_rng ( ) ;
259+
260+ let modulus = NonZero :: new ( U256 :: from_u32 ( 8192 ) ) . unwrap ( ) ;
261+ let mut vals = [ U256 :: ZERO , U256 :: ZERO , U256 :: ZERO , U256 :: ZERO , U256 :: ZERO ] ;
262+ for val in & mut vals {
263+ * val = U256 :: random_mod ( & mut rng, & modulus) ;
264+ }
265+ let expected = [ 55 , 3378 , 2172 , 1657 , 5323 ] ;
266+ for ( want, got) in expected. into_iter ( ) . zip ( vals. into_iter ( ) ) {
267+ assert_eq ! ( got, U256 :: from_u32( want) ) ;
268+ }
269+
270+ let mut state = [ 0u8 ; 16 ] ;
271+ rng. fill_bytes ( & mut state) ;
272+
273+ assert_eq ! (
274+ state,
275+ [
276+ 60 , 146 , 46 , 106 , 157 , 83 , 56 , 212 , 186 , 104 , 211 , 210 , 125 , 28 , 120 , 239
277+ ] ,
278+ ) ;
279+ }
280+
291281 /// Test that random bytes are sampled consecutively.
292282 #[ test]
293283 fn random_bits_4_bytes_sequential ( ) {
0 commit comments