xref: /llvm-project/polly/lib/External/isl/imath/examples/randprime.c (revision 658eb9e14264d48888ade0e3daf0b648f76c3f0e)
1*658eb9e1SMichael Kruse /*
2*658eb9e1SMichael Kruse   Name:     randprime.c
3*658eb9e1SMichael Kruse   Purpose:  Generate a probable prime at random.
4*658eb9e1SMichael Kruse   Author:   M. J. Fromberger
5*658eb9e1SMichael Kruse 
6*658eb9e1SMichael Kruse   Usage:  randprime [-s] <bits> [<outfile>]
7*658eb9e1SMichael Kruse 
8*658eb9e1SMichael Kruse   Generate a randomly-chosen probable prime having <bits> significant bits, and
9*658eb9e1SMichael Kruse   write it to the specified output file or to the standard output.  If the "-s"
10*658eb9e1SMichael Kruse   option is given, a prime p is chosen such that (p - 1) / 2 is also prime.
11*658eb9e1SMichael Kruse 
12*658eb9e1SMichael Kruse   A prime is obtained by reading random bits from /dev/random, setting the
13*658eb9e1SMichael Kruse   low-order bit, and testing for primality.  If the first candidate is not
14*658eb9e1SMichael Kruse   prime, successive odd candidates are tried until a probable prime is found.
15*658eb9e1SMichael Kruse 
16*658eb9e1SMichael Kruse   Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved.
17*658eb9e1SMichael Kruse 
18*658eb9e1SMichael Kruse   Permission is hereby granted, free of charge, to any person obtaining a copy
19*658eb9e1SMichael Kruse   of this software and associated documentation files (the "Software"), to deal
20*658eb9e1SMichael Kruse   in the Software without restriction, including without limitation the rights
21*658eb9e1SMichael Kruse   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22*658eb9e1SMichael Kruse   copies of the Software, and to permit persons to whom the Software is
23*658eb9e1SMichael Kruse   furnished to do so, subject to the following conditions:
24*658eb9e1SMichael Kruse 
25*658eb9e1SMichael Kruse   The above copyright notice and this permission notice shall be included in
26*658eb9e1SMichael Kruse   all copies or substantial portions of the Software.
27*658eb9e1SMichael Kruse 
28*658eb9e1SMichael Kruse   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29*658eb9e1SMichael Kruse   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30*658eb9e1SMichael Kruse   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
31*658eb9e1SMichael Kruse   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32*658eb9e1SMichael Kruse   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33*658eb9e1SMichael Kruse   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34*658eb9e1SMichael Kruse   SOFTWARE.
35*658eb9e1SMichael Kruse  */
36*658eb9e1SMichael Kruse 
37*658eb9e1SMichael Kruse #include <errno.h>
38*658eb9e1SMichael Kruse #include <limits.h>
39*658eb9e1SMichael Kruse #include <stdio.h>
40*658eb9e1SMichael Kruse #include <stdlib.h>
41*658eb9e1SMichael Kruse #include <string.h>
42*658eb9e1SMichael Kruse 
43*658eb9e1SMichael Kruse #include <getopt.h>
44*658eb9e1SMichael Kruse #include <unistd.h>
45*658eb9e1SMichael Kruse 
46*658eb9e1SMichael Kruse #include "imath.h"
47*658eb9e1SMichael Kruse #include "iprime.h"
48*658eb9e1SMichael Kruse 
49*658eb9e1SMichael Kruse /* Load the specified buffer with random bytes */
50*658eb9e1SMichael Kruse int randomize(unsigned char *buf, size_t len);
51*658eb9e1SMichael Kruse 
52*658eb9e1SMichael Kruse /* Overwrite the specified value with n_bits random bits */
53*658eb9e1SMichael Kruse mp_result mp_int_randomize(mp_int a, mp_size n_bits);
54*658eb9e1SMichael Kruse 
55*658eb9e1SMichael Kruse /* Find a prime starting from the given odd seed */
56*658eb9e1SMichael Kruse mp_result find_prime(mp_int seed, FILE *fb);
57*658eb9e1SMichael Kruse mp_result find_strong_prime(mp_int seed, FILE *fb);
58*658eb9e1SMichael Kruse 
59*658eb9e1SMichael Kruse typedef mp_result (*find_f)(mp_int, FILE *);
60*658eb9e1SMichael Kruse 
main(int argc,char * argv[])61*658eb9e1SMichael Kruse int main(int argc, char *argv[]) {
62*658eb9e1SMichael Kruse   int opt, modbits;
63*658eb9e1SMichael Kruse   FILE *ofp = stdout;
64*658eb9e1SMichael Kruse   mp_result res;
65*658eb9e1SMichael Kruse   find_f find_func = find_prime;
66*658eb9e1SMichael Kruse   char tag = 'p';
67*658eb9e1SMichael Kruse   mpz_t value;
68*658eb9e1SMichael Kruse 
69*658eb9e1SMichael Kruse   /* Process command-line arguments */
70*658eb9e1SMichael Kruse   while ((opt = getopt(argc, argv, "s")) != EOF) {
71*658eb9e1SMichael Kruse     switch (opt) {
72*658eb9e1SMichael Kruse       case 's':
73*658eb9e1SMichael Kruse         find_func = find_strong_prime;
74*658eb9e1SMichael Kruse         tag = 'P';
75*658eb9e1SMichael Kruse         break;
76*658eb9e1SMichael Kruse       default:
77*658eb9e1SMichael Kruse         fprintf(stderr, "Usage: randprime [-s] <bits> [<outfile>]\n");
78*658eb9e1SMichael Kruse         return 1;
79*658eb9e1SMichael Kruse     }
80*658eb9e1SMichael Kruse   }
81*658eb9e1SMichael Kruse 
82*658eb9e1SMichael Kruse   if (optind >= argc) {
83*658eb9e1SMichael Kruse     fprintf(stderr,
84*658eb9e1SMichael Kruse             "Error:  You must specify the number of significant bits.\n");
85*658eb9e1SMichael Kruse     fprintf(stderr, "Usage: randprime [-s] <bits> [<outfile>]\n");
86*658eb9e1SMichael Kruse     return 1;
87*658eb9e1SMichael Kruse   }
88*658eb9e1SMichael Kruse   modbits = (int)strtol(argv[optind++], NULL, 0);
89*658eb9e1SMichael Kruse   if (modbits < CHAR_BIT) {
90*658eb9e1SMichael Kruse     fprintf(stderr, "Error:  Invalid value for number of significant bits.\n");
91*658eb9e1SMichael Kruse     return 1;
92*658eb9e1SMichael Kruse   }
93*658eb9e1SMichael Kruse   if (modbits % 2 == 1) ++modbits;
94*658eb9e1SMichael Kruse 
95*658eb9e1SMichael Kruse   /* Check if output file is specified */
96*658eb9e1SMichael Kruse   if (optind < argc) {
97*658eb9e1SMichael Kruse     if ((ofp = fopen(argv[optind], "wt")) == NULL) {
98*658eb9e1SMichael Kruse       fprintf(stderr,
99*658eb9e1SMichael Kruse               "Error:  Unable to open output file for writing.\n"
100*658eb9e1SMichael Kruse               " - Filename: %s\n"
101*658eb9e1SMichael Kruse               " - Error:    %s\n",
102*658eb9e1SMichael Kruse               argv[optind], strerror(errno));
103*658eb9e1SMichael Kruse       return 1;
104*658eb9e1SMichael Kruse     }
105*658eb9e1SMichael Kruse   }
106*658eb9e1SMichael Kruse 
107*658eb9e1SMichael Kruse   mp_int_init(&value);
108*658eb9e1SMichael Kruse   if ((res = mp_int_randomize(&value, modbits - 1)) != MP_OK) {
109*658eb9e1SMichael Kruse     fprintf(stderr,
110*658eb9e1SMichael Kruse             "Error:  Unable to generate random start value.\n"
111*658eb9e1SMichael Kruse             " - %s (%d)\n",
112*658eb9e1SMichael Kruse             mp_error_string(res), res);
113*658eb9e1SMichael Kruse     goto EXIT;
114*658eb9e1SMichael Kruse   }
115*658eb9e1SMichael Kruse   fprintf(stderr, "%c: ", tag);
116*658eb9e1SMichael Kruse   find_func(&value, stderr);
117*658eb9e1SMichael Kruse   fputc('\n', stderr);
118*658eb9e1SMichael Kruse 
119*658eb9e1SMichael Kruse   /* Write the completed value to the specified output file */
120*658eb9e1SMichael Kruse   {
121*658eb9e1SMichael Kruse     int len;
122*658eb9e1SMichael Kruse     char *obuf;
123*658eb9e1SMichael Kruse 
124*658eb9e1SMichael Kruse     len = mp_int_string_len(&value, 10);
125*658eb9e1SMichael Kruse     obuf = malloc(len);
126*658eb9e1SMichael Kruse     mp_int_to_string(&value, 10, obuf, len);
127*658eb9e1SMichael Kruse     fputs(obuf, ofp);
128*658eb9e1SMichael Kruse     fputc('\n', ofp);
129*658eb9e1SMichael Kruse 
130*658eb9e1SMichael Kruse     free(obuf);
131*658eb9e1SMichael Kruse   }
132*658eb9e1SMichael Kruse 
133*658eb9e1SMichael Kruse EXIT:
134*658eb9e1SMichael Kruse   fclose(ofp);
135*658eb9e1SMichael Kruse   mp_int_clear(&value);
136*658eb9e1SMichael Kruse   return 0;
137*658eb9e1SMichael Kruse }
138*658eb9e1SMichael Kruse 
randomize(unsigned char * buf,size_t len)139*658eb9e1SMichael Kruse int randomize(unsigned char *buf, size_t len) {
140*658eb9e1SMichael Kruse   FILE *rnd = fopen("/dev/random", "rb");
141*658eb9e1SMichael Kruse   size_t nr;
142*658eb9e1SMichael Kruse 
143*658eb9e1SMichael Kruse   if (rnd == NULL) return -1;
144*658eb9e1SMichael Kruse 
145*658eb9e1SMichael Kruse   nr = fread(buf, sizeof(*buf), len, rnd);
146*658eb9e1SMichael Kruse   fclose(rnd);
147*658eb9e1SMichael Kruse 
148*658eb9e1SMichael Kruse   return (int)nr;
149*658eb9e1SMichael Kruse }
150*658eb9e1SMichael Kruse 
mp_int_randomize(mp_int a,mp_size n_bits)151*658eb9e1SMichael Kruse mp_result mp_int_randomize(mp_int a, mp_size n_bits) {
152*658eb9e1SMichael Kruse   mp_size n_bytes = (n_bits + CHAR_BIT - 1) / CHAR_BIT;
153*658eb9e1SMichael Kruse   unsigned char *buf;
154*658eb9e1SMichael Kruse   mp_result res = MP_OK;
155*658eb9e1SMichael Kruse 
156*658eb9e1SMichael Kruse   if ((buf = malloc(n_bytes)) == NULL) return MP_MEMORY;
157*658eb9e1SMichael Kruse 
158*658eb9e1SMichael Kruse   if ((mp_size)randomize(buf, n_bytes) != n_bytes) {
159*658eb9e1SMichael Kruse     res = MP_TRUNC;
160*658eb9e1SMichael Kruse     goto CLEANUP;
161*658eb9e1SMichael Kruse   }
162*658eb9e1SMichael Kruse 
163*658eb9e1SMichael Kruse   /* Clear bits beyond the number requested */
164*658eb9e1SMichael Kruse   if (n_bits % CHAR_BIT != 0) {
165*658eb9e1SMichael Kruse     unsigned char b_mask = (1 << (n_bits % CHAR_BIT)) - 1;
166*658eb9e1SMichael Kruse     unsigned char t_mask = (1 << (n_bits % CHAR_BIT)) >> 1;
167*658eb9e1SMichael Kruse 
168*658eb9e1SMichael Kruse     buf[0] &= b_mask;
169*658eb9e1SMichael Kruse     buf[0] |= t_mask;
170*658eb9e1SMichael Kruse   }
171*658eb9e1SMichael Kruse 
172*658eb9e1SMichael Kruse   /* Set low-order bit to insure value is odd */
173*658eb9e1SMichael Kruse   buf[n_bytes - 1] |= 1;
174*658eb9e1SMichael Kruse 
175*658eb9e1SMichael Kruse   res = mp_int_read_unsigned(a, buf, n_bytes);
176*658eb9e1SMichael Kruse 
177*658eb9e1SMichael Kruse CLEANUP:
178*658eb9e1SMichael Kruse   memset(buf, 0, n_bytes);
179*658eb9e1SMichael Kruse   free(buf);
180*658eb9e1SMichael Kruse 
181*658eb9e1SMichael Kruse   return res;
182*658eb9e1SMichael Kruse }
183*658eb9e1SMichael Kruse 
find_prime(mp_int seed,FILE * fb)184*658eb9e1SMichael Kruse mp_result find_prime(mp_int seed, FILE *fb) {
185*658eb9e1SMichael Kruse   mp_result res;
186*658eb9e1SMichael Kruse   int count = 0;
187*658eb9e1SMichael Kruse 
188*658eb9e1SMichael Kruse   if (mp_int_is_even(seed)) {
189*658eb9e1SMichael Kruse     if ((res = mp_int_add_value(seed, 1, seed)) != MP_OK) {
190*658eb9e1SMichael Kruse       return res;
191*658eb9e1SMichael Kruse     }
192*658eb9e1SMichael Kruse   }
193*658eb9e1SMichael Kruse 
194*658eb9e1SMichael Kruse   while ((res = mp_int_is_prime(seed)) == MP_FALSE) {
195*658eb9e1SMichael Kruse     ++count;
196*658eb9e1SMichael Kruse 
197*658eb9e1SMichael Kruse     if (fb != NULL && (count % 50) == 0) {
198*658eb9e1SMichael Kruse       fputc('.', fb);
199*658eb9e1SMichael Kruse     }
200*658eb9e1SMichael Kruse     if ((res = mp_int_add_value(seed, 2, seed)) != MP_OK) {
201*658eb9e1SMichael Kruse       return res;
202*658eb9e1SMichael Kruse     }
203*658eb9e1SMichael Kruse   }
204*658eb9e1SMichael Kruse 
205*658eb9e1SMichael Kruse   if (res == MP_TRUE && fb != NULL) fputc('+', fb);
206*658eb9e1SMichael Kruse 
207*658eb9e1SMichael Kruse   return res;
208*658eb9e1SMichael Kruse }
209*658eb9e1SMichael Kruse 
find_strong_prime(mp_int seed,FILE * fb)210*658eb9e1SMichael Kruse mp_result find_strong_prime(mp_int seed, FILE *fb) {
211*658eb9e1SMichael Kruse   mp_result res = MP_OK;
212*658eb9e1SMichael Kruse   mpz_t t;
213*658eb9e1SMichael Kruse 
214*658eb9e1SMichael Kruse   mp_int_init(&t);
215*658eb9e1SMichael Kruse   for (;;) {
216*658eb9e1SMichael Kruse     if (find_prime(seed, fb) != MP_TRUE) break;
217*658eb9e1SMichael Kruse     if (mp_int_copy(seed, &t) != MP_OK) break;
218*658eb9e1SMichael Kruse 
219*658eb9e1SMichael Kruse     if (mp_int_mul_pow2(&t, 1, &t) != MP_OK ||
220*658eb9e1SMichael Kruse         mp_int_add_value(&t, 1, &t) != MP_OK) {
221*658eb9e1SMichael Kruse       break;
222*658eb9e1SMichael Kruse     }
223*658eb9e1SMichael Kruse 
224*658eb9e1SMichael Kruse     if ((res = mp_int_is_prime(&t)) == MP_TRUE) {
225*658eb9e1SMichael Kruse       if (fb != NULL) fputc('!', fb);
226*658eb9e1SMichael Kruse 
227*658eb9e1SMichael Kruse       res = mp_int_copy(&t, seed);
228*658eb9e1SMichael Kruse       break;
229*658eb9e1SMichael Kruse     } else if (res != MP_FALSE)
230*658eb9e1SMichael Kruse       break;
231*658eb9e1SMichael Kruse 
232*658eb9e1SMichael Kruse     if (fb != NULL) fputc('x', fb);
233*658eb9e1SMichael Kruse     if (mp_int_add_value(seed, 2, seed) != MP_OK) break;
234*658eb9e1SMichael Kruse   }
235*658eb9e1SMichael Kruse 
236*658eb9e1SMichael Kruse   mp_int_clear(&t);
237*658eb9e1SMichael Kruse   return res;
238*658eb9e1SMichael Kruse }
239*658eb9e1SMichael Kruse 
240*658eb9e1SMichael Kruse /* Here there be dragons */
241