11//! Random number generator support
22
3- use super :: Uint ;
4- use crate :: { CtLt , Encoding , Limb , NonZero , Random , RandomBits , RandomBitsError , RandomMod } ;
3+ use super :: { Uint , Word } ;
4+ use crate :: { CtLt , Encoding , Limb , NonZero , Random , RandomBits , RandomBitsError , RandomMod , Zero } ;
55use rand_core:: { RngCore , TryRngCore } ;
66
77impl < const LIMBS : usize > Random for Uint < LIMBS > {
@@ -25,26 +25,45 @@ impl<const LIMBS: usize> Random for Uint<LIMBS> {
2525/// `rng.fill_bytes(&mut bytes[..i]); rng.fill_bytes(&mut bytes[i..])` constructs the same `bytes`,
2626/// as long as `i` is a multiple of `X`.
2727/// Note that the `TryRngCore` trait does _not_ require this behaviour from `rng`.
28- pub ( crate ) fn random_bits_core < T , R : TryRngCore + ?Sized > (
28+ pub ( crate ) fn random_bits_core < R : TryRngCore + ?Sized > (
2929 rng : & mut R ,
30- x : & mut T ,
31- n_bits : u32 ,
32- ) -> Result < ( ) , R :: Error >
33- where
34- T : Encoding ,
35- {
36- if n_bits == 0 {
30+ zeroed_limbs : & mut [ Limb ] ,
31+ bit_length : u32 ,
32+ ) -> Result < ( ) , RandomBitsError < R :: Error > > {
33+ if bit_length == 0 {
3734 return Ok ( ( ) ) ;
3835 }
3936
40- let n_bytes = n_bits . div_ceil ( u8 :: BITS ) as usize ;
41- let hi_mask = u8 :: MAX >> ( ( u8 :: BITS - ( n_bits % u8 :: BITS ) ) % u8 :: BITS ) ;
37+ let buffer : Word = 0 ;
38+ let mut buffer = buffer . to_be_bytes ( ) ;
4239
43- let mut buffer = x. to_le_bytes ( ) ;
44- let slice = buffer. as_mut ( ) ;
45- rng. try_fill_bytes ( & mut slice[ ..n_bytes] ) ?;
46- slice[ n_bytes - 1 ] &= hi_mask;
47- * x = T :: from_le_bytes ( buffer) ;
40+ let nonzero_limbs = bit_length. div_ceil ( Limb :: BITS ) as usize ;
41+ let partial_limb = bit_length % Limb :: BITS ;
42+ let mask = Word :: MAX >> ( ( Word :: BITS - partial_limb) % Word :: BITS ) ;
43+
44+ for i in 0 ..nonzero_limbs - 1 {
45+ rng. try_fill_bytes ( & mut buffer)
46+ . map_err ( RandomBitsError :: RandCore ) ?;
47+ zeroed_limbs[ i] = Limb ( Word :: from_le_bytes ( buffer) ) ;
48+ }
49+
50+ // This algorithm should sample the same number of random bytes, regardless of the pointer width
51+ // of the target platform. To this end, special attention has to be paid to the case where
52+ // bit_length - 1 < 32 mod 64. Bit strings of that size can be represented using `2X+1` 32-bit
53+ // words or `X+1` 64-bit words. Note that 64*(X+1) - 32*(2X+1) = 32. Hence, if we sample full
54+ // words only, a 64-bit platform will sample 32 bits more than a 32-bit platform. We prevent
55+ // this by forcing both platforms to only sample 4 bytes for the last word in this case.
56+ let slice = if partial_limb > 0 && partial_limb <= 32 {
57+ // Note: we do not have to zeroize the second half of the buffer, as the mask will take
58+ // care of this in the end.
59+ & mut buffer[ 0 ..4 ]
60+ } else {
61+ buffer. as_mut_slice ( )
62+ } ;
63+
64+ rng. try_fill_bytes ( slice)
65+ . map_err ( RandomBitsError :: RandCore ) ?;
66+ zeroed_limbs[ nonzero_limbs - 1 ] = Limb ( Word :: from_le_bytes ( buffer) & mask) ;
4867
4968 Ok ( ( ) )
5069}
@@ -74,46 +93,72 @@ impl<const LIMBS: usize> RandomBits for Uint<LIMBS> {
7493 bits_precision,
7594 } ) ;
7695 }
77- let mut x = Self :: ZERO ;
78- random_bits_core ( rng, & mut x , bit_length) . map_err ( RandomBitsError :: RandCore ) ?;
79- Ok ( x )
96+ let mut limbs = [ Limb :: ZERO ; LIMBS ] ;
97+ random_bits_core ( rng, & mut limbs , bit_length) ?;
98+ Ok ( Self :: from ( limbs ) )
8099 }
81100}
82101
83102impl < const LIMBS : usize > RandomMod for Uint < LIMBS > {
84- fn random_mod_vartime < R : RngCore + ?Sized > ( rng : & mut R , modulus : & NonZero < Self > ) -> Self {
85- let mut x = Self :: ZERO ;
86- let Ok ( ( ) ) = random_mod_vartime_core ( rng, & mut x , modulus, modulus. bits_vartime ( ) ) ;
87- x
103+ fn random_mod < R : RngCore + ?Sized > ( rng : & mut R , modulus : & NonZero < Self > ) -> Self {
104+ let mut n = Self :: ZERO ;
105+ let Ok ( ( ) ) = random_mod_core ( rng, & mut n , modulus, modulus. bits_vartime ( ) ) ;
106+ n
88107 }
89108
90109 fn try_random_mod_vartime < R : TryRngCore + ?Sized > (
91110 rng : & mut R ,
92111 modulus : & NonZero < Self > ,
93112 ) -> Result < Self , R :: Error > {
94- let mut x = Self :: ZERO ;
95- random_mod_vartime_core ( rng, & mut x , modulus, modulus. bits_vartime ( ) ) ?;
96- Ok ( x )
113+ let mut n = Self :: ZERO ;
114+ random_mod_core ( rng, & mut n , modulus, modulus. bits_vartime ( ) ) ?;
115+ Ok ( n )
97116 }
98117}
99118
100- /// Generic implementation of `random_mod_vartime ` which can be shared with `BoxedUint`.
119+ /// Generic implementation of `random_mod ` which can be shared with `BoxedUint`.
101120// TODO(tarcieri): obtain `n_bits` via a trait like `Integer`
102- pub ( super ) fn random_mod_vartime_core < T , R : TryRngCore + ?Sized > (
121+ pub ( super ) fn random_mod_core < T , R : TryRngCore + ?Sized > (
103122 rng : & mut R ,
104- x : & mut T ,
123+ n : & mut T ,
105124 modulus : & NonZero < T > ,
106125 n_bits : u32 ,
107126) -> Result < ( ) , R :: Error >
108127where
109- T : Encoding + CtLt ,
128+ T : AsMut < [ Limb ] > + AsRef < [ Limb ] > + CtLt + Zero ,
110129{
130+ #[ cfg( target_pointer_width = "64" ) ]
131+ let mut next_word = || rng. try_next_u64 ( ) ;
132+ #[ cfg( target_pointer_width = "32" ) ]
133+ let mut next_word = || rng. try_next_u32 ( ) ;
134+
135+ let n_limbs = n_bits. div_ceil ( Limb :: BITS ) as usize ;
136+
137+ let hi_word_modulus = modulus. as_ref ( ) . as_ref ( ) [ n_limbs - 1 ] . 0 ;
138+ let mask = !0 >> hi_word_modulus. leading_zeros ( ) ;
139+ let mut hi_word = next_word ( ) ? & mask;
140+
111141 loop {
112- random_bits_core ( rng, x, n_bits) ?;
113- if x. ct_lt ( modulus) . into ( ) {
114- return Ok ( ( ) ) ;
142+ while hi_word > hi_word_modulus {
143+ hi_word = next_word ( ) ? & mask;
144+ }
145+ // Set high limb
146+ n. as_mut ( ) [ n_limbs - 1 ] = Limb :: from_le_bytes ( hi_word. to_le_bytes ( ) ) ;
147+ // Set low limbs
148+ for i in 0 ..n_limbs - 1 {
149+ // Need to deserialize from little-endian to make sure that two 32-bit limbs
150+ // deserialized sequentially are equal to one 64-bit limb produced from the same
151+ // byte stream.
152+ n. as_mut ( ) [ i] = Limb :: from_le_bytes ( next_word ( ) ?. to_le_bytes ( ) ) ;
153+ }
154+ // If the high limb is equal to the modulus' high limb, it's still possible
155+ // that the full uint is too big so we check and repeat if it is.
156+ if n. ct_lt ( modulus) . into ( ) {
157+ break ;
115158 }
159+ hi_word = next_word ( ) ? & mask;
116160 }
161+ Ok ( ( ) )
117162}
118163
119164#[ cfg( test) ]
@@ -223,7 +268,7 @@ mod tests {
223268
224269 let bit_length = 989 ;
225270 let mut val = U1024 :: ZERO ;
226- random_bits_core ( & mut rng, & mut val, bit_length) . expect ( "safe" ) ;
271+ random_bits_core ( & mut rng, val. as_mut_limbs ( ) , bit_length) . expect ( "safe" ) ;
227272
228273 assert_eq ! (
229274 val,
@@ -242,41 +287,6 @@ mod tests {
242287 ) ;
243288 }
244289
245- /// Make sure random_mod_vartime output is consistent across platforms
246- #[ test]
247- fn random_mod_vartime_platform_independence ( ) {
248- let mut rng = get_four_sequential_rng ( ) ;
249-
250- let modulus = NonZero :: new ( U256 :: from_u32 ( 8192 ) ) . unwrap ( ) ;
251- let mut vals = [ U256 :: ZERO ; 5 ] ;
252- for val in & mut vals {
253- * val = U256 :: random_mod_vartime ( & mut rng, & modulus) ;
254- }
255- let expected = [ 55 , 3378 , 2172 , 1657 , 5323 ] ;
256- for ( want, got) in expected. into_iter ( ) . zip ( vals. into_iter ( ) ) {
257- // assert_eq!(got.as_words()[0], want);
258- assert_eq ! ( got, U256 :: from_u32( want) ) ;
259- }
260-
261- let modulus =
262- NonZero :: new ( U256 :: ZERO . wrapping_sub ( & U256 :: from_u64 ( rng. next_u64 ( ) ) ) ) . unwrap ( ) ;
263- let val = U256 :: random_mod_vartime ( & mut rng, & modulus) ;
264- assert_eq ! (
265- val,
266- U256 :: from_be_hex( "E17653A37F1BCC44277FA208E6B31E08CDC4A23A7E88E660EF781C7DD2D368BA" )
267- ) ;
268-
269- let mut state = [ 0u8 ; 16 ] ;
270- rng. fill_bytes ( & mut state) ;
271-
272- assert_eq ! (
273- state,
274- [
275- 105 , 47 , 30 , 235 , 242 , 2 , 67 , 197 , 163 , 64 , 75 , 125 , 34 , 120 , 40 , 134 ,
276- ] ,
277- ) ;
278- }
279-
280290 /// Test that random bytes are sampled consecutively.
281291 #[ test]
282292 fn random_bits_4_bytes_sequential ( ) {
@@ -287,8 +297,9 @@ mod tests {
287297 let mut rng = get_four_sequential_rng ( ) ;
288298 let mut first = U1024 :: ZERO ;
289299 let mut second = U1024 :: ZERO ;
290- random_bits_core ( & mut rng, & mut first, bit_length) . expect ( "safe" ) ;
291- random_bits_core ( & mut rng, & mut second, U1024 :: BITS - bit_length) . expect ( "safe" ) ;
300+ random_bits_core ( & mut rng, first. as_mut_limbs ( ) , bit_length) . expect ( "safe" ) ;
301+ random_bits_core ( & mut rng, second. as_mut_limbs ( ) , U1024 :: BITS - bit_length)
302+ . expect ( "safe" ) ;
292303 assert_eq ! ( second. shl( bit_length) . bitor( & first) , RANDOM_OUTPUT ) ;
293304 }
294305 }
0 commit comments