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