Prime number generator and tester.
[u/mdw/catacomb] / pgen.c
CommitLineData
0f5ec153 1/* -*-c-*-
2 *
3 * $Id: pgen.c,v 1.1 1999/11/19 13:17:57 mdw Exp $
4 *
5 * Finding and testing prime numbers
6 *
7 * (c) 1999 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Catacomb.
13 *
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: pgen.c,v $
33 * Revision 1.1 1999/11/19 13:17:57 mdw
34 * Prime number generator and tester.
35 *
36 */
37
38/*----- Header files ------------------------------------------------------*/
39
40#include "mp.h"
41#include "mpmont.h"
42#include "pgen.h"
43#include "ptab.h"
44#include "rabin.h"
45
46/*----- Main code ---------------------------------------------------------*/
47
48/* --- @pgen_create@ --- *
49 *
50 * Arguments: @pgen *p@ = pointer to prime generation context
51 * @mp *m@ = pointer to initial number to test
52 *
53 * Returns: One of the @PGEN@ constants above.
54 *
55 * Use: Tests an initial number for primality by computing its
56 * residue modulo various small prime numbers. This is fairly
57 * quick, but not particularly certain. If a @PGEN_MAYBE@
58 * result is returned, perform Rabin-Miller tests to confirm.
59 */
60
61int pgen_create(pgen *p, mp *m)
62{
63 int rc = PGEN_MAYBE;
64 int i;
65 mp *r = MP_NEW;
66 mpw qw;
67 mp q;
68
69 /* --- Take a copy of the number --- */
70
71 mp_shrink(m);
72 p->m = MP_COPY(m);
73
74 /* --- Fill in the residues --- */
75
76 mp_build(&q, &qw, &qw + 1);
77 for (i = 0; i < NPRIME; i++) {
78 qw = ptab[i];
79 mp_div(0, &r, m, &q);
80 p->r[i] = r->v[0];
81 if (!p->r[i] && rc == PGEN_MAYBE) {
82 if (MP_LEN(m) == 1 && m->v[0] == ptab[i])
83 rc = PGEN_PRIME;
84 else
85 rc = PGEN_COMPOSITE;
86 }
87 }
88
89 /* --- Done --- */
90
91 mp_drop(r);
92 return (rc);
93}
94
95/* --- @pgen_destroy@ --- *
96 *
97 * Arguments: @pgen *p@ = pointer to prime generation context
98 *
99 * Returns: ---
100 *
101 * Use: Discards a context and all the resources it holds.
102 */
103
104void pgen_destroy(pgen *p)
105{
106 mp_drop(p->m);
107}
108
109/* --- @pgen_step@ --- *
110 *
111 * Arguments: @pgen *p@ = pointer to prime generation context
112 * @mpw step@ = how much to step the number
113 *
114 * Returns: One of the @PGEN@ constants above.
115 *
116 * Use: Steps a number by a small amount. Stepping is much faster
117 * than initializing with a new number. The test performed is
118 * the same simple one used by @ptab_create@, so @PGEN_MAYBE@
119 * results should be followed up by a Rabin-Miller test.
120 */
121
122int pgen_step(pgen *p, mpw step)
123{
124 mp s;
125 int rc = PGEN_MAYBE;
126 int i;
127
128 /* --- Add the step on to the number --- */
129
130 mp_build(&s, &step, &step + 1);
131 p->m = mp_add(p->m, p->m, &s);
132
133 /* --- Update the residue table --- */
134
135 for (i = 0; i < NPRIME; i++) {
136 p->r[i] = (p->r[i] + step) % ptab[i];
137 if (!p->r[i] && rc == PGEN_MAYBE) {
138 if (MP_LEN(p->m) == 1 && p->m->v[0] == ptab[i])
139 rc = PGEN_PRIME;
140 else
141 rc = PGEN_COMPOSITE;
142 }
143 }
144
145 /* --- Done --- */
146
147 return (rc);
148}
149
150/* --- @pgen_jump@ --- *
151 *
152 * Arguments: @pgen *p@ = pointer to prime generation context
153 * @pgen *j@ = pointer to another generation context
154 *
155 * Returns: One of the @PGEN@ constants above.
156 *
157 * Use: Steps a number by a large amount. Even so, jumping is much
158 * faster than initializing a new number. The test peformed is
159 * the same simple one used by @ptab_create@, so @PGEN_MAYBE@
160 * results should be followed up by a Rabin-Miller test.
161 *
162 * Note that the number stored in the @j@ context is probably
163 * better off being even than prime. The important thing is
164 * that all of the residues for the number have already been
165 * computed.
166 */
167
168int pgen_jump(pgen *p, pgen *j)
169{
170 int rc = PGEN_MAYBE;
171 int i;
172
173 /* --- Add the step on --- */
174
175 p->m = mp_add(p->m, p->m, j->m);
176
177 /* --- Update the residue table --- */
178
179 for (i = 0; i < NPRIME; i++) {
180 p->r[i] = p->r[i] + j->r[i];
181 if (p->r[i] > ptab[i])
182 p->r[i] -= ptab[i];
183 if (!p->r[i] && rc == PGEN_MAYBE) {
184 if (MP_LEN(p->m) == 1 && p->m->v[0] == ptab[i])
185 rc = PGEN_PRIME;
186 else
187 rc = PGEN_COMPOSITE;
188 }
189 }
190
191 /* --- Done --- */
192
193 return (rc);
194}
195
196/*----- Test code ---------------------------------------------------------*/
197
198#ifdef TEST_RIG
199
200#include <mLib/testrig.h>
201
202static int verify(dstr *v)
203{
204 mp *m = *(mp **)v[0].buf;
205 mp *r = *(mp **)v[1].buf;
206 pgen p;
207 mpw gw;
208 mp g;
209 int rc;
210 static char baton[] = "/-\\|";
211 char *b = baton;
212 int ok = 1;
213
214 mp_build(&g, &gw, &gw + 1);
215 rc = pgen_create(&p, m);
216 for (;;) {
217 if (rc == PGEN_PRIME)
218 break;
219 if (rc == PGEN_MAYBE) {
220 int i;
221 rabin r;
222 rabin_create(&r, p.m);
223 for (i = 0; i < 5; i++) {
224 gw = rand();
225 if (rabin_test(&r, &g) == PGEN_COMPOSITE)
226 break;
227 }
228 rabin_destroy(&r);
229 if (i == 5)
230 break;
231 putc(*b++, stderr);
232 putc('\b', stderr);
233 if (!*b)
234 b = baton;
235 }
236 rc = pgen_step(&p, 2);
237 }
238
239 if (MP_CMP(p.m, !=, r)) {
240 fputs("\n*** failed.", stderr);
241 fputs("\nm = ", stderr); mp_writefile(m, stderr, 10);
242 fputs("\np = ", stderr); mp_writefile(p.m, stderr, 10);
243 fputs("\nr = ", stderr); mp_writefile(r, stderr, 10);
244 fputc('\n', stderr);
245 ok = 0;
246 }
247
248 mp_drop(m);
249 mp_drop(r);
250 pgen_destroy(&p);
251 return (ok);
252}
253
254static test_chunk tests[] = {
255 { "pgen", verify, { &type_mp, &type_mp, 0 } },
256 { 0, 0, { 0 } }
257};
258
259int main(int argc, char *argv[])
260{
261 sub_init();
262 test_run(argc, argv, tests, SRCDIR "/tests/pgen");
263 return (0);
264}
265
266#endif
267
268/*----- That's all, folks -------------------------------------------------*/