File: make-primes.c

package info (click to toggle)
nessus-libraries 1.0.10-2
  • links: PTS
  • area: main
  • in suites: woody
  • size: 9,536 kB
  • ctags: 12,585
  • sloc: ansic: 72,626; asm: 25,921; sh: 19,570; makefile: 1,974; cpp: 560; pascal: 536; yacc: 234; lex: 203; lisp: 186; perl: 76; fortran: 24
file content (645 lines) | stat: -rw-r--r-- 17,147 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
/*
 *          Copyright (c) mjh-EDV Beratung, 1996-1999
 *     mjh-EDV Beratung - 63263 Neu-Isenburg - Rosenstrasse 12
 *          Tel +49 6102 328279 - Fax +49 6102 328278
 *                Email info@mjh.teddy-net.com
 *
 *   Author: Jordan Hrycaj <jordan@mjh.teddy-net.com>
 *
 *   $Id: make-primes.c,v 1.1 2000/08/14 20:51:36 jordan Exp $
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Library General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this library; if not, write to the Free
 *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "common-stuff.h"

#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
#  include <sys/time.h>
# else
#  include <time.h>
# endif
#endif

#ifdef USE_PTHREADS
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
#endif

#ifdef HAVE_ASSERT_H
#include <assert.h>
#else
#define assert(x)
#endif

#ifndef HAVE_RAND
#define rand() random ()
#endif

#include "baseXX.h"
#include "peks-baseXX.h"
#include "rand/crandom.h"
#include "cipher/cipher.h"
#include "rand/rnd-pool.h"

#define __MAKE_PRIME_INTERNAL__
#include "make-primes.h"

/* ------------------------------------------------------------------------ *
 *                private variables                                         *
 * ------------------------------------------------------------------------ */

static int spDIM = 0 ;

/* ------------------------------------------------------------------------ *
 *                private functions                                         *
 * ------------------------------------------------------------------------ */

static void 
xprint 
  (FILE     *stream, 
   const char *text)
{
  fputs (text, stream);
  fflush (stream) ;
}

static unsigned short
get_a_random_smallprime_or_1 
  (void)
{
  extern unsigned short small_prime_numbers [] ;
  short int inx ;

  if (spDIM == 0)
    while (small_prime_numbers [++ spDIM])
      ;

  fast_random_bytes ((char *)&inx, sizeof (inx)) ;

  /* I need the number 1 or a prime from list of small primes 
     starting at 3. */
  inx %= (spDIM + 2) ;

  /* 1 and 2 are not in small_prime_numbers [] */
  inx -= 2 ;

  return inx < 0 ? -inx : small_prime_numbers [inx] ;
}

/* ------------------------------------------------------------------------ *
 *              global functions: i/o call back                             *
 * ------------------------------------------------------------------------ */

void xprint2 (const char *text) {xprint (stderr, text);}
void xprint1 (const char *text) {xprint (stdout, text);}

/* ------------------------------------------------------------------------ *
 *                private functions: pthreads support                       *
 * ------------------------------------------------------------------------ */

#undef  SYSNAME /* solaris wants it */
#define SYSNAME "make-primes"
#include "peks-sema.h"

/* ------------------------------------------------------------------------ *
 *               private functions: random number generator                 *
 * ------------------------------------------------------------------------ */

/* Some algorithm below tests a list of random numbers for some properties.
   Assuming, that the random generator has enough entropy, we do not destill
   a new random number, all the time. We just fiddle around with the given
   random bits, instead. */

typedef struct _hashy { 
  unsigned  length;	/* bytes represented by the rnd string */
  char  buffer [1];	/* random bits */
  /*VARIABLE SIZE*/
} hashy ;


