germtest.c
上传用户:zbbssh
上传日期:2007-01-08
资源大小:196k
文件大小:7k
源码类别:

CA认证

开发平台:

C/C++

  1. /*
  2.  * germtest.c - Random Sophie Germain prime generator.
  3.  *
  4.  * Copyright (c) 1995  Colin Plumb.  All rights reserved.
  5.  * For licensing and other legal details, see the file legal.c.
  6.  *
  7.  * This generates random Sophie Germain primes using the command
  8.  * line as a seed value.  It uses George Marsaglia's "mother of all
  9.  * random number generators" to pick the starting search value.
  10.  */
  11. #if HAVE_CONFIG_H
  12. #include "config.h"
  13. #endif
  14. #include <stdio.h>
  15. #if !NO_STRING_H
  16. #include <string.h>
  17. #elif HAVE_STRINGS_H
  18. #include <strings.h>
  19. #endif
  20. #if NEED_MEMORY_H
  21. #include <memory.h>
  22. #endif
  23. #include "bn.h"
  24. #include "germain.h"
  25. #include "sieve.h"
  26. #include "cputime.h"
  27. #define BNDEBUG 1
  28. #include "bnprint.h"
  29. #define bndPut(prompt, bn) bnPrint(stdout, prompt, bn, "n")
  30. #define bndPrintf printf
  31. /*
  32.  * Generate random numbers according to George Marsaglia's
  33.  * Mother Of All Random Number Generators.  This has a
  34.  * period of 0x17768215025F82EA0378038A03A203CA7FFF,
  35.  * or decimal 2043908804452974490458343567652678881935359.
  36.  */
  37. static unsigned mstate[8];
  38. static unsigned mcarry;
  39. static unsigned mindex;
  40. static unsigned
  41. mRandom(void)
  42. {
  43. unsigned long t;
  44. t = mcarry +
  45.     mstate[ mindex     ] * 1941ul +
  46.     mstate[(mindex+1)&7] * 1860ul +
  47.     mstate[(mindex+2)&7] * 1812ul +
  48.     mstate[(mindex+3)&7] * 1776ul +
  49.     mstate[(mindex+4)&7] * 1492ul +
  50.     mstate[(mindex+5)&7] * 1215ul +
  51.     mstate[(mindex+6)&7] * 1066ul +
  52.     mstate[(mindex+7)&7] * 12013ul;
  53. mcarry = (unsigned)(t >> 16); /* 0 <= mcarry <= 0x5a87 */
  54. mindex = (mindex-1) & 7;
  55. return mstate[mindex] = (unsigned)(t & 0xffff);
  56. }
  57. /*
  58.  * Initialize the RNG based on the given seed.
  59.  * A zero-length seed will produce pretty lousy numbers,
  60.  * but it will work.
  61.  */
  62. static void
  63. mSeed(unsigned char const *seed, unsigned len)
  64. {
  65. unsigned i;
  66. for (i = 0; i < 8; i++)
  67. mstate[i] = 0;
  68. mcarry = 1;
  69. while (len--) {
  70. mcarry += *seed++;
  71. (void)mRandom();
  72. }
  73. }
  74. /*
  75.  * Generate a bignum of a specified length, with the given
  76.  * high and low 8 bits. "High" is merged into the high 8 bits of the
  77.  * number.  For example, set it to 0x80 to ensure that the number is
  78.  * exactly "bits" bits long (i.e. 2^(bits-1) <= bn < 2^bits).
  79.  * "Low" is merged into the low 8 bits.  For example, set it to
  80.  * 1 to ensure that you generate an odd number.  "High" is merged
  81.  * into the high bits; set it to 0x80 to ensure that the high bit
  82.  * is set in the returned value.
  83.  */
  84. static int
  85. genRandBn(struct BigNum *bn, unsigned bits, unsigned char high,
  86. unsigned char low, unsigned char const *seed, unsigned len)
  87. {
  88. unsigned char buf[64];
  89. unsigned bytes;
  90. unsigned l = 0; /* Current position */
  91. unsigned i;
  92. bnSetQ(bn, 0);
  93. mSeed(seed, len);
  94. bytes = (bits+7) / 8; /* Number of bytes to use */
  95. for (i = 0; i < sizeof(buf); i++)
  96. buf[i] = (unsigned char)mRandom();
  97. buf[sizeof(buf)-1] |= low;
  98. while (bytes > sizeof(buf)) {
  99. bytes -= sizeof(buf);
  100. /* Merge in low half of high bits, if necessary */
  101. if (bytes == 1 && (bits & 7))
  102. buf[0] |= high << (bits & 7);
  103. if (bnInsertBigBytes(bn, buf, l, sizeof(buf)) < 0)
  104. return -1;
  105. l += sizeof(buf);
  106. for (i = 0; i < sizeof(buf); i++)
  107. buf[i] = (unsigned char)mRandom();
  108. }
  109. /* Do the final "bytes"-long section, using the tail bytes in buf */
  110. /* Mask off excess high bits */
  111. buf[sizeof(buf)-bytes] &= 255 >> (-bits & 7);
  112. /* Merge in specified high bits */
  113. buf[sizeof(buf)-bytes] |= high >> (-bits & 7);
  114. if (bytes > 1 && (bits & 7))
  115. buf[sizeof(buf)-bytes+1] |= high << (bits & 7);
  116. /* Merge in the appropriate bytes of the buffer */
  117. if (bnInsertBigBytes(bn, buf+sizeof(buf)-bytes, l, bytes) < 0)
  118. return -1;
  119. return 0;
  120. }
  121. struct Progress {
  122. FILE *f;
  123. unsigned column;
  124. unsigned wrap;
  125. };
  126. /* Print a progress indicator, with line-wrap */
  127. static int
  128. genProgress(void *arg, int c)
  129. {
  130. struct Progress *p = arg;
  131. if (++p->column > p->wrap) {
  132. putc('n', p->f);
  133. p->column = 1;
  134. }
  135. putc(c, p->f);
  136. fflush(p->f);
  137. return 0;
  138. }
  139. static int
  140. genSophieGermain(struct BigNum *bn, unsigned bits,
  141. unsigned char const *seed, unsigned len, FILE *f)
  142. {
  143. #if CLOCK_AVAIL
  144. timetype start, stop;
  145. unsigned long s;
  146. #endif
  147. int i;
  148. unsigned char s1[1024], s2[1024];
  149. unsigned p1, p2;
  150. struct BigNum step;
  151. struct Progress progress;
  152. if (f)
  153. fprintf(f, "Generating a %u-bit Sophie Germain prime with "%.*s"n",
  154. bits, (int)len, (char *)seed);
  155. progress.f = f;
  156. progress.column = 0;
  157. progress.wrap = 78;
  158. /* Find p - choose a starting place */
  159. if (genRandBn(bn, bits, 0xC0, 3, seed, len) < 0)
  160. return -1;
  161. #if BNDEBUG /* DEBUG - check that sieve works properly */
  162. bnBegin(&step);
  163. bnSetQ(&step, 2);
  164. sieveBuild(s1, 1024, bn, 2, 0);
  165. sieveBuildBig(s2, 1024, bn, &step, 0);
  166. p1 = p2 = 0;
  167. if (s1[0] != s2[0])
  168. printf("Difference: s1[0] = %x s2[0] = %xn", s1[0], s2[0]);
  169. do {
  170. p1 = sieveSearch(s1, 1024, p1);
  171. p2 = sieveSearch(s2, 1024, p2);
  172. if (p1 != p2)
  173. printf("Difference: p1 = %u p2 = %un", p1, p2);
  174. } while (p1 && p2);
  175. bnEnd(&step);
  176. #endif
  177. /* And search for a prime */
  178. #if CLOCK_AVAIL
  179. gettime(&start);
  180. #endif
  181. i = germainPrimeGen(bn, f ? genProgress : 0, (void *)&progress);
  182. if (i < 0)
  183. return -1;
  184. #if CLOCK_AVAIL
  185. gettime(&stop);
  186. #endif
  187. if (f) {
  188. putc('n', f);
  189. fprintf(f, "%d modular exponentiations performed.n", i);
  190. }
  191. #if CLOCK_AVAIL
  192. subtime(stop, start);
  193. s = sec(stop);
  194. bndPrintf("%u-bit time = %lu.%03u sec.", bits, s, msec(stop));
  195. if (s > 60) {
  196. putchar(' ');
  197. putchar('(');
  198. if (s > 3600)
  199. printf("%u:%02u", (unsigned)(s/3600),
  200.        (unsigned)(s/60%60));
  201. else
  202. printf("%u", (unsigned)(s/60));
  203. printf(":%02u)", (unsigned)(s%60));
  204. }
  205. putchar('n');
  206. #endif
  207. bndPut("p = ", bn);
  208. return 0;
  209. }
  210. /* Copy the command line to the buffer. */
  211. static unsigned
  212. copy(unsigned char *buf, int argc, char **argv)
  213. {
  214. unsigned pos, len;
  215. pos = 0;
  216. while (--argc) {
  217. len = strlen(*++argv);
  218. memcpy(buf, *argv, len);
  219. buf += len;
  220. pos += len;
  221. if (argc > 1) {
  222. *buf++ = ' ';
  223. pos++;
  224. }
  225. }
  226. return pos;
  227. }
  228. int
  229. main(int argc, char **argv)
  230. {
  231. unsigned len;
  232. struct BigNum bn;
  233. unsigned char buf[1024];
  234. if (argc < 2) {
  235. fprintf(stderr, "Usage: %s <seed>n", argv[0]);
  236. fputs("
  237. <seed> should be a a string of bytes to be hashed to seed the primen
  238. generator.  Note that unquoted whitespace between words will be countedn
  239. as a single space.  To include multiple spaces, quote them.n", stderr);
  240. return 1;
  241. }
  242. len = copy(buf, argc, argv);
  243. bnInit();
  244. bnBegin(&bn);
  245. genSophieGermain(&bn, 0x100, buf, len, stdout);
  246. genSophieGermain(&bn, 0x200, buf, len, stdout);
  247. genSophieGermain(&bn, 0x300, buf, len, stdout);
  248. genSophieGermain(&bn, 0x400, buf, len, stdout);
  249. genSophieGermain(&bn, 0x500, buf, len, stdout);
  250. genSophieGermain(&bn, 0x600, buf, len, stdout);
  251. #if 0
  252. /* These get *really* slow */
  253. genSophieGermain(&bn, 0x600, buf, len, stdout);
  254. genSophieGermain(&bn, 0x800, buf, len, stdout);
  255. genSophieGermain(&bn, 0xc00, buf, len, stdout);
  256. /* Like, plan on a *week* or more for this one. */
  257. genSophieGermain(&bn, 0x1000, buf, len, stdout);
  258. #endif
  259. bnEnd(&bn);
  260. return 0;
  261. }