crypto_bigint/uint/
rand.rs1use super::{Uint, Word};
4use crate::{Encoding, Limb, NonZero, Random, RandomBits, RandomBitsError, RandomMod, Zero};
5use rand_core::RngCore;
6use subtle::ConstantTimeLess;
7
8impl<const LIMBS: usize> Random for Uint<LIMBS> {
9 fn random(mut rng: &mut (impl RngCore + ?Sized)) -> Self {
10 let mut limbs = [Limb::ZERO; LIMBS];
11
12 for limb in &mut limbs {
13 *limb = Limb::random(&mut rng)
14 }
15
16 limbs.into()
17 }
18}
19
20pub(crate) fn random_bits_core(
24 rng: &mut (impl RngCore + ?Sized),
25 zeroed_limbs: &mut [Limb],
26 bit_length: u32,
27) -> Result<(), RandomBitsError> {
28 if bit_length == 0 {
29 return Ok(());
30 }
31
32 let buffer: Word = 0;
33 let mut buffer = buffer.to_be_bytes();
34
35 let nonzero_limbs = bit_length.div_ceil(Limb::BITS) as usize;
36 let partial_limb = bit_length % Limb::BITS;
37 let mask = Word::MAX >> ((Word::BITS - partial_limb) % Word::BITS);
38
39 for i in 0..nonzero_limbs - 1 {
40 rng.try_fill_bytes(&mut buffer)
41 .map_err(RandomBitsError::RandCore)?;
42 zeroed_limbs[i] = Limb(Word::from_be_bytes(buffer));
43 }
44
45 rng.try_fill_bytes(&mut buffer)
46 .map_err(RandomBitsError::RandCore)?;
47 zeroed_limbs[nonzero_limbs - 1] = Limb(Word::from_be_bytes(buffer) & mask);
48
49 Ok(())
50}
51
52impl<const LIMBS: usize> RandomBits for Uint<LIMBS> {
53 fn try_random_bits(
54 rng: &mut (impl RngCore + ?Sized),
55 bit_length: u32,
56 ) -> Result<Self, RandomBitsError> {
57 Self::try_random_bits_with_precision(rng, bit_length, Self::BITS)
58 }
59
60 fn try_random_bits_with_precision(
61 rng: &mut (impl RngCore + ?Sized),
62 bit_length: u32,
63 bits_precision: u32,
64 ) -> Result<Self, RandomBitsError> {
65 if bits_precision != Self::BITS {
66 return Err(RandomBitsError::BitsPrecisionMismatch {
67 bits_precision,
68 integer_bits: Self::BITS,
69 });
70 }
71 if bit_length > Self::BITS {
72 return Err(RandomBitsError::BitLengthTooLarge {
73 bit_length,
74 bits_precision,
75 });
76 }
77 let mut limbs = [Limb::ZERO; LIMBS];
78 random_bits_core(rng, &mut limbs, bit_length)?;
79 Ok(Self::from(limbs))
80 }
81}
82
83impl<const LIMBS: usize> RandomMod for Uint<LIMBS> {
84 fn random_mod(rng: &mut (impl RngCore + ?Sized), modulus: &NonZero<Self>) -> Self {
85 let mut n = Self::ZERO;
86 random_mod_core(rng, &mut n, modulus, modulus.bits_vartime());
87 n
88 }
89}
90
91pub(super) fn random_mod_core<T>(
94 rng: &mut (impl RngCore + ?Sized),
95 n: &mut T,
96 modulus: &NonZero<T>,
97 n_bits: u32,
98) where
99 T: AsMut<[Limb]> + AsRef<[Limb]> + ConstantTimeLess + Zero,
100{
101 #[cfg(target_pointer_width = "64")]
102 let mut next_word = || rng.next_u64();
103 #[cfg(target_pointer_width = "32")]
104 let mut next_word = || rng.next_u32();
105
106 let n_limbs = n_bits.div_ceil(Limb::BITS) as usize;
107
108 let hi_word_modulus = modulus.as_ref().as_ref()[n_limbs - 1].0;
109 let mask = !0 >> hi_word_modulus.leading_zeros();
110 let mut hi_word = next_word() & mask;
111
112 loop {
113 while hi_word > hi_word_modulus {
114 hi_word = next_word() & mask;
115 }
116 n.as_mut()[n_limbs - 1] = Limb::from_le_bytes(hi_word.to_le_bytes());
118 for i in 0..n_limbs - 1 {
120 n.as_mut()[i] = Limb::from_le_bytes(next_word().to_le_bytes());
124 }
125 if n.ct_lt(modulus).into() {
128 break;
129 }
130 hi_word = next_word() & mask;
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use crate::{Limb, NonZero, RandomBits, RandomMod, U256};
137 use rand_chacha::ChaCha8Rng;
138 use rand_core::SeedableRng;
139
140 #[test]
141 fn random_mod() {
142 let mut rng = ChaCha8Rng::seed_from_u64(1);
143
144 let modulus = NonZero::new(U256::from(42u8)).unwrap();
146 let res = U256::random_mod(&mut rng, &modulus);
147
148 assert!(res < U256::from(42u8));
150
151 let modulus = NonZero::new(U256::from(0x10000000000000001u128)).unwrap();
154 let res = U256::random_mod(&mut rng, &modulus);
155
156 assert!(res < U256::from(0x10000000000000001u128));
158 }
159
160 #[test]
161 fn random_bits() {
162 let mut rng = ChaCha8Rng::seed_from_u64(1);
163
164 let lower_bound = 16;
165
166 let bit_length = U256::BITS;
168 for _ in 0..10 {
169 let res = U256::random_bits(&mut rng, bit_length);
170 assert!(res > (U256::ONE << (bit_length - lower_bound)));
171 }
172
173 let bit_length = U256::BITS - Limb::BITS;
175 for _ in 0..10 {
176 let res = U256::random_bits(&mut rng, bit_length);
177 assert!(res > (U256::ONE << (bit_length - lower_bound)));
178 assert!(res < (U256::ONE << bit_length));
179 }
180
181 let bit_length = U256::BITS - Limb::BITS - 8;
183 for _ in 0..10 {
184 let res = U256::random_bits(&mut rng, bit_length);
185 assert!(res > (U256::ONE << (bit_length - lower_bound)));
186 assert!(res < (U256::ONE << bit_length));
187 }
188
189 let bit_length = U256::BITS - Limb::BITS - 8 - 3;
191 for _ in 0..10 {
192 let res = U256::random_bits(&mut rng, bit_length);
193 assert!(res > (U256::ONE << (bit_length - lower_bound)));
194 assert!(res < (U256::ONE << bit_length));
195 }
196
197 let bit_length = 7;
199 for _ in 0..10 {
200 let res = U256::random_bits(&mut rng, bit_length);
201 assert!(res < (U256::ONE << bit_length));
202 }
203
204 let bit_length = 0;
206 for _ in 0..10 {
207 let res = U256::random_bits(&mut rng, bit_length);
208 assert_eq!(res, U256::ZERO);
209 }
210 }
211}