static void
hashy_random_num
  (hashy   **RND,
   mpz_t    *ROP,
   unsigned bits)
{
  static frame_desc *md ;
  hashy *rnd = *RND ;
  unsigned len;
  char *p ;

  __enter_lock_semaphore ();

  if (md == 0) {
    md = create_frame (find_frame_class (MAKE_PRIME_HASH_TYPE), 0);
    assert (md != 0);
  }
  
  if (rnd == 0) {			/* create descriptor */
    len         = (bits + 7) / 8 ;
    rnd         = vmalloc (sizeof (hashy) + len - 1) ;
    rnd->length = len ;
    *RND = rnd ;

    /* get a mouth full of random bits */
    fast_random_bytes (rnd->buffer, rnd->length);
  }
  
  if (ROP == 0) {			/* ROP == 0: clean up */
    memset (rnd, 0, sizeof (hashy)+rnd->length-1) ;
    xfree  (rnd) ;
    __release_lock_semaphore ();
    return ;
  }

  len = rnd->length ;
  p   = rnd->buffer ;

  /* rehash the whole buffer while adding some easy randomness */
  while (len --) {
    int chunk = (md->mdlen < len) ? md->mdlen : len ;
    
    /* hash output from the random generator */
    { int r = rand () ; XCRCFIRST (md, (char*)&r, sizeof (r)); }
    
#ifdef HAVE_GETTIMEOFDAY2
    /* hash current time in millisecs, seconds etc. */
    { struct timeval tv ; gettimeofday2 (&tv, 0);
    XCRCNEXT (md, (char*)&tv, sizeof (tv)); }
#else
    { time_t ti = time (0);
    XCRCNEXT (md, (char*)&ti, sizeof (ti)); }
#endif

    /* re-hash the old contents */
    XCRCNEXT (md, p, chunk) ;

#if 1
    /* quickly add some more bits */
    make_random_bytes (p, chunk);
    XCRCNEXT (md, p, chunk) ;
#endif

    /* copy one chunk of data, set new internal state */
    memcpy (p, XCRCRESULT0 (md), chunk) ;

    /* let a quarter of the fragments overlap */
    len -= (chunk >> 2) * 3 ;
    p   += (chunk >> 2) * 3 ;
  }

  __release_lock_semaphore ();

  if ((len = (bits + 7) / 8) > rnd->length)
    len = rnd->length ;

  /* convert buffer to base 32 */
  bin2mpz (ROP, rnd->buffer, len);

  /* don't let the random number become too small */
  if (mpz_sizeinbase (*ROP, 2) < bits)
    mpz_setbit (*ROP, bits-1) ;
}

/* ------------------------------------------------------------------------ *
 *               private function: prime test                               *
 * ------------------------------------------------------------------------ */

static unsigned
is_not_miller_rabin_prime
  (hashy     **c,
   mpz_t      *p,
   int num_tests)
{
  /* References: 
   *
   *  - Bruce Schneier; Applied Cryprography; NY, Wiley & Sons, 2nd ed 1996, 
   *    chapter 11.5, pg 260 ff.
   *  - D.R. Stinson; Cryptography; Boca Raton, CRC Press 1995, chapter 4,
   *    Fig 4.8 pg 137 ff. 
   */
  
  mpz_t p_min_1, m, a, z;
  unsigned b, is_definitely_composite;

  unsigned rlen = 32 ;			/* max size of a random number */
  mpz_init (a);				/* will a (small) random a < p */

  if ((b = mpz_sizeinbase (*p, 2) - 1) < rlen)
    rlen = b ;				/* length for a randum mumber */

  mpz_init (p_min_1) ;
  mpz_sub_ui (p_min_1, *p, 1) ;
  b = mpz_scan1 (p_min_1, 0) ;		/* max b with 2^b | p-1 */
  
  mpz_init (m);
  mpz_tdiv_q_2exp (m, p_min_1, b);	/* so p-1 = m * 2^b */

  mpz_init (z);
  do {					/* do this test at least once */
    unsigned j ;
      
    is_definitely_composite = 1;	/* default assumption: no prime */
    hashy_random_num (c, &a, rlen);	/* get new random number */

    mpz_powm (z, a, m, *p) ;		/* z := a^m mod p */
    if (mpz_cmp_ui (z, 1) == 0)	/* z == 1 mod p */
      goto p_may_be_prime ;
      
    for (j = 0; j < b; j ++) {		/* see p-1 == m * 2^b */
      if (mpz_cmp (z, p_min_1) ==0)	/* z == -1 mod p */
	goto p_may_be_prime ;
	  
      mpz_powm_ui (z, z, 2, *p) ;	/* z := z^2 mod p */

      POINT_OF_RANDOM_VAR_COND (j % 11 == 0, z);  

      if (mpz_cmp_ui (z, 1) == 0)	/* if z == 1 here, then for rest */
	break ;				/* definitely not prime */
    }
    goto clean_up_and_return ;		/* not a prime when this is done */
    /*@NOTREACHED@*/
    
  p_may_be_prime:
    is_definitely_composite = 0;	/* maybe a prime, next test or done */
  } while ( -- num_tests > 0) ;		/* repeat that test */
  
 clean_up_and_return:

  mpz_clear         (p_min_1);
  mpz_clear               (m);
  mpz_clear               (a);
  mpz_clear               (z);

  return is_definitely_composite ;
}


