• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 20579846577

29 Dec 2025 06:24PM UTC coverage: 90.415% (+0.2%) from 90.243%
20579846577

push

github

web-flow
Merge pull request #5167 from randombit/jack/src-size-reductions

Changes to reduce unnecessary inclusions

101523 of 112285 relevant lines covered (90.42%)

12817276.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.0
/src/lib/math/numbertheory/make_prm.cpp
1
/*
2
* Prime Generation
3
* (C) 1999-2007,2018,2019 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/internal/primality.h>
9

10
#include <botan/numthry.h>
11
#include <botan/rng.h>
12
#include <botan/internal/barrett.h>
13
#include <botan/internal/bit_ops.h>
14
#include <botan/internal/ct_utils.h>
15
#include <botan/internal/divide.h>
16
#include <botan/internal/loadstor.h>
17

18
namespace Botan {
19

20
namespace {
21

22
class Prime_Sieve final {
×
23
   public:
24
      Prime_Sieve(const BigInt& init_value, size_t sieve_size, word step, bool check_2p1) :
885✔
25
            m_sieve(std::min(sieve_size, PRIME_TABLE_SIZE)), m_step(step), m_check_2p1(check_2p1) {
885✔
26
         for(size_t i = 0; i != m_sieve.size(); ++i) {
468,300✔
27
            m_sieve[i] = ct_mod_word(init_value, PRIMES[i]);
467,415✔
28
         }
29
      }
885✔
30

31
      size_t sieve_size() const { return m_sieve.size(); }
32

33
      bool check_2p1() const { return m_check_2p1; }
1,002,941,118✔
34

35
      bool next() {
1,203,980✔
36
         auto passes = CT::Mask<word>::set();
1,203,980✔
37
         for(size_t i = 0; i != m_sieve.size(); ++i) {
1,004,145,098✔
38
            m_sieve[i] = sieve_step_incr(m_sieve[i], m_step, PRIMES[i]);
1,002,941,118✔
39

40
            // If m_sieve[i] == 0 then val % p == 0 -> not prime
41
            passes &= CT::Mask<word>::expand(m_sieve[i]);
1,002,941,118✔
42

43
            if(this->check_2p1()) {
1,002,941,118✔
44
               /*
45
               If v % p == (p-1)/2 then 2*v+1 == 0 (mod p)
46

47
               So if potentially generating a safe prime, we want to
48
               avoid this value because 2*v+1 will certainly not be prime.
49

50
               See "Safe Prime Generation with a Combined Sieve" M. Wiener
51
               https://eprint.iacr.org/2003/186.pdf
52
               */
53
               passes &= ~CT::Mask<word>::is_equal(m_sieve[i], (PRIMES[i] - 1) / 2);
973,312,190✔
54
            }
55
         }
56

57
         return passes.as_bool();
1,203,980✔
58
      }
59

60
   private:
61
      // Return (v + step) % mod
62
      //
63
      // This assumes v is already < mod, which is an invariant of the sieve
64
      static constexpr word sieve_step_incr(word v, word step, word mod) {
1,002,941,118✔
65
         BOTAN_DEBUG_ASSERT(v < mod);
1,002,941,118✔
66
         // The sieve step and primes are public so this modulo is ok
67
         const word stepmod = (step >= mod) ? (step % mod) : step;
1,002,941,118✔
68

69
         // This sum is at most 2*(mod-1)
70
         const word next = (v + stepmod);
1,002,941,118✔
71
         return next - CT::Mask<word>::is_gte(next, mod).if_set_return(mod);
1,002,941,118✔
72
      }
73

74
      std::vector<word> m_sieve;
75
      const word m_step;
76
      const bool m_check_2p1;
77
};
78

79
#if defined(BOTAN_ENABLE_DEBUG_ASSERTS)
80

81
bool no_small_multiples(const BigInt& v, const Prime_Sieve& sieve) {
82
   const size_t sieve_size = sieve.sieve_size();
83
   const bool check_2p1 = sieve.check_2p1();
84

85
   if(v.is_even())
86
      return false;
87

88
   const BigInt v_x2_p1 = 2 * v + 1;
89

90
   for(size_t i = 0; i != sieve_size; ++i) {
91
      if((v % PRIMES[i]) == 0)
92
         return false;
93

94
      if(check_2p1) {
95
         if(v_x2_p1 % PRIMES[i] == 0)
96
            return false;
97
      }
98
   }
99

100
   return true;
101
}
102

103
#endif
104

105
}  // namespace
106

