33
44use alloc:: { vec, vec:: Vec } ;
55
6- use crypto_bigint:: { Integer , Limb , NonZero , Random , Uint , Zero } ;
6+ use crypto_bigint:: { Random , Uint } ;
77use rand_core:: CryptoRngCore ;
88
9- use crate :: hazmat:: {
10- precomputed:: { SmallPrime , RECIPROCALS , SMALL_PRIMES } ,
11- Primality ,
12- } ;
9+ use crate :: hazmat:: precomputed:: { SmallPrime , RECIPROCALS , SMALL_PRIMES } ;
1310
1411/// Returns a random odd integer with given bit length
1512/// (that is, with both `0` and `bit_length-1` bits set).
@@ -42,6 +39,14 @@ pub fn random_odd_uint<const L: usize>(rng: &mut impl CryptoRngCore, bit_length:
4239 random
4340}
4441
42+ // The type we use to calculate incremental residues.
43+ // Should be >= `SmallPrime` in size.
44+ type Residue = u32 ;
45+
46+ // The maximum increment that won't overflow the type we use to calculate residues of increments:
47+ // we need `(max_prime - 1) + max_incr <= Type::MAX`.
48+ const INCR_LIMIT : Residue = Residue :: MAX - SMALL_PRIMES [ SMALL_PRIMES . len ( ) - 1 ] as Residue + 1 ;
49+
4550/// An iterator returning numbers with up to and including given bit length,
4651/// starting from a given number, that are not multiples of the first 2048 small primes.
4752#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -60,52 +65,49 @@ pub struct Sieve<const L: usize> {
6065 last_round : bool ,
6166}
6267
63- // The type we use to calculate incremental residues.
64- // Should be >= `SmallPrime` in size.
65- type Residue = u32 ;
66-
67- // The maximum increment that won't overflow the type we use to calculate residues of increments:
68- // we need `(max_prime - 1) + max_incr <= Type::MAX`.
69- const INCR_LIMIT : Residue = Residue :: MAX - SMALL_PRIMES [ SMALL_PRIMES . len ( ) - 1 ] as Residue + 1 ;
70-
7168impl < const L : usize > Sieve < L > {
7269 /// Creates a new sieve, iterating from `start` and
7370 /// until the last number with `max_bit_length` bits,
7471 /// producing numbers that are not non-trivial multiples
75- /// of a list of small primes in the range `[2, start)`.
72+ /// of a list of small primes in the range `[2, start)` (`safe_primes = false`)
73+ /// or `[2, start/2)` (`safe_primes = true`).
74+ ///
75+ /// Note that `start` is adjusted to `2`, or the next `1 mod 2` number (`safe_primes = false`);
76+ /// and `5`, or `3 mod 4` number (`safe_primes = true`).
7677 ///
77- /// Note that `start` is adjusted to `2`, or the next `1 mod 2` number (`safe_prime = false`);
78- /// and `5`, or `3 mod 4` number (`safe_prime = true`).
78+ /// Panics if `max_bit_length` is greater than the size of the target `Uint`.
7979 ///
80- /// If `safe_primes` is `true`, it only produces the candidates
81- /// that can possibly be safe primes (that is, 5, and those equal to 3 modulo 4).
80+ /// If `safe_primes` is `true`, both the returned `n` and `n/2` are sieved.
8281 pub fn new ( start : & Uint < L > , max_bit_length : usize , safe_primes : bool ) -> Self {
83- let mut base = * start;
82+ if max_bit_length > Uint :: < L > :: BITS {
83+ panic ! (
84+ "The requested bit length ({}) is larger than the chosen Uint size" ,
85+ max_bit_length
86+ ) ;
87+ }
88+
89+ // If we are targeting safe primes, iterate over the corresponding
90+ // possible Germain primes (`n/2`), reducing the task to that with `safe_primes = false`.
91+ let ( max_bit_length, base) = if safe_primes {
92+ ( max_bit_length - 1 , start >> 1 )
93+ } else {
94+ ( max_bit_length, * start)
95+ } ;
96+
97+ let mut base = base;
8498
8599 // This is easier than making all the methods generic enough to handle these corner cases.
86- let produces_nothing = max_bit_length < base. bits ( )
87- || ( !safe_primes && max_bit_length < 2 )
88- || ( safe_primes && max_bit_length < 3 ) ;
100+ let produces_nothing = max_bit_length < base. bits ( ) || max_bit_length < 2 ;
89101
90- // Add exceptions to the produced candidates - the only ones that don 't fit
91- // the general pattern of incrementing the base by 2 or by 4 .
102+ // Add the exception to the produced candidates - the only one that doesn 't fit
103+ // the general pattern of incrementing the base by 2.
92104 let mut starts_from_exception = false ;
93- if !safe_primes {
94- if base <= Uint :: < L > :: from ( 2u32 ) {
95- starts_from_exception = true ;
96- base = Uint :: < L > :: from ( 3u32 ) ;
97- } else {
98- // Adjust the base so that we hit correct numbers when incrementing it by 2.
99- base |= Uint :: < L > :: ONE ;
100- }
101- } else if base <= Uint :: < L > :: from ( 5u32 ) {
105+ if base <= Uint :: < L > :: from ( 2u32 ) {
102106 starts_from_exception = true ;
103- base = Uint :: < L > :: from ( 7u32 ) ;
107+ base = Uint :: < L > :: from ( 3u32 ) ;
104108 } else {
105- // Adjust the base so that we hit correct numbers when incrementing it by 4.
106- // If we are looking for safe primes, we are only interested
107- // in the numbers == 3 mod 4.
108- base |= Uint :: < L > :: from ( 3u32 ) ;
109+ // Adjust the base so that we hit odd numbers when incrementing it by 2.
110+ base |= Uint :: < L > :: ONE ;
109111 }
110112
111113 // Only calculate residues by primes up to and not including `base`,
@@ -157,8 +159,6 @@ impl<const L: usize> Sieve<L> {
157159 }
158160
159161 // Find the increment limit.
160- // Note that the max value is the same regardless of the value of `self.safe_prime`,
161- // since `(2^n - 1) = 3 mod 4` (for n > 1).
162162 let max_value = ( Uint :: < L > :: ONE << self . max_bit_length ) . wrapping_sub ( & Uint :: < L > :: ONE ) ;
163163 let incr_limit = max_value. wrapping_sub ( & self . base ) ;
164164 self . incr_limit = if incr_limit > INCR_LIMIT . into ( ) {
@@ -179,11 +179,24 @@ impl<const L: usize> Sieve<L> {
179179 // Returns `true` if the current `base + incr` is divisible by any of the small primes.
180180 fn current_is_composite ( & self ) -> bool {
181181 for ( i, m) in self . residues . iter ( ) . enumerate ( ) {
182- let r = ( * m as Residue + self . incr ) % ( SMALL_PRIMES [ i] as Residue ) ;
182+ let d = SMALL_PRIMES [ i] as Residue ;
183+ let r = ( * m as Residue + self . incr ) % d;
184+
183185 if r == 0 {
184186 return true ;
185187 }
188+
189+ // A trick from "Safe Prime Generation with a Combined Sieve" by Michael J. Wiener
190+ // (https://eprint.iacr.org/2003/186).
191+ // Remember that the check above was for the `(n - 1)/2`;
192+ // If `(n - 1)/2 mod d == (d - 1)/2`, it means that `n mod d == 0`.
193+ // In other words, we are checking the remainder of `n mod d`
194+ // for virtually no additional cost.
195+ if self . safe_primes && r == ( d - 1 ) >> 1 {
196+ return true ;
197+ }
186198 }
199+
187200 false
188201 }
189202
@@ -193,11 +206,14 @@ impl<const L: usize> Sieve<L> {
193206 let result = if self . current_is_composite ( ) {
194207 None
195208 } else {
196- Some ( self . base . wrapping_add ( & self . incr . into ( ) ) )
209+ let mut num = self . base . wrapping_add ( & self . incr . into ( ) ) ;
210+ if self . safe_primes {
211+ num = ( num << 1 ) | Uint :: < L > :: ONE ;
212+ }
213+ Some ( num)
197214 } ;
198215
199- // If we are looking for safe primes, we are only interested in the numbers == 3 mod 4.
200- self . incr += if self . safe_primes { 4 } else { 2 } ;
216+ self . incr += 2 ;
201217 result
202218 }
203219
@@ -229,33 +245,8 @@ impl<const L: usize> Iterator for Sieve<L> {
229245 type Item = Uint < L > ;
230246
231247 fn next ( & mut self ) -> Option < Self :: Item > {
232- Sieve :: < L > :: next ( self )
233- }
234- }
235-
236- /// Performs trial division of the given number by a list of small primes starting from 2.
237- /// Returns `Some(primality)` if there was a definitive conclusion about `num`'s primality,
238- /// and `None` otherwise.
239- pub fn sieve_once < const L : usize > ( num : & Uint < L > ) -> Option < Primality > {
240- // Our reciprocals start from 3, so we check for 2 separately
241- if num == & Uint :: < L > :: from ( 2u32 ) {
242- return Some ( Primality :: Prime ) ;
243- }
244- if num. is_even ( ) . into ( ) {
245- return Some ( Primality :: Composite ) ;
246- }
247- for small_prime in SMALL_PRIMES . iter ( ) {
248- let ( quo, rem) = num. div_rem_limb ( NonZero :: new ( Limb :: from ( * small_prime) ) . unwrap ( ) ) ;
249- if rem. is_zero ( ) . into ( ) {
250- let primality = if quo == Uint :: < L > :: ONE {
251- Primality :: Prime
252- } else {
253- Primality :: Composite
254- } ;
255- return Some ( primality) ;
256- }
248+ Self :: next ( self )
257249 }
258- None
259250}
260251
261252#[ cfg( test) ]
@@ -328,15 +319,26 @@ mod tests {
328319 check_sieve ( 5 , 3 , true , & [ 5 , 7 ] ) ;
329320 check_sieve ( 7 , 3 , true , & [ 7 ] ) ;
330321
331- // start is adjusted to 5 here, so multiples of 3 can be excluded
332- check_sieve ( 1 , 4 , true , & [ 5 , 7 , 11 ] ) ;
322+ // In the following three cases, the "half-start" would be set to 3,
323+ // and since every small divisor equal or greater than the start is not tested
324+ // (because we can't distinguish between the remainder being 0
325+ // and the number being actually equal to the divisor),
326+ // no divisors will actually be tested at all, so 15 (a composite)
327+ // is included in the output.
328+ check_sieve ( 1 , 4 , true , & [ 5 , 7 , 11 , 15 ] ) ;
329+ check_sieve ( 5 , 4 , true , & [ 5 , 7 , 11 , 15 ] ) ;
330+ check_sieve ( 7 , 4 , true , & [ 7 , 11 , 15 ] ) ;
333331
334- check_sieve ( 5 , 4 , true , & [ 5 , 7 , 11 ] ) ;
335- check_sieve ( 7 , 4 , true , & [ 7 , 11 ] ) ;
336332 check_sieve ( 9 , 4 , true , & [ 11 ] ) ;
337333 check_sieve ( 13 , 4 , true , & [ ] ) ;
338334 }
339335
336+ #[ test]
337+ #[ should_panic( expected = "The requested bit length (65) is larger than the chosen Uint size" ) ]
338+ fn sieve_too_many_bits ( ) {
339+ let _sieve = Sieve :: new ( & U64 :: ONE , 65 , false ) ;
340+ }
341+
340342 #[ test]
341343 fn random_below_max_length ( ) {
342344 for _ in 0 ..10 {
0 commit comments