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