107
/*
108
* Generate a random prime
109
*/
110
BigInt random_prime(
759✔
111
   RandomNumberGenerator& rng, size_t bits, const BigInt& coprime, size_t equiv, size_t modulo, size_t prob) {
112
   if(bits <= 1) {
759✔
113
      throw Invalid_Argument("random_prime: Can't make a prime of " + std::to_string(bits) + " bits");
8✔
114
   }
115
   if(coprime.is_negative() || (!coprime.is_zero() && coprime.is_even()) || coprime.bits() >= bits) {
1,521✔
116
      throw Invalid_Argument("random_prime: invalid coprime");
×
117
   }
118
   // TODO(Botan4) reduce this to ~1000
119
   if(modulo == 0 || modulo >= 100000) {
757✔
120
      throw Invalid_Argument("random_prime: Invalid modulo value");
×
121
   }
122

123
   equiv %= modulo;
757✔
124

125
   if(equiv == 0) {
757✔
126
      throw Invalid_Argument("random_prime Invalid value for equiv/modulo");
1✔
127
   }
128

129
   // Handle small values:
130

131
   if(bits <= 16) {
756✔
132
      if(equiv != 1 || modulo != 2 || coprime != 0) {
38✔
133
         throw Not_Implemented("random_prime equiv/modulo/coprime options not usable for small primes");
×
134
      }
135

136
      if(bits == 2) {
19✔
137
         return BigInt::from_word(((rng.next_byte() % 2) == 0 ? 2 : 3));
1✔
138
      } else if(bits == 3) {
18✔
139
         return BigInt::from_word(((rng.next_byte() % 2) == 0 ? 5 : 7));
1✔
140
      } else if(bits == 4) {
17✔
141
         return BigInt::from_word(((rng.next_byte() % 2) == 0 ? 11 : 13));
1✔
142
      } else {
143
         for(;;) {
4,520✔
144
            // This is slightly biased, but for small primes it does not seem to matter
145
            uint8_t b[4] = {0};
2,268✔
146
            rng.randomize(b, 4);
2,268✔
147
            const size_t idx = load_le<uint32_t>(b, 0) % PRIME_TABLE_SIZE;
2,268✔
148
            const uint16_t small_prime = PRIMES[idx];
2,268✔
149

150
            if(high_bit(small_prime) == bits) {
4,536✔
151
               return BigInt::from_word(small_prime);
16✔
152
            }
153
         }
2,252✔
154
      }
155
   }
156

157
   const size_t MAX_ATTEMPTS = 32 * 1024;
737✔
158

159
   const size_t mr_trials = miller_rabin_test_iterations(bits, prob, true);
737✔
160

161
   while(true) {
×
162
      BigInt p(rng, bits);
737✔
163

164
      // Force lowest and two top bits on
165
      p.set_bit(bits - 1);
737✔
166
      p.set_bit(bits - 2);
737✔
167
      p.set_bit(0);
737✔
168

169
      // Force p to be equal to equiv mod modulo
170
      p += (modulo - (p % modulo)) + equiv;
737✔
171

172
      Prime_Sieve sieve(p, bits, modulo, true);
737✔
173

174
      for(size_t attempt = 0; attempt <= MAX_ATTEMPTS; ++attempt) {
1,167,710✔
175
         p += modulo;
1,167,710✔
176

177
         if(!sieve.next()) {
1,167,710✔
178
            continue;
1,166,973✔
179
         }
180

181
         // here p can be even if modulo is odd, continue on in that case
182
         if(p.is_even()) {
52,402✔
183
            continue;
9,190✔
184
         }
185

186
         BOTAN_DEBUG_ASSERT(no_small_multiples(p, sieve));
17,011✔
187

188
         auto mod_p = Barrett_Reduction::for_secret_modulus(p);
17,011✔
189

190
         if(coprime > 1) {
17,011✔
191
            /*
192
            First do a single M-R iteration to quickly eliminate most non-primes,
193
            before doing the coprimality check which is expensive
194
            */
195
            if(!is_miller_rabin_probable_prime(p, mod_p, rng, 1)) {
99✔
196
               continue;
93✔
197
            }
198

199
            /*
200
            * Check if p - 1 and coprime are relatively prime, using gcd.
201
            * The gcd computation is const-time
202
            */
203
            if(gcd(p - 1, coprime) > 1) {
12✔
204
               continue;
×
205
            }
206
         }
207

208
         if(p.bits() > bits) {
16,918✔
209
            break;
210
         }
211

212
         if(!is_miller_rabin_probable_prime(p, mod_p, rng, mr_trials)) {
16,918✔
213
            continue;
16,181✔
214
         }
215

216
         if(prob > 32 && !is_lucas_probable_prime(p, mod_p)) {
737✔
217
            continue;
×
218
         }
219

220
         return p;
737✔
221
      }
17,011✔
222
   }
737✔
223
}
224