static unsigned
this_number_is_a_prime
  (hashy            **c,
   mpz_t           *num,
   unsigned prob_weight)
   
{
  extern unsigned short small_prime_numbers [] ;
  unsigned p, r = 0, n = 0 ;

  mpz_t OP;
  mpz_init (OP);

  /* check for divisibility by some small primes, first */
  while ((p = small_prime_numbers [n ++]) != 0) {
    /* does p | num <=> num == 0(mod p) ? */
    r = mpz_mod_ui (OP, *num, (unsigned long)p) ;
    if (r == 0) 
      break ;
  }

  if (r) /* Rabin-Miller test */
    r = (is_not_miller_rabin_prime (c, num, prob_weight) == 0) ;
  
#ifdef _seems_not_to_be_better_than_the_miller_rabin_test_
  if (r) /* some probabilistic test due to Knuth */
    r = mpz_probab_prime_p (*num, prob_weight) ;
#endif

  mpz_clear (OP);
  return r;
}


/* ------------------------------------------------------------------------ *
 *           private function: make module and generator                    *
 * ------------------------------------------------------------------------ */

static unsigned
get_gen_prime_module_for_given_prime
  (hashy          **c,
   mpz_t           *P,			/* prime module to be found */
   unsigned       *gp,			/* generator (mod p) to be found */
   mpz_t           *Q,			/* input: a large prime */
   unsigned     pprob,			/* prime test prob weight */
   unsigned max_tries,
   void (*prt)(const char*))
{
  int run = 0;				/* indices in small_prime_numbers [] */

  unsigned p_is_1_mod_4 ;		/* set, if p == 1 (mod 4) */
  unsigned g ;
  mpz_t G, OP;				/* G := (mpz_t) g */

  mpz_init (G) ;
  mpz_init (OP) ;

  do {
    unsigned r = get_a_random_smallprime_or_1 () ;
    unsigned s = get_a_random_smallprime_or_1 () ;

    unsigned t = r * s ;	/* t = rs, for small primes r, s */

    if (t == 1)
      continue ;

    /* print keep alive message */
    if (prt != 0 && (run) % 44 == 0) (*prt) (".") ;

    /* What we got here, are a product t of small small primes, and a large 
       prime Q.  We check, whether P := (Q * t + 1) is prime.  If so, the
       Euler function 
       
           phi (P) = p - 1 = Q * t 
       
       is the the product of one large, and at most two small primes.  In
       order to show that a given value G, say is a generator of the module
       generated by Q, it suffices to show, that G^Q*r != 1 (mod P), 
       G^Q*s != 1 (mod P), and G^t != 1 (mod P). */
	 
    mpz_mul_ui (OP, *Q, t);			/* OP := q * t */
    mpz_add_ui (*P, OP, 1);			/* p := q * t + 1 */

    /* retry if this number is not prime */
    if (!this_number_is_a_prime (c, P, pprob))
      continue ;

    /* print found message */
    if (prt != 0) (*prt) ("p") ;
    
    /* Check, whether p is 1 (mod 4). There reason for that is an attack on
       the El Gamal signature scheme possible if:
       
           p == 1 (mod 4) and g | (p-1)  ... (more restrictions)

       For details, see Note 11.67 in: A. Menezes, P.van Oorschot,
       S. Vanstone (Eds.), "Handbook of Applied Cryptography", CRC 
       Press 1997, ISBN 0-8493-8523-7, pg 458 ff. */

    p_is_1_mod_4 = (mpz_mod_ui (OP, OP, 4) == 0) ;	/* OP was (p - 1) */

    /* find generator g (mod p) */
    for (g = 2; g < UINT_MAX; g ++) {

      mpz_set_ui (G, g);

      /* check whether g | p-1 (see the comment, above) */
      if (p_is_1_mod_4 && mpz_mod_ui (OP, *P, g) == 1) 
	continue ;

      /* print keep alive message */
      if (prt != 0 && g % 11 == 0) (*prt) (".") ;

      POINT_OF_RANDOM_VAR_COND (g % 13 == 0, OP);

      mpz_powm_ui (OP, G, t, *P) ;		/* OP := g^t (mod p) */
      if (mpz_cmp_ui (OP, 1) == 0)		/* g^t == 1 (mod p) ? */
	continue ;

      /* for convenience we need: s != 1 */
      if (s == 1) { s = r ; r = 1 ; }

      if (r == 1) {
	/* this case saves one multiplication operation */
	mpz_powm (OP, G, *Q, *P) ;
      } else {				/* means r != 1 */
	mpz_mul_ui (OP, *Q, r) ;		/* OP := q * r */
	mpz_powm (OP, G, OP, *P) ;		/* OP := g^qr (mod p) */
      }
      if (mpz_cmp_ui (OP, 1) == 0)		/* g^qr == 1 (mod p) ? */
	continue ;
	
      /* note that s != 1 */
      mpz_mul_ui (OP, *Q, s) ;		/* OP := q * s */
      mpz_powm (OP, G, OP, *P) ;		/* OP := g^qs (mod p) */
      if (mpz_cmp_ui (OP, 1) == 0)		/* g^qr == 1 (mod p) ? */
	continue ;

      /* now, g^x != 1 (mod p) for all d | (p-1), so p is generator */
      if (prt != 0) (*prt) ("g") ;
      mpz_clear (G);
      mpz_clear (OP);
      return *gp = g ;
    }
  } while (++ run < (int)max_tries); 
  
  if (prt != 0) (*prt) (";\n") ;

  mpz_clear (G);
  mpz_clear (OP);

  /* not found: r-code 0 */
  return 0;
}


