File Coverage

random_prime.c
Criterion Covered Total %
statement 91 101 90.1
branch 57 72 79.1
condition n/a
subroutine n/a
pod n/a
total 148 173 85.5


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include "csprng.h"
4             #include "primality.h"
5             #include "util.h"
6             #include "prime_counts.h"
7             #include "mulmod.h"
8             #include "constants.h"
9             #include "random_prime.h"
10              
11 67           UV random_nbit_prime(void* ctx, UV b)
12             {
13 67           uint32_t start = 0, range;
14             UV n, p;
15 67           switch (b) {
16 0           case 0:
17 0           case 1: return 0;
18 1 50         case 2: return urandomb(ctx,1) ? 2 : 3;
19 1 50         case 3: return urandomb(ctx,1) ? 5 : 7;
20 1 50         case 4: return urandomb(ctx,1) ? 11 : 13;
21 3           case 5: start = 7; range = 5; break;
22 1           case 6: start = 12; range = 7; break;
23 1           case 7: start = 19; range = 13; break;
24 1           case 8: start = 32; range = 23; break;
25 1           case 9: start = 55; range = 43; break;
26 57           default: break;
27             }
28              
29 64 100         if (start)
30 7           return nth_prime(start + urandomm32(ctx,range));
31              
32 57 50         if (b > BITS_PER_WORD)
33 0           return 0;
34              
35             /* Trivial method */
36 57           p = (UVCONST(1) << (b-1)) + 1;
37             while (1) {
38 575           n = p + (urandomb(ctx,b-2) << 1);
39 575 100         if (is_prob_prime(n))
40 57           return n;
41             }
42             }
43              
44 16           UV random_ndigit_prime(void* ctx, UV d)
45             {
46             UV lo, hi;
47 16 50         if (d == 0) return 0;
48 16 100         if (d == 1) return nth_prime(1 + urandomm32(ctx,4));
49 15 100         if (d == 2) return nth_prime(5 + urandomm32(ctx,21));
50 14 100         if (d >= (BITS_PER_WORD == 64 ? 20 : 10)) return 0;
51 11           lo = powmod(10,d-1,UV_MAX)+1;
52 11           hi = 10*lo-11;
53 72           while (1) {
54 83           UV n = (lo + urandomm64(ctx,hi-lo+1)) | 1;
55 83 100         if (is_prob_prime(n))
56 11           return n;
57             }
58             }
59              
60 11027           UV random_prime(void* ctx, UV lo, UV hi)
61             {
62             UV n, oddrange;
63 11027 100         if (lo > hi) return 0;
64             /* Pull edges in to nearest primes */
65 11025 100         lo = (lo <= 2) ? 2 : next_prime(lo-1);
66 11025 50         hi = (hi >= MPU_MAX_PRIME) ? MPU_MAX_PRIME : prev_prime(hi+1);
67 11025 100         if (lo > hi) return 0;
68             /* There must be at least one prime in the range */
69 11021 100         if (!(lo&1)) lo--; /* treat 2 as 1 */
70 11021           oddrange = ((hi-lo)>>1) + 1; /* look for odds */
71             while (1) {
72 28836           n = lo + 2 * urandomm64(ctx, oddrange);
73 28836 100         if (n == 1 || is_prob_prime(n))
    100          
74 11021 100         return (n == 1) ? 2 : n;
75             }
76             }
77              
78             /* Note that 7 chosen bases or the first 12 prime bases are enough
79             * to guarantee sucess. We could choose to limit to those. */
80 4           bool is_mr_random(void* ctx, UV n, UV k) {
81 4 50         if (k >= 3*(n/4))
82 0           return is_prob_prime(n);
83              
84             /* TODO: do 16 at a time */
85 22 100         while (k--) {
86 19           UV base = 2 + urandomm64(ctx, n-2);
87 19 100         if (!is_strong_pseudoprime(n, base))
88 1           return 0;
89             }
90 3           return 1;
91             }
92              
93 9           UV random_semiprime(void* ctx, UV b) { /* Even split of bits */
94             static const uint16_t small_semi[] = {35,35,49,65,77,91,143,143,169,299,319,341,377,403};
95             UV min, max, n, L, N;
96              
97 9 50         if (b < 4 || b > BITS_PER_WORD)
    50          
98 0           return 0;
99              
100 9           switch (b) {
101 2           case 4: return 9;
102 1           case 5: return 21;
103 1           case 6: return small_semi[ 0 + urandomm32(ctx,3) ];
104 1           case 7: return small_semi[ 3 + urandomm32(ctx,3) ];
105 1           case 8: return small_semi[ 6 + urandomm32(ctx,3) ];
106 1           case 9: return small_semi[ 9 + urandomm32(ctx,5) ];
107 2           default: break;
108             }
109              
110 2           min = UVCONST(1) << (b-1);
111 2           max = min + (min-1);
112 2           L = b / 2;
113 2           N = b - L;
114              
115             do {
116 2           n = random_nbit_prime(ctx,L) * random_nbit_prime(ctx,N);
117 2 50         } while (n < min || n > max);
    50          
118 2           return n;
119             }
120              
121 8           UV random_unrestricted_semiprime(void* ctx, UV b) { /* generic semiprime */
122             static const unsigned char small_semi[] = {4,6,9,10,14,15,21,22,25,26,33,34,35,38,39,46,49,51,55,57,58,62,65,69,74,77,82,85,86,87,91,93,94,95,106,111,115,118,119,121,122,123};
123             UV min, n;
124              
125 8 50         if (b < 3 || b > BITS_PER_WORD)
    50          
126 0           return 0;
127              
128 8           switch (b) {
129 1           case 3: return small_semi[ 0 + urandomm32(ctx, 2) ];
130 1           case 4: return small_semi[ 2 + urandomm32(ctx, 4) ];
131 1           case 5: return small_semi[ 6 + urandomm32(ctx, 4) ];
132 1           case 6: return small_semi[ 10 + urandomm32(ctx,12) ];
133 1           case 7: return small_semi[ 22 + urandomm32(ctx,20) ];
134 3           default: break;
135             }
136             /* There are faster ways to generate if we could be lax on distribution.
137             * Picking a random prime followed by a second that makes a semiprime in
138             * the range seems obvious and is fast, but the distribution is wrong.
139             * With that method, some semiprimes are much more likely than others. */
140 3           min = UVCONST(1) << (b-1);
141             do {
142 7           n = min + urandomb(ctx,b-1);
143 7 100         } while (!is_semiprime(n));
144 3           return n;
145             }
146              
147 4           UV random_safe_prime(void* ctx, UV bits)
148             {
149             static const unsigned char small_safe[] = {5,7,11,23,47,59,83,107};
150 4           const uint16_t p15mask = 14079;
151             UV p, q, B;
152              
153 4 50         if (bits < 3 || bits > BITS_PER_WORD)
    50          
154 0           return 0;
155              
156 4           switch (bits) {
157 1           case 3: return small_safe[ 0 + urandomm32(ctx, 2) ];
158 0           case 4: return 11;
159 1           case 5: return 23;
160 0           case 6: return small_safe[ 4 + urandomm32(ctx, 2) ];
161 0           case 7: return small_safe[ 6 + urandomm32(ctx, 2) ];
162 2           default: break;
163             }
164              
165             /* do { q = 2 * random_nbit_prime(ctx, bits-1) + 1; } while (!is_prob_prime(q)); */
166              
167             /* Alternately we could construct p with last 2 bits set, then q = p >> 1. */
168 2           B = (UVCONST(1) << (bits-2)) + 1;
169             do {
170 530           p = B + (urandomb(ctx, bits-3) << 1);
171 530           q = 2*p+1;
172 619           } while ( (p15mask & (1U << (p%15))) ||
173 89 100         (p%7) == 0 || (p%7) == 3 ||
    100          
174 597 100         !is_prob_prime(p) || !is_prob_prime(q) );
    100          
    100          
175              
176 2           return q;
177             }