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