static unsigned
find_a_random_prime
  (hashy                 **c,
   mpz_t              *prime,
   unsigned             bits,
#if 0 /* experimental, e.g. check 3 (mod 4) */
   int (*cond)(mpz_t*,mpz_t*),
#endif
   unsigned       prob_weight,
   unsigned         max_tries,
   void   (*prt)(const char*))
{
  mpz_t OP ;

  /* random number must be 'bits' bits large */
  int run = max_tries;
  
  mpz_init  (OP);

  do						/* do at least once */
    {
      hashy_random_num (c, prime, bits);	/* get fresh randum number */
      mpz_setbit         (*prime, 0);		/* num |= 1 makes it odd */

      /* print keep alive message, sometimes */
      if (prt != 0 && (run % 20) == 0) (* prt) (".") ;
      
#if 0 /* experimental, e.g. check 3 (mod 4) */
      /* check, whether there is a particular condition */
      if (cond != 0 && (*cond) (prime, &OP) != 0)
	continue ;
#endif
      /* retry if this number is not prime */
      if (!this_number_is_a_prime (c, prime, prob_weight))
	continue ;

      /* print found message, return */
      if (prt != 0) (* prt) ("q") ;

      mpz_clear (OP);
      return 1 + max_tries - run ;
    }
  while (-- run > 0) ;

  if (prt != 0) (* prt) (";\n") ;

  mpz_clear (OP);
  return 0;
}