225
BigInt generate_rsa_prime(RandomNumberGenerator& keygen_rng,
148✔
226
                          RandomNumberGenerator& prime_test_rng,
227
                          size_t bits,
228
                          const BigInt& coprime,
229
                          size_t prob) {
230
   if(bits < 512) {
148✔
231
      throw Invalid_Argument("generate_rsa_prime bits too small");
×
232
   }
233

234
   /*
235
   * The restriction on coprime <= 64 bits is arbitrary but generally speaking
236
   * very large RSA public exponents are a bad idea both for performance and due
237
   * to attacks on small d.
238
   */
239
   if(coprime <= 1 || coprime.is_even() || coprime.bits() > 64) {
296✔
240
      throw Invalid_Argument("generate_rsa_prime coprime must be small odd positive integer");
×
241
   }
242

243
   const size_t MAX_ATTEMPTS = 32 * 1024;
148✔
244

245
   const size_t mr_trials = miller_rabin_test_iterations(bits, prob, true);
148✔
246

247
   while(true) {
×
248
      BigInt p(keygen_rng, bits);
148✔
249

250
      auto scope = CT::scoped_poison(p);
148✔
251

252
      /*
253
      Force high two bits so multiplication always results in expected n bit integer
254

255
      Force the two low bits, and step by 4, so the generated prime is always == 3 (mod 4).
256
      This way when we perform the inversion modulo phi(n) it is always of the form 2*o
257
      with o odd, which allows a fastpath and avoids leaking any information about the
258
      structure of the prime.
259
      */
260
      p.set_bit(bits - 1);
148✔
261
      p.set_bit(bits - 2);
148✔
262
      p.set_bit(1);
148✔
263
      p.set_bit(0);
148✔
264

265
      const word step = 4;
148✔
266

267
      Prime_Sieve sieve(p, bits, step, false);
148✔
268

269
      for(size_t attempt = 0; attempt <= MAX_ATTEMPTS; ++attempt) {
36,270✔
270
         p += step;
36,270✔
271

272
         if(!sieve.next()) {
36,270✔
273
            continue;
36,122✔
274
         }
275

276
         BOTAN_DEBUG_ASSERT(no_small_multiples(p, sieve));
4,886✔
277

278
         auto mod_p = Barrett_Reduction::for_secret_modulus(p);
4,886✔
279

280
         /*
281
         * Do a single primality test first before checking coprimality, since
282
         * currently a single Miller-Rabin test is faster than computing gcd,
283
         * and this eliminates almost all wasted gcd computations.
284
         */
285
         if(!is_miller_rabin_probable_prime(p, mod_p, prime_test_rng, 1)) {
4,886✔
286
            continue;
4,738✔
287
         }
288

289
         /*
290
         * Check if p - 1 and coprime are relatively prime.
291
         */
292
         if(gcd(p - 1, coprime) > 1) {
296✔
293
            continue;
×
294
         }
295

296
         if(p.bits() > bits) {
148✔
297
            break;
298
         }
299

300
         if(is_miller_rabin_probable_prime(p, mod_p, prime_test_rng, mr_trials)) {
148✔
301
            return p;
296✔
302
         }
303
      }
4,886✔
304
   }
296✔
305
}
306

307
/*
308
* Generate a random safe prime
309
*/
310
BigInt random_safe_prime(RandomNumberGenerator& rng, size_t bits) {
8✔
311
   if(bits <= 64) {
8✔
312
      throw Invalid_Argument("random_safe_prime: Can't make a prime of " + std::to_string(bits) + " bits");
×
313
   }
314

315
   const size_t error_bound = 128;
8✔
316

317
   BigInt q;
8✔
318
   BigInt p;
8✔
319
   for(;;) {
207✔
320
      /*
321
      Generate q == 2 (mod 3), since otherwise [in the case of q == 1 (mod 3)],
322
      2*q+1 == 3 (mod 3) and so certainly not prime.
323
      */
324
      q = random_prime(rng, bits - 1, BigInt::zero(), 2, 3, error_bound);
207✔
325
      p = (q << 1) + 1;
414✔
326

327
      if(is_prime(p, rng, error_bound, true)) {
207✔
328
         return p;
8✔
329
      }
330
   }
331
}
8✔
332

333
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc