*.py: Hack around Python exception-catching syntax mismatch.
[catacomb-python] / pock
1 #! /usr/bin/python
2 ### -*- mode: python, coding: utf-8 -*-
3 ###
4 ### Tool for generating and verifying primality certificates
5 ###
6 ### (c) 2017 Straylight/Edgeware
7 ###
8
9 ###----- Licensing notice ---------------------------------------------------
10 ###
11 ### This file is part of the Python interface to Catacomb.
12 ###
13 ### Catacomb/Python is free software; you can redistribute it and/or modify
14 ### it under the terms of the GNU General Public License as published by
15 ### the Free Software Foundation; either version 2 of the License, or
16 ### (at your option) any later version.
17 ###
18 ### Catacomb/Python is distributed in the hope that it will be useful,
19 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ### GNU General Public License for more details.
22 ###
23 ### You should have received a copy of the GNU General Public License
24 ### along with Catacomb/Python; if not, write to the Free Software Foundation,
25 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27 ###--------------------------------------------------------------------------
28 ### Imported modules.
29
30 from sys import argv, stdin, stdout, stderr
31 import os as OS
32 import itertools as I
33 import math as M
34 import optparse as OP
35
36 import catacomb as C
37
38 ###--------------------------------------------------------------------------
39 ### Utilities.
40
41 def _excval():
42 """Return the most recent exception object."""
43 return SYS.exc_info()[1]
44
45 class ExpectedError (Exception):
46 """
47 I represent an expected error, which should be reported in a friendly way.
48 """
49 pass
50
51 def prod(ff, one = 1):
52 """
53 Return ONE times the product of the elements of FF.
54
55 This is not done very efficiently.
56 """
57 return reduce(lambda prod, f: prod*f, ff, one)
58
59 def parse_label(line):
60 """
61 Split LINE at an `=' character and return the left and right halves.
62
63 The returned pieces have leading and trailing whitespace trimmed.
64 """
65 eq = line.find('=')
66 if eq < 0: raise ExpectedError('expected `LABEL = ...\'')
67 return line[:eq].strip(), line[eq + 1:].strip()
68
69 def parse_list(s, n):
70 l = s.split(',', n - 1)
71 if n is not None and len(l) != n:
72 raise ExpectedError('expected `,\'-separated list of %d items' % n)
73 return l
74
75 def conv_int(s):
76 """Convert S to a integer."""
77 try: return C.MP(s, 0)
78 except TypeError: raise ExpectedError('invalid integer `%s\'' % s)
79
80 VERBOSITY = 1
81
82 class ProgressReporter (object):
83 """
84 I keep users amused while the program looks for large prime numbers.
85
86 My main strategy is the printing of incomprehensible runes. I can be
87 muffled by lowering by verbosity level.
88
89 Prime searches are recursive in nature. When a new recursive level is
90 started, call `push'; and call `pop' when the level is finished. This must
91 be done around the top level too.
92 """
93 def __init__(me):
94 """Initialize the ProgressReporter."""
95 me._level = -1
96 me._update()
97 def _update(me):
98 """
99 Update our idea of whether we're active.
100
101 We don't write inscrutable runes when inactive. The current policy is to
102 write nothing if verbosity is zero, to write runes for the top level only
103 if verbosity is 1, and to write runes always if verbosity is higher than
104 that.
105 """
106 me._active = VERBOSITY >= 2 or (VERBOSITY == 1 and me._level == 0)
107 def push(me):
108 """Push a new search level."""
109 me._level += 1
110 me._update()
111 if me._level > 0: me.p('[')
112 else: me.p(';; ')
113 def pop(me):
114 """Pop a search level."""
115 if me._level > 0: me.p(']')
116 else: me.p('\n')
117 me._level -= 1
118 me._update()
119 def p(me, ch):
120 """Print CH as a progress rune."""
121 if me._active: stderr.write(ch); stderr.flush()
122
123 def combinations(r, v):
124 """
125 Return an iterator which yields all combinations of R elements from V.
126
127 V must be an indexable sequence. The each combination is returned as a
128 list, containing elements from V in their original order.
129 """
130
131 ## Set up the selection vector. C will contain the indices of the items of
132 ## V we've selected for the current combination. At all times, C contains
133 ## a strictly increasing sequence of integers in the interval [0, N).
134 n = len(v)
135 c = range(r)
136
137 while True:
138
139 ## Yield up the current combination.
140 vv = [v[i] for i in c]
141 yield vv
142
143 ## Now advance to the next one. Find the last index in C which we can
144 ## increment subject to the rules. As we iterate downwards, i will
145 ## contain the index into C, and j will be the maximum acceptable value
146 ## for the corresponding item. We'll step the last index until it
147 ## reaches the limit, and then step the next one down, resetting the last
148 ## index, and so on.
149 i, j = r, n
150 while True:
151
152 ## If i is zero here, then we've advanced everything as far as it will
153 ## go. We're done.
154 if i == 0: return
155
156 ## Move down to the next index.
157 i -= 1; j -= 1
158
159 ## If this index isn't at its maximum value, then we've found the place
160 ## to step.
161 if c[i] != j: break
162
163 ## Step this index on by one, and set the following indices to the
164 ## immediately following values.
165 j = c[i] + 1
166 while i < r: c[i] = j; i += 1; j += 1
167
168 class ArgFetcher (object):
169 """
170 I return arguments from a list, reporting problems when they occur.
171 """
172 def __init__(me, argv, errfn):
173 """
174 Initialize, returning successive arguments from ARGV.
175
176 Errors are reported to ERRFN.
177 """
178 me._argv = argv
179 me._argc = len(argv)
180 me._errfn = errfn
181 me._i = 0
182 def arg(me, default = None, must = True):
183 """
184 Return the next argument.
185
186 If MUST is true, then report an error (to the ERRFN) if there are no more
187 arguments; otherwise, return the DEFAULT.
188 """
189 if me._i >= me._argc:
190 if must: me._errfn('missing argument')
191 return default
192 arg = me._argv[me._i]; me._i += 1
193 return arg
194 def int(me, default = None, must = True, min = None, max = None):
195 """
196 Return the next argument converted to an integer.
197
198 If MUST is true, then report an error (to the ERRFN) if there are no more
199 arguments; otherwise return the DEFAULT. Report an error if the next
200 argument is not a valid integer, or if the integer is beyond the MIN and
201 MAX bounds.
202 """
203 arg = me.arg(default = None, must = must)
204 if arg is None: return default
205 try: arg = int(arg)
206 except ValueError: me._errfn('bad integer')
207 if (min is not None and arg < min) or (max is not None and arg > max):
208 me._errfn('out of range')
209 return arg
210
211 ###--------------------------------------------------------------------------
212 ### Sieving for small primes.
213
214 class Sieve (object):
215 """
216 I represent a collection of small primes, up to some chosen limit.
217
218 The limit is available as the `limit' attribute. Let L be this limit;
219 then, if N < L^2 is some composite, then N has at least one prime factor
220 less than L.
221 """
222
223 ## Figure out the number of bits in a (nonnegative) primitive `int'. We'll
224 ## use a list of these as our sieve.
225 _NBIT = 15
226 while type(1 << (_NBIT + 1)) == int: _NBIT += 1
227
228 def __init__(me, limit):
229 """
230 Initialize a sieve holding all primes below LIMIT.
231 """
232
233 ## The sieve is maintained in the `_bits' attribute. This is a list of
234 ## integers, used as a bitmask: let 2 < n < L be an odd integer; then bit
235 ## (n - 3)/2 will be clear iff n is prime. Let W be the value of
236 ## `_NBIT', above; then bit W i + j in the sieve is stored in bit j of
237 ## `_bits[i]'.
238
239 ## Store the limit for later inspection.
240 me.limit = limit
241
242 ## Calculate the size of sieve we'll need and initialize the bit list.
243 n = (limit - 2)/2
244 sievesz = (n + me._NBIT - 1)/me._NBIT
245 me._sievemax = sievesz*me._NBIT
246 me._bits = sievesz*[0]
247
248 ## This is standard Sieve of Eratosthenes. For each index i: if
249 ## bit i is clear, then p = 2 i + 3 is prime, so set the bits
250 ## corresponding to each multiple of p, i.e., bits (k p - 3)/2 =
251 ## (2 k i + 3 - 3)/2 = k i for k > 1.
252 for i in xrange(me._sievemax):
253 if me._bitp(i): i += 1; continue
254 p = 2*i + 3
255 if p >= limit: break
256 for j in xrange(i + p, me._sievemax, p): me._setbit(j)
257 i += 1
258
259 def _bitp(me, i): i, j = divmod(i, me._NBIT); return (me._bits[i] >> j)&1
260 def _setbit(me, i): i, j = divmod(i, me._NBIT); me._bits[i] |= 1 << j
261
262 def smallprimes(me):
263 """
264 Return an iterator over the known small primes.
265 """
266 yield 2
267 n = 3
268 for b in me._bits:
269 for j in xrange(me._NBIT):
270 if not (b&1): yield n
271 b >>= 1; n += 2
272
273 ## We generate the sieve on demand.
274 SIEVE = None
275
276 def initsieve(sievebits):
277 """
278 Generate the sieve.
279
280 Ensure that it can be used to check the primality of numbers up to (but not
281 including) 2^SIEVEBITS.
282 """
283 global SIEVE
284 if SIEVE is not None: raise ValueError('sieve already defined')
285 if sievebits < 6: sievebits = 6
286 SIEVE = Sieve(1 << (sievebits + 1)/2)
287
288 ###--------------------------------------------------------------------------
289 ### Primality checking.
290
291 def small_test(p):
292 """
293 Check that P is a small prime.
294
295 If not, raise an `ExpectedError'. The `SIEVE' variable must have been
296 initialized.
297 """
298 if p < 2: raise ExpectedError('%d too small' % p)
299 if SIEVE.limit*SIEVE.limit < p:
300 raise ExpectedError('%d too large for small prime' % p)
301 for q in SIEVE.smallprimes():
302 if q*q > p: return
303 if p%q == 0: raise ExpectedError('%d divides %d' % (q, p))
304
305 def pock_test(p, a, qq):
306 """
307 Check that P is prime using Pocklington's criterion.
308
309 If not, raise an `ExpectedError'.
310
311 Let Q be the product of the elements of the sequence QQ. The test works as
312 follows. Suppose p is the smallest prime factor of P. If A^{P-1} /== 1
313 (mod P) then P is certainly composite (Fermat's test); otherwise, we have
314 established that the order of A in (Z/pZ)^* divides P - 1. Next, let t =
315 A^{(P-1)/q} for some prime factor q of Q, and let g = gcd(t - 1, P). If g
316 = P then the proof is inconclusive; if 1 < g < P then g is a nontrivial
317 factor of P, so P is composite; otherwise, t has order q in (Z/pZ)^*, so
318 (Z/pZ)^* contains a subgroup of size q, and therefore q divides p - 1. If
319 QQ is a sequence of distinct primes, and the preceding criterion holds for
320 all q in QQ, then Q divides p - 1. If Q^2 < P then the proof is
321 inconclusive; otherwise, let p' be any prime dividing P/p. Then p' >= p >
322 Q, so p p' > Q^2 > P; but p p' divides P, so this is a contradiction.
323 Therefore P/p has no prime factors, and P is prime.
324 """
325
326 ## We don't actually need the distinctness criterion. Suppose that q^e
327 ## divides Q. Then gcd(t - 1, P) = 1 implies that A^{(P-1)/q^{e-1}} has
328 ## order q^e in (Z/pZ)^*, which accounts for the multiplicity.
329
330 Q = prod(qq)
331 if p < 2: raise ExpectedError('%d too small' % p)
332 if Q*Q <= p:
333 raise ExpectedError('too few Pocklington factors for %d' % p)
334 if pow(a, p - 1, p) != 1:
335 raise ExpectedError('%d is Fermat witness for %d' % (a, p))
336 for q in qq:
337 if Q%(q*q) == 0:
338 raise ExpectedError('duplicate Pocklington factor %d for %d' % (q, p))
339 g = p.gcd(pow(a, (p - 1)/q, p) - 1)
340 if g == p:
341 raise ExpectedError('%d order not multiple of %d mod %d' % (a, q, p))
342 elif g != 1:
343 raise ExpectedError('%d divides %d' % (g, p))
344
345 def ecpp_test(p, a, b, x, y, qq):
346 """
347 Check that P is prime using Goldwasser and Kilian's ECPP method.
348
349 If not, raise an `ExpectedError'.
350
351 Let Q be the product of the elements of the sequence QQ. Suppose p is the
352 smallest prime factor of P. Let g = gcd(4 A^3 + 27 B^2, P). If g = P then
353 the test is inconclusive; otherwise, if g /= 1 then g is a nontrivial
354 factor of P. Define E(GF(p)) = { (x, y) | y^2 = x^3 + A x + B } U { inf }
355 to be the elliptic curve over p with short-Weierstraß coefficients A and B;
356 we have just checked that this curve is not singular. If R = (X, Y) is not
357 a point on this curve, then the test is inconclusive. If Q R is not the
358 point at infinity, then the test fails; otherwise we deduce that P has
359 Q-torsion in E. Let S = (Q/q) R for some prime factor q of Q. If S is the
360 point at infinity then the test is inconclusive; otherwise, q divides the
361 order of S in E. If QQ is a sequence of distinct primes, and the preceding
362 criterion holds for all q in QQ, then Q divides the order of S. Therefore
363 #E(p) >= Q. If Q <= (qrrt(P) + 1)^2 then the test is inconclusive.
364 Otherwise, Hasse's theorem tells us that |p + 1 - #E(p)| <= 2 sqrt(p);
365 hence we must have p + 1 + 2 sqrt(p) = (sqrt(p) + 1)^2 >= #E(p) >= Q >
366 (qrrt(P) + 1)^2; so sqrt(p) + 1 > qrrt(P) + 1, i.e., p^2 > P. As for
367 Pocklington above, if p' is any prime factor of P/p, then p p' >= p^2 > P,
368 which is a contradiction, and we conclude that P is prime.
369 """
370
371 ## This isn't going to work if gcd(P, 6) /= 1: we're going to use the
372 ## large-characteristic addition formulae.
373 g = p.gcd(6)
374 if g != 1: raise ExpectedError('%d divides %d' % (g, p))
375
376 ## We want to check that Q > (qrrt(P) + 1)^2 iff sqrt(Q) > qrrt(P) + 1; but
377 ## calculating square roots is not enjoyable (partly because we have to
378 ## deal with the imprecision). Fortunately, some algebra will help: the
379 ## condition holds iff qrrt(P) < sqrt(Q) - 1 iff P < Q^2 - 4 Q sqrt(Q) +
380 ## 6 Q - 4 sqrt(Q) + 1 = Q (Q + 6) + 1 - 4 sqrt(Q) (Q + 1) iff Q (Q + 6) -
381 ## P + 1 > 4 sqrt(Q) (Q + 1) iff (Q (Q + 6) - P + 1)^2 > 16 Q (Q + 1)^2
382 Q = prod(qq)
383 t, u = Q*(Q + 6) - p + 1, 4*(Q + 1)
384 if t*t <= Q*u*u: raise ExpectedError('too few subgroups for ECPP')
385
386 ## Construct the curve.
387 E = C.PrimeField(p).ec(a, b) # careful: may not be a prime!
388
389 ## Find the base point.
390 R = E(x, y)
391 if not R.oncurvep():
392 raise ExpectedError('(%d, %d) is not on the curve' % (x, y))
393
394 ## Check that it has Q-torsion.
395 if Q*R: raise ExpectedError('(%d, %d) not a %d-torsion point' % (x, y, Q))
396
397 ## Now check the individual factors.
398 for q in qq:
399 if Q%(q*q) == 0:
400 raise ExpectedError('duplicate ECPP factor %d for %d' % (q, p))
401 S = (Q/q)*R
402 if not S:
403 raise ExpectedError('(%d, %d) order not a multiple of %d' % (x, y, q))
404 g = p.gcd(S._z)
405 if g != 1:
406 raise ExpectedError('%d divides %d' % (g, p))
407
408 ###--------------------------------------------------------------------------
409 ### Proof steps and proofs.
410
411 class BaseStep (object):
412 """
413 I'm a step in a primality proof.
414
415 I assert that a particular number is prime, and can check this.
416
417 This class provides basic protocol for proof steps, mostly to do with
418 handling labels.
419
420 The step's label is kept in its `label' attribute. It can be set by the
421 constructor, and is `None' by default. Users can modify this attribute if
422 they like. Labels beginning `$' are assumed to be internal and
423 uninteresting; other labels cause `check' lines to be written to the output
424 listing the actual number of interest.
425
426 Protocol that proof steps should provide:
427
428 label A string labelling the proof step and the associated prime
429 number.
430
431 p The prime number which this step proves to be prime.
432
433 check() Check that the proof step is actually correct, assuming that
434 any previous steps have already been verified.
435
436 out(FILE) Write an appropriate encoding of the proof step to the output
437 FILE.
438 """
439 def __init__(me, label = None, *arg, **kw):
440 """Initialize a proof step, setting a default label if necessary."""
441 super(BaseStep, me).__init__(*arg, **kw)
442 me.label = label
443 def out(me, file):
444 """
445 Write the proof step to an output FILE.
446
447 Subclasses must implement a method `_out' which actually does the work.
448 Here, we write a `check' line to verify that the proof actually applies
449 to the number we wanted, if the label says that this is an interesting
450 step.
451 """
452 me._out(file)
453 if me.label is not None and not me.label.startswith('$'):
454 file.write('check %s, %d, %d\n' % (me.label, me.p.nbits, me.p))
455
456 class SmallStep (BaseStep):
457 """
458 I represent a claim that a number is a small prime.
459
460 Such claims act as the base cases in a complicated primality proof. When
461 verifying, the claim is checked by trial division using a collection of
462 known small primes.
463 """
464 def __init__(me, pp, p, *arg, **kw):
465 """
466 Initialize a small-prime step.
467
468 PP is the overall PrimeProof object of which this is a step; P is the
469 small number whose primality is asserted.
470 """
471 super(SmallStep, me).__init__(*arg, **kw)
472 me.p = p
473 def check(me):
474 """Check that the number is indeed a small prime."""
475 return small_test(me.p)
476 def _out(me, file):
477 """Write a small-prime step to the FILE."""
478 file.write('small %s = %d\n' % (me.label, me.p))
479 def __repr__(me): return 'SmallStep(%d)' % (me.p)
480 @classmethod
481 def parse(cls, pp, line):
482 """
483 Parse a small-prime step from a LINE in a proof file.
484
485 SMALL-STEP ::= `small' LABEL `=' P
486
487 PP is a PrimeProof object holding the results from the previous steps.
488 """
489 if SIEVE is None: raise ExpectedError('missing `sievebits\' line')
490 label, p = parse_label(line)
491 return cls(pp, conv_int(p), label = label)
492
493 class PockStep (BaseStep):
494 """
495 I represent a Pocklington certificate for a number.
496
497 The number is not explicitly represented in a proof file. See `pock_test'
498 for the underlying mathematics.
499 """
500 def __init__(me, pp, a, R, qqi, *arg, **kw):
501 """
502 Inititialize a Pocklington step.
503
504 PP is the overall PrimeProof object of which this is a step; A is the
505 generator of a substantial subgroup of units; R is a cofactor; and QQI is
506 a sequence of labels for previous proof steps. If Q is the product of
507 the primes listed in QQI, then the number whose primality is asserted is
508 2 Q R + 1.
509 """
510 super(PockStep, me).__init__(*arg, **kw)
511 me._a = a
512 me._R = R
513 me._qqi = qqi
514 me._qq = [pp.get_step(qi).p for qi in qqi]
515 me.p = prod(me._qq, 2*R) + 1
516 def check(me):
517 """Verify a proof step based on Pocklington's theorem."""
518 return pock_test(me.p, me._a, me._qq)
519 def _out(me, file):
520 """Write a Pocklington step to the FILE."""
521 file.write('pock %s = %d, %d, [%s]\n' % \
522 (me.label, me._a,
523 me._R, ', '.join('%s' % qi for qi in me._qqi)))
524 def __repr__(me): return 'PockStep(%d, %d, %s)' % (me._a, me._R, me._qqi)
525 @classmethod
526 def parse(cls, pp, line):
527 """
528 Parse a Pocklington step from a LINE in a proof file.
529
530 POCK-STEP ::= `pock' LABEL `=' A `,' R `,' `[' Q-LIST `]'
531 Q-LIST ::= Q [`,' Q-LIST]
532
533 PP is a PrimeProof object holding the results from the previous steps.
534 """
535 label, rest = parse_label(line)
536 a, R, qq = parse_list(rest, 3)
537 qq = qq.strip()
538 if not qq.startswith('[') or not qq.endswith(']'):
539 raise ExpectedError('missing `[...]\' around Pocklington factors')
540 return cls(pp, conv_int(a), conv_int(R),
541 [q.strip() for q in qq[1:-1].split(',')], label = label)
542
543 class ECPPStep (BaseStep):
544 """
545 I represent a Goldwasser--Kilian ECPP certificate for a number.
546 """
547 def __init__(me, pp, p, a, b, x, y, qqi, *arg, **kw):
548 """
549 Inititialize an ECPP step.
550
551 PP is the overall PrimeProof object of which this is a step; P is the
552 number whose primality is asserted; A and B are the short Weierstraß
553 curve coefficients; X and Y are the base point coordinates; and QQI is a
554 sequence of labels for previous proof steps.
555 """
556 super(ECPPStep, me).__init__(*arg, **kw)
557 me._a, me._b = a, b
558 me._x, me._y = x, y
559 me._qqi = qqi
560 me._qq = [pp.get_step(qi).p for qi in qqi]
561 me.p = p
562 def check(me):
563 """Verify a proof step based on Goldwasser and Kilian's theorem."""
564 return ecpp_test(me.p, me._a, me._b, me._x, me._y, me._qq)
565 def _out(me, file):
566 """Write an ECPP step to the FILE."""
567 file.write('ecpp %s = %d, %d, %d, %d, %d, [%s]\n' % \
568 (me.label, me.p, me._a, me._b, me._x, me._y,
569 ', '.join('%s' % qi for qi in me._qqi)))
570 def __repr__(me):
571 return 'ECPPstep(%d, %d, %d, %d, %d, %s)' % \
572 (me.p, me._a, me._b, me._x, me._y, me._qqi)
573 @classmethod
574 def parse(cls, pp, line):
575 """
576 Parse an ECPP step from a LINE in a proof file.
577
578 ECPP-STEP ::= `ecpp' LABEL `=' P `,' A `,' B `,' X `,' Y `,'
579 `[' Q-LIST `]'
580 Q-LIST ::= Q [`,' Q-LIST]
581
582 PP is a PrimeProof object holding the results from the previous steps.
583 """
584 label, rest = parse_label(line)
585 p, a, b, x, y, qq = parse_list(rest, 6)
586 qq = qq.strip()
587 if not qq.startswith('[') or not qq.endswith(']'):
588 raise ExpectedError('missing `[...]\' around ECPP factors')
589 return cls(pp, conv_int(p), conv_int(a), conv_int(b),
590 conv_int(x), conv_int(y),
591 [q.strip() for q in qq[1:-1].split(',')], label = label)
592
593 def check(pp, line):
594 """
595 Handle a `check' line in a proof file.
596
597 CHECK ::= `check' LABEL, B, N
598
599 Verify that the proof step with the given LABEL asserts the primality of
600 the integer N, and that 2^{B-1} <= N < 2^B.
601 """
602 label, nb, p = parse_list(line, 3)
603 label, nb, p = label.strip(), conv_int(nb), conv_int(p)
604 pi = pp.get_step(label).p
605 if pi != p:
606 raise ExpectedError('check failed: %s = %d /= %d' % (label, pi, p))
607 if p.nbits != nb:
608 raise ExpectedError('check failed: nbits(%s) = %d /= %d' % \
609 (label, p.nbits, nb))
610 if VERBOSITY: print ';; %s = %d [%d]' % (label, p, nb)
611
612 def setsievebits(pp, line):
613 """
614 Handle a `sievebits' line in a proof file.
615
616 SIEVEBITS ::= `sievebits' N
617
618 Ensure that the verifier is willing to accept small primes up to 2^N.
619 """
620 initsieve(int(line))
621
622 class PrimeProof (object):
623 """
624 I represent a proof of primality for one or more numbers.
625
626 I can encode my proof as a line-oriented text file, in a simple format, and
627 read such a proof back to check it.
628 """
629
630 ## A table to dispatch on keywords read from a file.
631 STEPMAP = { 'small': SmallStep.parse,
632 'pock': PockStep.parse,
633 'ecpp': ECPPStep.parse,
634 'sievebits': setsievebits,
635 'check': check }
636
637 def __init__(me):
638 """
639 Initialize a proof object.
640 """
641 me._steps = {} # Maps labels to steps.
642 me._stepseq = [] # Sequence of labels, in order.
643 me._pmap = {} # Maps primes to steps.
644 me._i = 0
645
646 def addstep(me, step):
647 """
648 Add a new STEP to the proof.
649
650 The STEP may have a label already. If not, a new internal label is
651 chosen. The proof step is checked before being added to the proof. The
652 label is returned.
653 """
654
655 ## If there's already a step for this prime, and the new step doesn't
656 ## have a label, then return the old one instead.
657 if step.label is None:
658 try: return me._pmap[step.p]
659 except KeyError: pass
660
661 ## Make sure the step is actually correct.
662 step.check()
663
664 ## Generate a label if the step doesn't have one already.
665 if step.label is None: step.label = '$t%d' % me._i; me._i += 1
666
667 ## If the label is already taken then we have a problem.
668 if step.label in me._steps:
669 raise ExpectedError('duplicate label `%s\'' % step.label)
670
671 ## Store the proof step.
672 me._pmap[step.p] = step.label
673 me._steps[step.label] = step
674 me._stepseq.append(step.label)
675 return step.label
676
677 def get_step(me, label):
678 """
679 Check that LABEL labels a known step, and return that step.
680 """
681 try: return me._steps[label]
682 except KeyError: raise ExpectedError('unknown label `%s\'' % label)
683
684 def write(me, file):
685 """
686 Write the proof to the given FILE.
687 """
688
689 ## Prefix the main steps with a `sievebits' line.
690 file.write('sievebits %d\n' % (2*(SIEVE.limit.bit_length() - 1)))
691
692 ## Write the steps out one by one.
693 for label in me._stepseq: me._steps[label].out(file)
694
695 def read(me, file):
696 """
697 Read a proof from a given FILE.
698
699 FILE ::= {STEP | CHECK | SIEVEBITS} [FILE]
700 STEP ::= SMALL-STEP | POCK-STEP
701
702 Comments (beginning `;') and blank lines are ignored. Other lines begin
703 with a keyword.
704 """
705 lastp = None
706 for lno, line in enumerate(file, 1):
707 line = line.strip()
708 if line.startswith(';'): continue
709 ww = line.split(None, 1)
710 if not ww: continue
711 w = ww[0]
712 if len(ww) > 1: tail = ww[1]
713 else: tail = ''
714 try:
715 try: op = me.STEPMAP[w]
716 except KeyError:
717 raise ExpectedError('unrecognized keyword `%s\'' % w)
718 step = op(me, tail)
719 if step is not None:
720 me.addstep(step)
721 lastp = step.p
722 except ExpectedError:
723 raise ExpectedError('%s:%d: %s' %
724 (file.name, lno, _excval().message))
725 return lastp
726
727 ###--------------------------------------------------------------------------
728 ### Finding provable primes.
729
730 class BasePrime (object):
731 """
732 I represent a prime number which has been found and can be proven.
733
734 This object can eventually be turned into a sequence of proof steps and
735 added to a PrimeProof. This isn't done immediately, because some
736 prime-search strategies want to build a pool of provable primes and will
737 then select some subset of them to actually construct the number of final
738 interest. This way, we avoid cluttering the output proof with proofs of
739 uninteresting numbers.
740
741 Protocol required.
742
743 p The prime number in question.
744
745 label(LABEL) Associate LABEL with this prime, and the corresponding proof
746 step. A label can be set in the constructor, or later using
747 this method.
748
749 register(PP) Register the prime with a PrimeProof, adding any necessary
750 proof steps. Returns the label of the proof step for this
751 number.
752
753 _mkstep(PP, **KW)
754 Return a proof step for this prime.
755 """
756 def __init__(me, label = None, *args, **kw):
757 """Initialize a provable prime number object."""
758 super(BasePrime, me).__init__(*args, **kw)
759 me._index = me._pp = None
760 me._label = label
761 def label(me, label):
762 """Set this number's LABEL."""
763 me._label = label
764 def register(me, pp):
765 """
766 Register the prime's proof steps with PrimeProof PP.
767
768 Return the final step's label.
769 """
770 if me._pp is not None:
771 assert me._pp == pp
772 else:
773 me._pp = pp
774 me._index = pp.addstep(me._mkstep(pp, label = me._label))
775 ##try: me._index = pp.addstep(me._mkstep(pp, label = me._label))
776 ##except: raise RuntimeError('generated proof failed sanity check')
777 return me._index
778
779 class SmallPrime (BasePrime):
780 """I represent a prime small enough to be checked in isolation."""
781 def __init__(me, p, *args, **kw):
782 super(SmallPrime, me).__init__(*args, **kw)
783 me.p = p
784 def _mkstep(me, pp, **kw):
785 return SmallStep(pp, me.p, **kw)
786
787 class PockPrime (BasePrime):
788 """I represent a prime proven using Pocklington's theorem."""
789 def __init__(me, p, a, qq, *args, **kw):
790 super(PockPrime, me).__init__(*args, **kw)
791 me.p = p
792 me._a = a
793 me._qq = qq
794 def _mkstep(me, pp, **kw):
795 return PockStep(pp, me._a, (me.p - 1)/prod((q.p for q in me._qq), 2),
796 [q.register(pp) for q in me._qq], **kw)
797
798 def gen_small(nbits, label = None, p = None):
799 """
800 Return a new small prime.
801
802 The prime will be exactly NBITS bits long. The proof step will have the
803 given LABEL attached. Report progress to the ProgressReporter P.
804 """
805 while True:
806
807 ## Pick a random NBITS-bit number.
808 n = C.rand.mp(nbits, 1)
809 assert n.nbits == nbits
810
811 ## If it's probably prime, then check it against the small primes we
812 ## know. If it passes then we're done. Otherwise, try again.
813 if n.primep():
814 for q in SIEVE.smallprimes():
815 if q*q > n: return SmallPrime(n, label = label)
816 if n%q == 0: break
817
818 def gen_pock(nbits, nsubbits = 0, label = None, p = ProgressReporter()):
819 """
820 Return a new prime provable using Pocklington's theorem.
821
822 The prime N will be exactly NBITS long, of the form N = 2 Q R + 1. If
823 NSUBBITS is nonzero, then each prime factor of Q will be NSUBBITS bits
824 long; otherwise a suitable default will be chosen. The proof step will
825 have the given LABEL attached. Report progress to the ProgressReporter P.
826
827 The prime numbers this function returns are a long way from being uniformly
828 distributed.
829 """
830
831 ## Pick a suitable value for NSUBBITS if we don't have one.
832 if not nsubbits:
833
834 ## This is remarkably tricky. Picking about 1/3 sqrt(NBITS) factors
835 ## seems about right for large numbers, but there's serious trouble
836 ## lurking for small sizes.
837 nsubbits = int(3*M.sqrt(nbits))
838 if nbits < nsubbits + 3: nsubbits = nbits//2 + 1
839 if nbits == 2*nsubbits: nsubbits += 1
840
841 ## Figure out how many subgroups we'll need.
842 npiece = ((nbits + 1)//2 + nsubbits - 1)//nsubbits
843 p.push()
844
845 ## Keep searching...
846 while True:
847
848 ## Come up with a collection of known prime factors.
849 p.p('!'); qq = [gen(nsubbits, p = p) for i in xrange(npiece)]
850 Q = prod(q.p for q in qq)
851
852 ## Come up with bounds on the cofactor. If we're to have N = 2 Q R + 1,
853 ## and 2^{B-1} <= N < 2^B, then we must have 2^{B-2}/Q <= R < 2^{B-1}/Q.
854 Rbase = (C.MP(0).setbit(nbits - 2) + Q - 1)//Q
855 Rwd = C.MP(0).setbit(nbits - 2)//Q
856
857 ## Probe the available space of cofactors. If the space is kind of
858 ## narrow, then we want to give up quickly if we're not finding anything
859 ## suitable.
860 step = 0
861 while step < Rwd:
862 step += 1
863
864 ## Pick a random cofactor and examine the number we ended up with.
865 ## Make sure it really does have the length we expect.
866 R = C.rand.range(Rwd) + Rbase
867 n = 2*Q*R + 1
868 assert n.nbits == nbits
869
870 ## As a complication, if NPIECE is 1, it's just about possible that Q^2
871 ## <= n, in which case this isn't going to work.
872 if Q*Q < n: continue
873
874 ## If n has small factors, then pick another cofactor.
875 if C.PrimeFilter.smallfactor(n) == C.PGEN_FAIL: continue
876
877 ## Work through the small primes to find a suitable generator. The
878 ## value 2 is almost always acceptable, so don't try too hard here.
879 for a in I.islice(SIEVE.smallprimes(), 16):
880
881 ## First, try the Fermat test. If that fails, then n is definitely
882 ## composite.
883 if pow(a, n - 1, n) != 1: p.p('.'); break
884 p.p('*')
885
886 ## Work through the subgroup orders, checking that suitable powers of
887 ## a generate the necessary subgroups.
888 for q in qq:
889 if n.gcd(pow(a, (n - 1)/q.p, n) - 1) != 1:
890 p.p('@'); ok = False; break
891 else:
892 ok = True
893
894 ## we're all good.
895 if ok: p.pop(); return PockPrime(n, a, qq, label = label)
896
897 def gen(nbits, label = None, p = ProgressReporter()):
898 """
899 Generate a prime number with NBITS bits.
900
901 Give it the LABEL, and report progress to P.
902 """
903 if SIEVE.limit >> (nbits + 1)/2: g = gen_small
904 else: g = gen_pock
905 return g(nbits, label = label, p = p)
906
907 def gen_limlee(nbits, nsubbits,
908 label = None, qlfmt = None, p = ProgressReporter()):
909 """
910 Generate a Lim--Lee prime with NBITS bits.
911
912 Let p be the prime. Then we'll have p = 2 q_0 q_1 ... q_k, with all q_i at
913 least NSUBBITS bits long, and all but q_k exactly that long.
914
915 The prime will be given the LABEL; progress is reported to P. The factors
916 q_i will be labelled by filling in the `printf'-style format string QLFMT
917 with the argument i.
918 """
919
920 ## Figure out how many factors (p - 1)/2 will have.
921 npiece = nbits//nsubbits
922 if npiece < 2: raise ExpectedError('too few pieces')
923
924 ## Decide how big to make the pool of factors.
925 poolsz = max(3*npiece + 5, 25) # Heuristic from GnuPG
926
927 ## Prepare for the main loop.
928 disp = nstep = 0
929 qbig = None
930 p.push()
931
932 ## Try to make a prime.
933 while True:
934 p.p('!')
935
936 ## Construct a pool of NSUBBITS-size primes. There's a problem with very
937 ## small sizes: we might not be able to build a pool of distinct primes.
938 pool = []; qmap = {}
939 for i in xrange(poolsz):
940 for j in xrange(64):
941 q = gen(nsubbits, p = p)
942 if q.p not in qmap: break
943 else:
944 raise ExpectedError('insufficient diversity')
945 qmap[q.p] = q
946 pool.append(q)
947
948 ## Work through combinations of factors from the pool.
949 for qq in combinations(npiece - 1, pool):
950
951 ## Construct the product of the selected factors.
952 qsmall = prod(q.p for q in qq)
953
954 ## Maybe we'll need to replace the large factor. Try not to do this
955 ## too often. DISP measures the large factor's performance at
956 ## producing candidates with the right length. If it looks bad then
957 ## we'll have to replace it.
958 if 3*disp*disp > nstep*nstep:
959 qbig = None
960 if disp < 0: p.p('<')
961 else: p.p('>')
962
963 ## If we don't have a large factor, then make one.
964 if qbig is None:
965 qbig = gen(nbits - qsmall.nbits, p = p)
966 disp = 0; nstep = 0
967
968 ## We have a candidate. Calculate it and make sure it has the right
969 ## length.
970 n = 2*qsmall*qbig.p + 1
971 nstep += 1
972 if n.nbits < nbits: disp -= 1
973 elif n.nbits > nbits: disp += 1
974 elif C.PrimeFilter.smallfactor(n) == C.PGEN_FAIL: pass
975 else:
976
977 ## The candidate has passed the small-primes test. Now check it
978 ## against Pocklington.
979 for a in I.islice(SIEVE.smallprimes(), 16):
980
981 ## Fermat test.
982 if pow(a, n - 1, n) != 1: p.p('.'); break
983 p.p('*')
984
985 ## Find a generator of a sufficiently large subgroup.
986 if n.gcd(pow(a, (n - 1)/qbig.p, n) - 1) != 1: p.p('@'); continue
987 ok = True
988 for q in qq:
989 if n.gcd(pow(a, (n - 1)/q.p, n) - 1) != 1:
990 p.p('@'); ok = False; break
991
992 ## We're done.
993 if ok:
994
995 ## Label the factors.
996 qq.append(qbig)
997 if qlfmt:
998 for i, q in enumerate(qq): q.label(qlfmt % i)
999
1000 ## Return the number we found.
1001 p.pop(); return PockPrime(n, a, qq, label = label)
1002
1003 ###--------------------------------------------------------------------------
1004 ### Main program.
1005
1006 def __main__():
1007 global VERBOSITY
1008
1009 ## Prepare an option parser.
1010 op = OP.OptionParser(
1011 usage = '''\
1012 pock [-qv] [-s SIEVEBITS] CMD ARGS...
1013 gen NBITS
1014 ll NBITS NSUBBITS
1015 check [FILE]''',
1016 description = 'Generate or verify certified prime numbers.')
1017 op.add_option('-v', '--verbose', dest = 'verbosity',
1018 action = 'count', default = 1,
1019 help = 'print mysterious runes while looking for prime numbers')
1020 op.add_option('-q', '--quiet', dest = 'quietude',
1021 action = 'count', default = 0,
1022 help = 'be quiet while looking for prime numbers')
1023 op.add_option('-s', '--sievebits', dest = 'sievebits',
1024 type = 'int', default = 32,
1025 help = 'size (in bits) of largest small prime')
1026 opts, argv = op.parse_args()
1027 VERBOSITY = opts.verbosity - opts.quietude
1028 p = ProgressReporter()
1029 a = ArgFetcher(argv, op.error)
1030
1031 ## Process arguments and do what the user asked.
1032 w = a.arg()
1033
1034 if w == 'gen':
1035 ## Generate a prime with no special structure.
1036 initsieve(opts.sievebits)
1037 nbits = a.int(min = 4)
1038 pp = PrimeProof()
1039 p = gen(nbits, 'p', p = p)
1040 p.register(pp)
1041 pp.write(stdout)
1042
1043 elif w == 'll':
1044 ## Generate a Lim--Lee prime.
1045 initsieve(opts.sievebits)
1046 nbits = a.int(min = 4)
1047 nsubbits = a.int(min = 4, max = nbits)
1048 pp = PrimeProof()
1049 p = gen_limlee(nbits, nsubbits, 'p', 'q_%d', p = p)
1050 p.register(pp)
1051 pp.write(stdout)
1052
1053 elif w == 'check':
1054 ## Check an existing certificate.
1055 fn = a.arg(default = '-', must = False)
1056 if fn == '-': f = stdin
1057 else: f = open(fn, 'r')
1058 pp = PrimeProof()
1059 p = pp.read(f)
1060
1061 else:
1062 raise ExpectedError("unknown command `%s'" % w)
1063
1064 if __name__ == '__main__':
1065 prog = OS.path.basename(argv[0])
1066 try: __main__()
1067 except ExpectedError: exit('%s: %s' % (prog, _excval().message))
1068 except IOError: exit('%s: %s' % (prog, _excval()))
1069
1070 ###----- That's all, folks --------------------------------------------------