/* ------------------------------------------------------------------------ *
 *               global functions: make primes                              *
 * ------------------------------------------------------------------------ */

#ifdef USE_PTHREADS
void 
prime_maker_sema_create
  (void *attr)
{
  if (spDIM == 0)
    get_a_random_smallprime_or_1 () ;
  __sema_create (attr); 
}

void 
prime_maker_sema_destroy 
  (void)
{
  __sema_destroy (); 
}
#endif
 
unsigned
number_is_a_prime
  (mpz_t           *num,
   unsigned prob_weight)
{
  hashy *c = 0;
  int n = this_number_is_a_prime (&c, num, prob_weight) ;
  hashy_random_num (&c, 0, 0);
  return n;
}
  
unsigned
get_random_prime
  (mpz_t             *P,
   unsigned        bits,
   unsigned prob_weight,
   unsigned   max_tries,
   void (*prt)(const char*))
{
  hashy *c = 0;
  int n = find_a_random_prime (&c, P, bits, prob_weight, max_tries, prt);
  hashy_random_num (&c, 0, 0);
  return n;
}

void
get_random_num
  (mpz_t    *ROP,
   unsigned bits,
   mpz_t    *MOD)
{
  mpz_t gcd;
  unsigned k;
  hashy *c;
  char *s;

  if (bits == 0)
    bits = 8 ;

  /* find any random number with at least "bits" bits */

  if (MOD == 0) {
    k = (bits + 7) / 8 ;
    s = ALLOCA (k) ;
    prime_random_bytes (s, k) ;
    bin2mpz (ROP, s, k) ;
    DEALLOCA (s) ;
    POINT_OF_RANDOM_VAR (s);
    /* don't let the random number become too small */
    if (mpz_sizeinbase (*ROP, 2) < bits)
      mpz_setbit (*ROP, bits-1) ;
    return ;
    /* @NOTREACHED@ */
  }

  mpz_init (gcd) ;
  do {
    k = 100 ;
    c =   0 ;
    do {
      /* find a random number *ROP relatively prime to *MOD */
      hashy_random_num (&c, ROP, bits);
      mpz_gcd (gcd, *ROP, *MOD) ;
    } while (mpz_cmp_ui (gcd, 1) != 0 && -- k) ;
    hashy_random_num (&c, 0, 0); /* reset */
  } while (k == 0) ;
  
  mpz_clear (gcd) ;  
  POINT_OF_RANDOM_VAR (gcd);
}

unsigned
get_generated_prime_module
  (mpz_t       *P,			/* prime module to be found */
   unsigned   *gp,			/* generator (mod p) to be found */
   mpz_t       *Q,			/* a large prime to be found */
   unsigned  bits,
   void (*prt)(const char*))
{
  int   run = TRY_GENERATE_PRIME_MODULE ;
  int try_p = TRY_RANDOM_IS_PRIME ;
  int try_g = TRY_PRIME_HAS_GENERATOR ;
  int pprob = PRIME_PROBABBILTY_WEIGHT;
  hashy  *c = 0;

  if (bits < 20)
    bits = 20 ;

  if (prt != 0) /* cosmetics */
    (*prt) (GENERATING_PRIMES_TXT) ;

  for (;;) {

    int ok = find_a_random_prime 
      (&c, Q, bits, pprob, try_p, prt) ;
    
    if (ok) 
      ok = get_gen_prime_module_for_given_prime 
	(&c, P, gp, Q, pprob, try_g, prt) ;

    if (ok) {
      /* reset random string recycler */
      hashy_random_num (&c, 0, 0);
      return *gp ;
    }

    if (run -- == 0) { /* loop control */
      hashy_random_num (&c, 0, 0);
      if (prt != 0) /* cosmetics */
	(*prt) (NOMORE_NEXT_TXT) ;
      return 0 ;
    }
    
    if (prt != 0) /* cosmetics */
      (*prt) (ADVANCING_NEXT_TXT) ;

    POINT_OF_RANDOM_VAR (Q);
  }
  /*@NOTREACHED@*/

  /* make stupid compilers happy */
  return 0; 
}