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 , Zero } ;
55use rand_core:: { RngCore , TryRngCore } ;
66use subtle:: ConstantTimeLess ;
77
@@ -30,7 +30,7 @@ pub(crate) fn random_bits_core<R: TryRngCore + ?Sized>(
3030 rng : & mut R ,
3131 zeroed_limbs : & mut [ Limb ] ,
3232 bit_length : u32 ,
33- ) -> Result < ( ) , RandomBitsError < R :: Error > > {
33+ ) -> Result < ( ) , R :: Error > {
3434 if bit_length == 0 {
3535 return Ok ( ( ) ) ;
3636 }
@@ -43,8 +43,7 @@ pub(crate) fn random_bits_core<R: TryRngCore + ?Sized>(
4343 let mask = Word :: MAX >> ( ( Word :: BITS - partial_limb) % Word :: BITS ) ;
4444
4545 for i in 0 ..nonzero_limbs - 1 {
46- rng. try_fill_bytes ( & mut buffer)
47- . map_err ( RandomBitsError :: RandCore ) ?;
46+ rng. try_fill_bytes ( & mut buffer) ?;
4847 zeroed_limbs[ i] = Limb ( Word :: from_le_bytes ( buffer) ) ;
4948 }
5049
@@ -62,8 +61,7 @@ pub(crate) fn random_bits_core<R: TryRngCore + ?Sized>(
6261 buffer. as_mut_slice ( )
6362 } ;
6463
65- rng. try_fill_bytes ( slice)
66- . map_err ( RandomBitsError :: RandCore ) ?;
64+ rng. try_fill_bytes ( slice) ?;
6765 zeroed_limbs[ nonzero_limbs - 1 ] = Limb ( Word :: from_le_bytes ( buffer) & mask) ;
6866
6967 Ok ( ( ) )
@@ -95,7 +93,7 @@ impl<const LIMBS: usize> RandomBits for Uint<LIMBS> {
9593 } ) ;
9694 }
9795 let mut limbs = [ Limb :: ZERO ; LIMBS ] ;
98- random_bits_core ( rng, & mut limbs, bit_length) ?;
96+ random_bits_core ( rng, & mut limbs, bit_length) . map_err ( RandomBitsError :: RandCore ) ?;
9997 Ok ( Self :: from ( limbs) )
10098 }
10199}
@@ -128,43 +126,19 @@ pub(super) fn random_mod_core<T, R: TryRngCore + ?Sized>(
128126where
129127 T : AsMut < [ Limb ] > + AsRef < [ Limb ] > + ConstantTimeLess + Zero ,
130128{
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-
142129 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 ( ) ) ;
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.
130+ random_bits_core ( rng, n. as_mut ( ) , n_bits) ?;
131+
157132 if n. ct_lt ( modulus) . into ( ) {
158133 break ;
159134 }
160- hi_word = next_word ( ) ? & mask;
161135 }
162136 Ok ( ( ) )
163137}
164138
165139#[ cfg( test) ]
166140mod tests {
167- use crate :: uint:: rand:: random_bits_core;
141+ use crate :: uint:: rand:: { random_bits_core, random_mod_core } ;
168142 use crate :: { Limb , NonZero , Random , RandomBits , RandomMod , U256 , U1024 , Uint } ;
169143 use chacha20:: ChaCha8Rng ;
170144 use rand_core:: { RngCore , SeedableRng } ;
@@ -288,6 +262,32 @@ mod tests {
288262 ) ;
289263 }
290264
265+ /// Make sure random_mod output is consistent across platforms
266+ #[ test]
267+ fn random_mod_platform_independence ( ) {
268+ let mut rng = get_four_sequential_rng ( ) ;
269+
270+ let modulus = NonZero :: new ( U256 :: from_u32 ( 8192 ) ) . unwrap ( ) ;
271+ let mut vals = [ U256 :: ZERO , U256 :: ZERO , U256 :: ZERO , U256 :: ZERO , U256 :: ZERO ] ;
272+ for val in & mut vals {
273+ random_mod_core ( & mut rng, val, & modulus, modulus. bits_vartime ( ) ) . unwrap ( ) ;
274+ }
275+ let expected = [ 55 , 3378 , 2172 , 1657 , 5323 ] ;
276+ for ( want, got) in expected. into_iter ( ) . zip ( vals. into_iter ( ) ) {
277+ assert_eq ! ( got, U256 :: from_u32( want) ) ;
278+ }
279+
280+ let mut state = [ 0u8 ; 16 ] ;
281+ rng. fill_bytes ( & mut state) ;
282+
283+ assert_eq ! (
284+ state,
285+ [
286+ 60 , 146 , 46 , 106 , 157 , 83 , 56 , 212 , 186 , 104 , 211 , 210 , 125 , 28 , 120 , 239
287+ ] ,
288+ ) ;
289+ }
290+
291291 /// Test that random bytes are sampled consecutively.
292292 #[ test]
293293 fn random_bits_4_bytes_sequential ( ) {
0 commit comments