@@ -6,6 +6,9 @@ use rand_core::CryptoRngCore;
6
6
#[ cfg( feature = "default-rng" ) ]
7
7
use rand_core:: OsRng ;
8
8
9
+ #[ cfg( feature = "multicore" ) ]
10
+ use rayon:: iter:: { ParallelBridge , ParallelIterator } ;
11
+
9
12
use crate :: hazmat:: { lucas_test, random_odd_integer, AStarBase , LucasCheck , MillerRabin , Primality , Sieve } ;
10
13
11
14
/// Returns a random prime of size `bit_length` using [`OsRng`] as the RNG.
@@ -16,6 +19,20 @@ pub fn generate_prime<T: Integer + RandomBits + RandomMod>(bit_length: u32) -> T
16
19
generate_prime_with_rng ( & mut OsRng , bit_length)
17
20
}
18
21
22
+ /// Returns a random prime of size `bit_length` using [`OsRng`] as the RNG.
23
+ ///
24
+ /// See [`is_prime_with_rng`] for details about the performed checks.
25
+ ///
26
+ /// Uses `threadcount` cores to parallelize the prime search.
27
+ ///
28
+ /// Panics if `bit_length` is less than 2, or greater than the bit size of the target `Uint`.
29
+ ///
30
+ /// Panics if the platform is unable to spawn threads.
31
+ #[ cfg( all( feature = "default-rng" , feature = "multicore" ) ) ]
32
+ pub fn par_generate_prime < T : Integer + RandomBits + RandomMod > ( bit_length : u32 , threadcount : usize ) -> T {
33
+ par_generate_prime_with_rng ( & mut OsRng , bit_length, threadcount)
34
+ }
35
+
19
36
/// Returns a random safe prime (that is, such that `(n - 1) / 2` is also prime) of size
20
37
/// `bit_length` using [`OsRng`] as the RNG.
21
38
///
@@ -25,6 +42,21 @@ pub fn generate_safe_prime<T: Integer + RandomBits + RandomMod>(bit_length: u32)
25
42
generate_safe_prime_with_rng ( & mut OsRng , bit_length)
26
43
}
27
44
45
+ /// Returns a random safe prime (that is, such that `(n - 1) / 2` is also prime) of size
46
+ /// `bit_length` using [`OsRng`] as the RNG.
47
+ ///
48
+ /// See [`is_prime_with_rng`] for details about the performed checks.
49
+ ///
50
+ /// Uses `threadcount` cores to parallelize the prime search.
51
+ ///
52
+ /// Panics if `bit_length` is less than 3, or greater than the bit size of the target `Uint`.
53
+ ///
54
+ /// Panics if the platform is unable to spawn threads.
55
+ #[ cfg( all( feature = "default-rng" , feature = "multicore" ) ) ]
56
+ pub fn par_generate_safe_prime < T : Integer + RandomBits + RandomMod > ( bit_length : u32 , threadcount : usize ) -> T {
57
+ par_generate_safe_prime_with_rng ( & mut OsRng , bit_length, threadcount)
58
+ }
59
+
28
60
/// Probabilistically checks if the given number is prime using [`OsRng`] as the RNG.
29
61
///
30
62
/// See [`is_prime_with_rng`] for details about the performed checks.
@@ -90,6 +122,94 @@ pub fn generate_safe_prime_with_rng<T: Integer + RandomBits + RandomMod>(
90
122
}
91
123
}
92
124
125
+ /// Returns a random prime of size `bit_length` using the provided RNG.
126
+ ///
127
+ /// Uses `threadcount` cores to parallelize the prime search.
128
+ ///
129
+ /// Panics if `bit_length` is less than 2, or greater than the bit size of the target `Uint`.
130
+ ///
131
+ /// Panics if the platform is unable to spawn threads.
132
+ #[ cfg( feature = "multicore" ) ]
133
+ pub fn par_generate_prime_with_rng < T > (
134
+ rng : & mut ( impl CryptoRngCore + Send + Sync + Clone ) ,
135
+ bit_length : u32 ,
136
+ threadcount : usize ,
137
+ ) -> T
138
+ where
139
+ T : Integer + RandomBits + RandomMod ,
140
+ {
141
+ if bit_length < 2 {
142
+ panic ! ( "`bit_length` must be 2 or greater." ) ;
143
+ }
144
+ let bit_length = NonZero :: new ( bit_length) . expect ( "`bit_length` should be non-zero" ) ;
145
+
146
+ let threadpool = rayon:: ThreadPoolBuilder :: new ( )
147
+ . num_threads ( threadcount)
148
+ . build ( )
149
+ . expect ( "If the platform can spawn threads, then this call will work." ) ;
150
+ let start = random_odd_integer :: < T > ( rng, bit_length) . get ( ) ;
151
+ let sieve = Sieve :: new ( start, bit_length, false ) ;
152
+
153
+ let prime = threadpool. install ( || {
154
+ sieve. par_bridge ( ) . find_any ( |c| {
155
+ let mut rng = rng. clone ( ) ;
156
+ is_prime_with_rng ( & mut rng, c)
157
+ } )
158
+ } ) ;
159
+ match prime {
160
+ Some ( prime) => prime,
161
+ None => {
162
+ drop ( threadpool) ;
163
+ par_generate_prime_with_rng ( rng, bit_length. get ( ) , threadcount)
164
+ }
165
+ }
166
+ }
167
+
168
+ /// Returns a random safe prime (that is, such that `(n - 1) / 2` is also prime)
169
+ /// of size `bit_length` using the provided RNG.
170
+ ///
171
+ /// Uses `threadcount` cores to parallelize the prime search.
172
+ ///
173
+ /// Panics if `bit_length` is less than 3, or greater than the bit size of the target `Uint`.
174
+ /// Panics if the platform is unable to spawn threads.
175
+ ///
176
+ /// See [`is_prime_with_rng`] for details about the performed checks.
177
+ #[ cfg( feature = "multicore" ) ]
178
+ pub fn par_generate_safe_prime_with_rng < T > (
179
+ rng : & mut ( impl CryptoRngCore + Send + Sync + Clone ) ,
180
+ bit_length : u32 ,
181
+ threadcount : usize ,
182
+ ) -> T
183
+ where
184
+ T : Integer + RandomBits + RandomMod ,
185
+ {
186
+ if bit_length < 2 {
187
+ panic ! ( "`bit_length` must be 2 or greater." ) ;
188
+ }
189
+ let bit_length = NonZero :: new ( bit_length) . expect ( "`bit_length` should be non-zero" ) ;
190
+
191
+ let threadpool = rayon:: ThreadPoolBuilder :: new ( )
192
+ . num_threads ( threadcount)
193
+ . build ( )
194
+ . expect ( "If the platform can spawn threads, then this call will work." ) ;
195
+ let start = random_odd_integer :: < T > ( rng, bit_length) . get ( ) ;
196
+ let sieve = Sieve :: new ( start, bit_length, true ) ;
197
+
198
+ let prime = threadpool. install ( || {
199
+ sieve. par_bridge ( ) . find_any ( |c| {
200
+ let mut rng = rng. clone ( ) ;
201
+ is_safe_prime_with_rng ( & mut rng, c)
202
+ } )
203
+ } ) ;
204
+ match prime {
205
+ Some ( prime) => prime,
206
+ None => {
207
+ drop ( threadpool) ;
208
+ par_generate_safe_prime_with_rng ( rng, bit_length. get ( ) , threadcount)
209
+ }
210
+ }
211
+ }
212
+
93
213
/// Probabilistically checks if the given number is prime using the provided RNG.
94
214
///
95
215
/// Performed checks:
@@ -367,6 +487,51 @@ mod tests {
367
487
}
368
488
}
369
489
490
+ #[ cfg( all( test, feature = "multicore" ) ) ]
491
+ mod multicore_tests {
492
+ use super :: { is_prime, par_generate_prime_with_rng} ;
493
+ use crypto_bigint:: { nlimbs, BoxedUint , U128 } ;
494
+
495
+ use super :: * ;
496
+ #[ test]
497
+ fn parallel_prime_generation ( ) {
498
+ for bit_length in ( 28 ..=128 ) . step_by ( 10 ) {
499
+ let p: U128 = par_generate_prime_with_rng ( & mut OsRng , bit_length, 4 ) ;
500
+ assert ! ( p. bits_vartime( ) == bit_length) ;
501
+ assert ! ( is_prime( & p) ) ;
502
+ }
503
+ }
504
+
505
+ #[ test]
506
+ fn parallel_prime_generation_boxed ( ) {
507
+ for bit_length in ( 28 ..=128 ) . step_by ( 10 ) {
508
+ let p: BoxedUint = par_generate_prime_with_rng ( & mut OsRng , bit_length, 2 ) ;
509
+ assert ! ( p. bits_vartime( ) == bit_length) ;
510
+ assert ! ( p. to_words( ) . len( ) == nlimbs!( bit_length) ) ;
511
+ assert ! ( is_prime( & p) ) ;
512
+ }
513
+ }
514
+
515
+ #[ test]
516
+ fn parallel_safe_prime_generation ( ) {
517
+ for bit_length in ( 28 ..=128 ) . step_by ( 10 ) {
518
+ let p: U128 = par_generate_safe_prime_with_rng ( & mut OsRng , bit_length, 8 ) ;
519
+ assert ! ( p. bits_vartime( ) == bit_length) ;
520
+ assert ! ( is_prime( & p) ) ;
521
+ }
522
+ }
523
+
524
+ #[ test]
525
+ fn parallel_safe_prime_generation_boxed ( ) {
526
+ for bit_length in ( 28 ..=128 ) . step_by ( 10 ) {
527
+ let p: BoxedUint = par_generate_safe_prime_with_rng ( & mut OsRng , bit_length, 4 ) ;
528
+ assert ! ( p. bits_vartime( ) == bit_length) ;
529
+ assert ! ( p. to_words( ) . len( ) == nlimbs!( bit_length) ) ;
530
+ assert ! ( is_prime( & p) ) ;
531
+ }
532
+ }
533
+ }
534
+
370
535
#[ cfg( test) ]
371
536
#[ cfg( feature = "tests-openssl" ) ]
372
537
mod tests_openssl {
0 commit comments