bntest16.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. /*
  2. * Test driver for low-level bignum library (16-bit version).
  3. * This access the low-level library directly. It is NOT an example of
  4. * how to program with the library normally! By accessing the library
  5. * at a low level, it is possible to exercise the smallest components
  6. * and thus localize bugs more accurately. This is especially useful
  7. * when writing assembly-language primitives.
  8. *
  9. * This also does timing tests on modular exponentiation. Modular
  10. * exponentiation is so computationally expensive that the fact that this
  11. * code omits one level of interface glue has no perceptible effect on
  12. * the results.
  13. */
  14. #ifndef HAVE_CONFIG_H
  15. #define HAVE_CONFIG_H 0
  16. #endif
  17. #if HAVE_CONFIG_H
  18. #include "bnconfig.h"
  19. #endif
  20. /*
  21. * Some compilers complain about #if FOO if FOO isn't defined,
  22. * so do the ANSI-mandated thing explicitly...
  23. */
  24. #ifndef NO_STDLIB_H
  25. #define NO_STDLIB_H 0
  26. #endif
  27. #ifndef NO_STRING_H
  28. #define NO_STRING_H 0
  29. #endif
  30. #ifndef HAVE_STRINGS_H
  31. #define HAVE_STRINGS_H 0
  32. #endif
  33. #include <stdio.h>
  34. #if !NO_STDLIB_H
  35. #include <stdlib.h> /* For strtol */
  36. #else
  37. long strtol(const char *, char **, int);
  38. #endif
  39. #if !NO_STRING_H
  40. #include <string.h> /* For memcpy */
  41. #elif HAVE_STRINGS_H
  42. #include <strings.h>
  43. #endif
  44. #include "cputime.h"
  45. #include "lbn16.h"
  46. #include "kludge.h"
  47. #if BNYIELD
  48. int (*bnYield)(void) = 0;
  49. #endif
  50. /* Work with up to 2048-bit numbers */
  51. #define MAXBITS 3072
  52. #define SIZE (MAXBITS/16 + 1)
  53. /* Additive congruential random number generator, x[i] = x[i-24] + x[i-55] */
  54. static BNWORD16 randp[55];
  55. static BNWORD16 *randp1 = randp, *randp2 = randp+24;
  56. static BNWORD16
  57. rand16(void)
  58. {
  59. if (++randp2 == randp+55) {
  60. randp2 = randp;
  61. randp1++;
  62. } else if (++randp1 == randp+55) {
  63. randp1 = randp;
  64. }
  65. return *randp1 += *randp2;
  66. }
  67. /*
  68. * CRC-3_2: x^3_2+x^26+x^23+x^22+x^1_6+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1
  69. *
  70. * The additive congruential RNG is seeded with a single integer,
  71. * which is shuffled with a CRC polynomial to generate the initial
  72. * table values. The Polynomial is the same size as the words being
  73. * used.
  74. *
  75. * Thus, in the various versions of this library, we actually use this
  76. * polynomial as-is, this polynomial mod x^17, and this polynomial with
  77. * the leading coefficient deleted and replaced with x^6_4. As-is,
  78. * it's irreducible, so it has a long period. Modulo x^17, it factors as
  79. * (x^4+x^3+x^2+x+1) * (x^12+x^11+x^8+x^7+x^6+x^5+x^4+x^3+1),
  80. * which still has a large enough period (4095) for the use it's put to.
  81. * With the leading coefficient moved up, it factors as
  82. * (x^50+x^49+x^48+x^47+x^46+x^43+x^41+x^40+x^38+x^37+x^36+x^35+x^34+x^33+
  83. * x^31+x^30+x^29+x^28+x^27+x^25+x^23+x^18+x^1_6+x^15+x^14+x^13+x^11+x^9+
  84. * x^8+x^7+x^6+x^5+x^3+x^2+1)*(x^11+x^10+x^9+x^5+x^4+x^3+1)*(x^3+x+1),
  85. * which definitely has a long enough period to serve for initialization.
  86. *
  87. * The effort put into this PRNG is kind of unwarranted given the trivial
  88. * use it's being put to, but oh, well. It does have the nice advantage
  89. * of producing numbers that are portable between platforms, so if there's
  90. * a problem with one platform, you can compare all the intermediate
  91. * results with another platform.
  92. */
  93. #define POLY (BNWORD16)0x04c11db7
  94. static void
  95. srand16(BNWORD16 seed)
  96. {
  97. int i, j;
  98. for (i = 0; i < 55; i++) {
  99. for (j = 0; j < 16; j++)
  100. if (seed >> (16-1))
  101. seed = (seed << 1) ^ POLY;
  102. else
  103. seed <<= 1;
  104. randp[i] = seed;
  105. }
  106. for (i = 0; i < 3*55; i ++)
  107. rand16();
  108. }
  109. static void
  110. randnum(BNWORD16 *num, unsigned len)
  111. {
  112. while (len--)
  113. BIGLITTLE(*--num,*num++) = rand16();
  114. }
  115. static void
  116. bnprint16(BNWORD16 const *num, unsigned len)
  117. {
  118. BIGLITTLE(num -= len, num += len);
  119. while (len--)
  120. printf("%0*lX", 16/4, (unsigned long)BIGLITTLE(*num++,*--num));
  121. }
  122. static void
  123. bnput16(char const *prompt, BNWORD16 const *num, unsigned len)
  124. {
  125. fputs(prompt, stdout);
  126. bnprint16(num, len);
  127. putchar('\n');
  128. }
  129. /*
  130. * One of our tests uses a known prime. The following selections were
  131. * taken from the tables at the end of Hans Reisel's "Prime Numbers and
  132. * Computer Methods for Factorization", second edition - an excellent book.
  133. * (ISBN 0-8176-3743-5 ISBN 3-7323-3743-5)
  134. */
  135. #if 0
  136. /* P31=1839605 17620282 38179967 87333633 from the factors of 3^256+2^256 */
  137. static unsigned char const prime[] = {
  138. 0x17,0x38,0x15,0xBC,0x8B,0xBB,0xE9,0xEF,0x01,0xA9,0xFD,0x3A,0x01
  139. };
  140. #elif 0
  141. /* P48=40554942 04557502 46193993 36199835 4279613_2 73199617 from the same */
  142. static unsigned char const prime[] = {
  143. 0x47,0x09,0x77,0x07,0xCF,0xFD,0xE1,0x54,0x3E,0x24,
  144. 0xF7,0xF1,0x7A,0x3E,0x91,0x51,0xCC,0xC7,0xD4,0x01
  145. };
  146. #elif 0
  147. /*
  148. * P75 = 450 55287320 97906895 47687014 5808213_2
  149. * 05219565 99525911 39967932 66003_258 91979521
  150. * from the factors of 4^128+3+128
  151. * (The "026" and "062" are to prevent a Bad String from appearing here.)
  152. */
  153. static unsigned char const prime[] = {
  154. 0xFF,0x00,0xFF,0x00,0xFF,0x01,0x06,0x4F,0xF8,0xED,
  155. 0xA3,0x37,0x23,0x2A,0x04,0xEA,0xF9,0x5F,0x30,0x4C,
  156. 0xAE,0xCD, 026,0x4E, 062,0x10,0x04,0x7D,0x0D,0x79,
  157. 0x01
  158. };
  159. #else
  160. /*
  161. * P75 = 632 85659796 45277755 9123_2190 67300940
  162. * 51844953 78793489 59444670 35675855 57440257
  163. * from the factors of 5^128+4^128
  164. * (The "026" is to prevent a Bad String from appearing here.)
  165. */
  166. static unsigned char const prime[] = {
  167. 0x01,0x78,0x4B,0xA5,0xD3,0x30,0x03,0xEB,0x73,0xE6,
  168. 0x0F,0x4E,0x31,0x7D,0xBC,0xE2,0xA0,0xD4, 026,0x3F,
  169. 0x3C,0xEA,0x1B,0x44,0xAD,0x39,0xE7,0xE5,0xAD,0x19,
  170. 0x67,0x01
  171. };
  172. #endif
  173. static int
  174. usage(char const *name)
  175. {
  176. fprintf(stderr, "Usage: %s [modbits [expbits [expbits2]]\n"
  177. "With no arguments, just runs test suite. If modbits is given, runs\n"
  178. "quick validation test, then runs timing tests of modular exponentiation.\n"
  179. "If expbits is given, it is used as an exponent size, otherwise it defaults\n"
  180. "to the same as modbits. If expbits2 is given it is used as the second\n"
  181. "exponent size in the double-exponentiation tests, otherwise it defaults\n"
  182. "to the same as expbits. All are limited to %u bits.\n",
  183. name, (unsigned)MAXBITS);
  184. return 1;
  185. }
  186. /* for libzrtp support */
  187. int
  188. bntest_main(int argc, char **argv)
  189. {
  190. unsigned i, j, k, l, m;
  191. int z;
  192. BNWORD16 t, carry, borrow;
  193. BNWORD16 a[SIZE], b[SIZE], c[SIZE], d[SIZE];
  194. BNWORD16 e[SIZE], f[SIZE];
  195. static BNWORD16 entries[sizeof(prime)*2][(sizeof(prime)-1)/(16/8)+1];
  196. BNWORD16 *array[sizeof(prime)*2];
  197. unsigned long modbits = 0, expbits = 0, expbits2 = 0;
  198. char *p;
  199. #define A BIGLITTLE((a+SIZE),a)
  200. #define B BIGLITTLE((b+SIZE),b)
  201. #define C BIGLITTLE((c+SIZE),c)
  202. #define D BIGLITTLE((d+SIZE),d)
  203. #define E BIGLITTLE((e+SIZE),e)
  204. #define F BIGLITTLE((f+SIZE),f)
  205. static unsigned const smallprimes[] = {
  206. 2, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43
  207. };
  208. /* Set up array for precomputed modexp */
  209. for (i = 0; i < sizeof(array)/sizeof(*array); i++)
  210. array[i] = entries[i] BIG(+ SIZE);
  211. srand16(1);
  212. puts(BIGLITTLE("Big-endian machine","Little-endian machine"));
  213. if (argc >= 2) {
  214. modbits = strtoul(argv[1], &p, 0);
  215. if (!modbits || *p) {
  216. fprintf(stderr, "Invalid modbits: %s\n", argv[1]);
  217. return usage(argv[0]);
  218. }
  219. }
  220. if (argc >= 3) {
  221. expbits = strtoul(argv[2], &p, 0);
  222. if (!expbits || *p) {
  223. fprintf(stderr, "Invalid expbits: %s\n", argv[2]);
  224. return usage(argv[0]);
  225. }
  226. expbits2 = expbits;
  227. }
  228. if (argc >= 4) {
  229. expbits2 = strtoul(argv[3], &p, 0);
  230. if (!expbits2 || *p) {
  231. fprintf(stderr, "Invalid expbits2: %s\n", argv[3]);
  232. return usage(argv[0]);
  233. }
  234. }
  235. if (argc >= 5) {
  236. fprintf(stderr, "Too many arguments: %s\n", argv[4]);
  237. return usage(argv[0]);
  238. }
  239. /* B is a nice not-so-little prime */
  240. lbnInsertBigBytes_16(B, prime, 0, sizeof(prime));
  241. ((unsigned char *)c)[0] = 0;
  242. lbnInsertBigBytes_16(B, (unsigned char *)c, sizeof(prime), 1);
  243. lbnExtractBigBytes_16(B, (unsigned char *)c, 0, sizeof(prime)+1);
  244. i = (sizeof(prime)-1)/(16/8)+1; /* Size of array in words */
  245. if (((unsigned char *)c)[0] ||
  246. memcmp(prime, (unsigned char *)c+1, sizeof(prime)) != 0)
  247. {
  248. printf("Input != output!:\n ");
  249. for (k = 0; k < sizeof(prime); k++)
  250. printf("%02X ", prime[k]);
  251. putchar('\n');
  252. for (k = 0; k < sizeof(prime)+1; k++)
  253. printf("%02X ", ((unsigned char *)c)[k]);
  254. putchar('\n');
  255. bnput16("p = ", B, i);
  256. }
  257. /* Timing test code - only if requested on the command line */
  258. if (modbits) {
  259. timetype start, stop;
  260. unsigned long cursec, expsec, twoexpsec, dblexpsec;
  261. unsigned curms, expms, twoexpms, dblexpms;
  262. expsec = twoexpsec = dblexpsec = 0;
  263. expms = twoexpms = dblexpms = 0;
  264. lbnCopy_16(C,B,i);
  265. lbnSub1_16(C,i,1); /* C is exponent: p-1 */
  266. puts("Testing modexp with a known prime. "
  267. "All results should be 1.");
  268. bnput16("p = ", B, i);
  269. bnput16("p-1 = ", C, i);
  270. z = lbnTwoExpMod_16(A, C, i, B, i);
  271. if (z < 0)
  272. goto nomem;
  273. bnput16("2^(p-1) mod p = ", A, i);
  274. for (j = 0; j < 10; j++) {
  275. randnum(A,i);
  276. (void)lbnDiv_16(D,A,i,B,i);
  277. bnput16("a = ", A, i);
  278. z = lbnExpMod_16(D, A, i, C, i, B, i);
  279. if (z < 0)
  280. goto nomem;
  281. bnput16("a^(p-1) mod p = ", D, i);
  282. #if 0
  283. z = lbnBasePrecompBegin_16(array, (sizeof(prime)*8+4)/5, 5,
  284. A, i, B, i);
  285. if (z < 0)
  286. goto nomem;
  287. BIGLITTLE(D[-1],D[0]) = -1;
  288. z = lbnBasePrecompExp_16(D, (BNWORD16 const * const *)array,
  289. 5, C, i, B, i);
  290. if (z < 0)
  291. goto nomem;
  292. bnput16("a^(p-1) mod p = ", D, i);
  293. #endif
  294. for (k = 0; k < 5; k++) {
  295. randnum(E,i);
  296. bnput16("e = ", E, i);
  297. z = lbnExpMod_16(D, A, i, E, i, B, i);
  298. if (z < 0)
  299. goto nomem;
  300. bnput16("a^e mod p = ", D, i);
  301. #if 0
  302. z = lbnBasePrecompExp_16(D, (BNWORD16 const * const *)array,
  303. 5, E, i, B, i);
  304. if (z < 0)
  305. goto nomem;
  306. bnput16("a^e mod p = ", D, i);
  307. #endif
  308. }
  309. }
  310. printf("\n"
  311. "Timing exponentiations modulo a %d-bit modulus, i.e.\n"
  312. "2^<%d> mod <%d> bits, <%d>^<%d> mod <%d> bits and\n"
  313. "<%d>^<%d> * <%d>^<%d> mod <%d> bits\n",
  314. (int)modbits, (int)expbits, (int)modbits,
  315. (int)modbits, (int)expbits, (int)modbits,
  316. (int)modbits, (int)expbits, (int)modbits, (int)expbits2,
  317. (int)modbits);
  318. i = ((int)modbits-1)/16+1;
  319. k = ((int)expbits-1)/16+1;
  320. l = ((int)expbits2-1)/16+1;
  321. for (j = 0; j < 25; j++) {
  322. randnum(A,i); /* Base */
  323. randnum(B,k); /* Exponent */
  324. randnum(C,i); /* Modulus */
  325. randnum(D,i); /* Base2 */
  326. randnum(E,l); /* Exponent */
  327. /* Clip bases and mod to appropriate number of bits */
  328. t = ((BNWORD16)2<<((modbits-1)%16)) - 1;
  329. *(BIGLITTLE(A-i,A+i-1)) &= t;
  330. *(BIGLITTLE(C-i,C+i-1)) &= t;
  331. *(BIGLITTLE(D-i,D+i-1)) &= t;
  332. /* Make modulus large (msbit set) and odd (lsbit set) */
  333. *(BIGLITTLE(C-i,C+i-1)) |= (t >> 1) + 1;
  334. BIGLITTLE(C[-1],C[0]) |= 1;
  335. /* Clip exponent to appropriate number of bits */
  336. t = ((BNWORD16)2<<((expbits-1)%16)) - 1;
  337. *(BIGLITTLE(B-k,B+k-1)) &= t;
  338. /* Make exponent large (msbit set) */
  339. *(BIGLITTLE(B-k,B+k-1)) |= (t >> 1) + 1;
  340. /* The same for exponent 2 */
  341. t = ((BNWORD16)2<<((expbits2-1)%16)) - 1;
  342. *(BIGLITTLE(E-l,E+l-1)) &= t;
  343. *(BIGLITTLE(E-l,E+l-1)) |= (t >> 1) + 1;
  344. m = lbnBits_16(A, i);
  345. if (m > (unsigned)modbits) {
  346. bnput16("a = ", a, i);
  347. printf("%u bits, should be <= %d\n",
  348. m, (int)modbits);
  349. }
  350. m = lbnBits_16(B, k);
  351. if (m != (unsigned)expbits) {
  352. bnput16("b = ", b, i);
  353. printf("%u bits, should be %d\n",
  354. m, (int)expbits);
  355. }
  356. m = lbnBits_16(C, i);
  357. if (m != (unsigned)modbits) {
  358. bnput16("c = ", c, k);
  359. printf("%u bits, should be %d\n",
  360. m, (int)modbits);
  361. }
  362. m = lbnBits_16(D, i);
  363. if (m > (unsigned)modbits) {
  364. bnput16("d = ", d, i);
  365. printf("%u bits, should be <= %d\n",
  366. m, (int)modbits);
  367. }
  368. m = lbnBits_16(E, l);
  369. if (m != (unsigned)expbits2) {
  370. bnput16("e = ", e, i);
  371. printf("%u bits, should be %d\n",
  372. m, (int)expbits2);
  373. }
  374. gettime(&start);
  375. z = lbnTwoExpMod_16(A, B, k, C, i);
  376. if (z < 0)
  377. goto nomem;
  378. gettime(&stop);
  379. subtime(stop, start);
  380. twoexpsec += cursec = sec(stop);
  381. twoexpms += curms = msec(stop);
  382. printf("2^<%d>:%4lu.%03u ", (int)expbits, cursec, curms);
  383. fflush(stdout);
  384. gettime(&start);
  385. z = lbnExpMod_16(A, A, i, B, k, C, i);
  386. if (z < 0)
  387. goto nomem;
  388. gettime(&stop);
  389. subtime(stop, start);
  390. expsec += cursec = sec(stop);
  391. expms += curms = msec(stop);
  392. printf("<%d>^<%d>:%4lu.%03u ",(int)modbits, (int)expbits,
  393. cursec, curms);
  394. fflush(stdout);
  395. #if 0
  396. gettime(&start);
  397. z = lbnDoubleExpMod_16(D, A, i, B, k, D, i, E, l,C,i);
  398. if (z < 0)
  399. goto nomem;
  400. gettime(&stop);
  401. subtime(stop, start);
  402. dblexpsec += cursec = sec(stop);
  403. dblexpms += curms = msec(stop);
  404. printf("<%d>^<%d>*<%d>^<%d>:%4lu.%03u\n",
  405. (int)modbits, (int)expbits,
  406. (int)modbits, (int)expbits2,
  407. cursec, curms);
  408. #else
  409. putchar('\n');
  410. #endif
  411. }
  412. twoexpms += (twoexpsec % j) * 1000;
  413. printf("2^<%d> mod <%d> bits AVERAGE: %4lu.%03u s\n",
  414. (int)expbits, (int)modbits, twoexpsec/j, twoexpms/j);
  415. expms += (expsec % j) * 1000;
  416. printf("<%d>^<%d> mod <%d> bits AVERAGE: %4lu.%03u s\n",
  417. (int)modbits, (int)expbits, (int)modbits, expsec/j, expms/j);
  418. #if 0
  419. dblexpms += (dblexpsec % j) * 1000;
  420. printf("<%d>^<%d> * <%d>^<%d> mod <%d> bits AVERAGE:"
  421. " %4lu.%03u s\n",
  422. (int)modbits, (int)expbits, (int)modbits,
  423. (int)expbits2,
  424. (int)modbits, dblexpsec/j, dblexpms/j);
  425. #endif
  426. putchar('\n');
  427. }
  428. printf("Beginning 1000 interations of sanity checking.\n");
  429. printf("Any output indicates a bug. No output is very strong\n");
  430. printf("evidence that all the important low-level bignum routines\n");
  431. printf("are working properly.\n");
  432. /*
  433. * If you change this loop to have an iteration 0, all results
  434. * are primted on that iteration. Useful to see what's going
  435. * on in case of major wierdness, but it produces a *lot* of
  436. * output.
  437. */
  438. for (j = 1; j <= 1000; j++) {
  439. /* Do the tests for lots of different number sizes. */
  440. for (i = 1; i <= SIZE/2; i++) {
  441. /* Make a random number i words long */
  442. do {
  443. randnum(A,i);
  444. } while (lbnNorm_16(A,i) < i);
  445. /* Checl lbnCmp - does a == a? */
  446. if (lbnCmp_16(A,A,i) || !j) {
  447. bnput16("a = ", A, i);
  448. printf("(a <=> a) = %d\n", lbnCmp_16(A,A,i));
  449. }
  450. memcpy(c, a, sizeof(a));
  451. /* Check that the difference, after copy, is good. */
  452. if (lbnCmp_16(A,C,i) || !j) {
  453. bnput16("a = ", A, i);
  454. bnput16("c = ", C, i);
  455. printf("(a <=> c) = %d\n", lbnCmp_16(A,C,i));
  456. }
  457. /* Generate a non-zero random t */
  458. do {
  459. t = rand16();
  460. } while (!t);
  461. /*
  462. * Add t to A. Check that:
  463. * - lbnCmp works in both directions, and
  464. * - A + t is greater than A. If there was a carry,
  465. * the result, less the carry, should be *less*
  466. * than A.
  467. */
  468. carry = lbnAdd1_16(A,i,t);
  469. if (lbnCmp_16(A,C,i) + lbnCmp_16(C,A,i) != 0 ||
  470. lbnCmp_16(A,C,i) != (carry ? -1 : 1) || !j)
  471. {
  472. bnput16("c = ", C, i);
  473. printf("t = %lX\n", (unsigned long)t);
  474. bnput16("a = c+t = ", A, i);
  475. printf("carry = %lX\n", (unsigned long)carry);
  476. printf("(a <=> c) = %d\n", lbnCmp_16(A,C,i));
  477. printf("(c <=> a) = %d\n", lbnCmp_16(C,A,i));
  478. }
  479. /* Subtract t again */
  480. memcpy(d, a, sizeof(a));
  481. borrow = lbnSub1_16(A,i,t);
  482. if (carry != borrow || lbnCmp_16(A,C,i) || !j) {
  483. bnput16("a = ", C, i);
  484. printf("t = %lX\n", (unsigned long)t);
  485. lbnAdd1_16(A,i,t);
  486. bnput16("a += t = ", A, i);
  487. printf("Carry = %lX\n", (unsigned long)carry);
  488. lbnSub1_16(A,i,t);
  489. bnput16("a -= t = ", A, i);
  490. printf("Borrow = %lX\n", (unsigned long)borrow);
  491. printf("(a <=> c) = %d\n", lbnCmp_16(A,C,i));
  492. }
  493. /* Generate a random B */
  494. do {
  495. randnum(B,i);
  496. } while (lbnNorm_16(B,i) < i);
  497. carry = lbnAddN_16(A,B,i);
  498. memcpy(d, a, sizeof(a));
  499. borrow = lbnSubN_16(A,B,i);
  500. if (carry != borrow || lbnCmp_16(A,C,i) || !j) {
  501. bnput16("a = ", C, i);
  502. bnput16("b = ", B, i);
  503. bnput16("a += b = ", D, i);
  504. printf("Carry = %lX\n", (unsigned long)carry);
  505. bnput16("a -= b = ", A, i);
  506. printf("Borrow = %lX\n", (unsigned long)borrow);
  507. printf("(a <=> c) = %d\n", lbnCmp_16(A,C,i));
  508. }
  509. /* D = B * t */
  510. lbnMulN1_16(D, B, i, t);
  511. memcpy(e, d, sizeof(e));
  512. /* D = A + B * t, "carry" is overflow */
  513. borrow = *(BIGLITTLE(D-i-1,D+i)) += lbnAddN_16(D,A,i);
  514. carry = lbnMulAdd1_16(A, B, i, t);
  515. /* Did MulAdd get the same answer as mul then add? */
  516. if (carry != borrow || lbnCmp_16(A, D, i) || !j) {
  517. bnput16("a = ", C, i);
  518. bnput16("b = ", B, i);
  519. printf("t = %lX\n", (unsigned long)t);
  520. bnput16("e = b * t = ", E, i+1);
  521. bnput16(" a + e = ", D, i+1);
  522. bnput16("a + b * t = ", A, i);
  523. printf("carry = %lX\n", (unsigned long)carry);
  524. }
  525. memcpy(d, a, sizeof(a));
  526. borrow = lbnMulSub1_16(A, B, i, t);
  527. /* Did MulSub perform the inverse of MulAdd */
  528. if (carry != borrow || lbnCmp_16(A,C,i) || !j) {
  529. bnput16(" a = ", C, i);
  530. bnput16(" b = ", B, i);
  531. bnput16("a += b*t = ", D, i);
  532. printf("Carry = %lX\n", (unsigned long)carry);
  533. bnput16("a -= b*t = ", A, i);
  534. printf("Borrow = %lX\n", (unsigned long)borrow);
  535. printf("(a <=> c) = %d\n", lbnCmp_16(A,C,i));
  536. bnput16("b*t = ", E, i+1);
  537. }
  538. /* At this point we're done with t, so it's scratch */
  539. #if 0
  540. /* Extra debug code */
  541. lbnMulN1_16(C, A, i, BIGLITTLE(B[-1],B[0]));
  542. bnput16("a * b[0] = ", C, i+1);
  543. for (k = 1; k < i; k++) {
  544. carry = lbnMulAdd1_16(BIGLITTLE(C-k,C+k), A, i,
  545. *(BIGLITTLE(B-1-k,B+k)));
  546. *(BIGLITTLE(C-i-k,C+i+k)) = carry;
  547. bnput16("a * b[x] = ", C, i+k+1);
  548. }
  549. lbnMulN1_16(D, B, i, BIGLITTLE(A[-1],A[0]));
  550. bnput16("b * a[0] = ", D, i+1);
  551. for (k = 1; k < i; k++) {
  552. carry = lbnMulAdd1_16(BIGLITTLE(D-k,D+k), B, i,
  553. *(BIGLITTLE(A-1-k,A+k)));
  554. *(BIGLITTLE(D-i-k,D+i+k)) = carry;
  555. bnput16("b * a[x] = ", D, i+k+1);
  556. }
  557. #endif
  558. /* Does Mul work both ways symmetrically */
  559. lbnMul_16(C,A,i,B,i);
  560. lbnMul_16(D,B,i,A,i);
  561. if (lbnCmp_16(C,D,i+i) || !j) {
  562. bnput16("a = ", A, i);
  563. bnput16("b = ", B, i);
  564. bnput16("a * b = ", C, i+i);
  565. bnput16("b * a = ", D, i+i);
  566. printf("(a*b <=> b*a) = %d\n",
  567. lbnCmp_16(C,D,i+i));
  568. }
  569. /* Check multiplication modulo some small things */
  570. /* 30030 = 2*3*5*11*13 */
  571. k = lbnModQ_16(C, i+i, 30030);
  572. for (l = 0;
  573. l < sizeof(smallprimes)/sizeof(*smallprimes);
  574. l++)
  575. {
  576. m = smallprimes[l];
  577. t = lbnModQ_16(C, i+i, m);
  578. carry = lbnModQ_16(A, i, m);
  579. borrow = lbnModQ_16(B, i, m);
  580. if (t != (carry * borrow) % m) {
  581. bnput16("a = ", A, i);
  582. printf("a mod %u = %u\n", m,
  583. (unsigned)carry);
  584. bnput16("b = ", B, i);
  585. printf("b mod %u = %u\n", m,
  586. (unsigned)borrow);
  587. bnput16("a*b = ", C, i+i);
  588. printf("a*b mod %u = %u\n", m,
  589. (unsigned)t);
  590. printf("expected %u\n",
  591. (unsigned)((carry*borrow)%m));
  592. }
  593. /* Verify that (C % 30030) % m == C % m */
  594. if (m <= 13 && t != k % m) {
  595. printf("c mod 30030 = %u mod %u= %u\n",
  596. k, m, k%m);
  597. printf("c mod %u = %u\n",
  598. m, (unsigned)t);
  599. }
  600. }
  601. /* Generate an F less than A and B */
  602. do {
  603. randnum(F,i);
  604. } while (lbnCmp_16(F,A,i) >= 0 ||
  605. lbnCmp_16(F,B,i) >= 0);
  606. /* Add F to D (remember, D = A*B) */
  607. lbnAdd1_16(BIGLITTLE(D-i,D+i), i, lbnAddN_16(D, F, i));
  608. memcpy(c, d, sizeof(d));
  609. /*
  610. * Divide by A and check that quotient and remainder
  611. * match (remainder should be F, quotient should be B)
  612. */
  613. t = lbnDiv_16(E,C,i+i,A,i);
  614. if (t || lbnCmp_16(E,B,i) || lbnCmp_16(C, F, i) || !j) {
  615. bnput16("a = ", A, i);
  616. bnput16("b = ", B, i);
  617. bnput16("f = ", F, i);
  618. bnput16("a * b + f = ", D, i+i);
  619. printf("qhigh = %lX\n", (unsigned long)t);
  620. bnput16("(a*b+f) / a = ", E, i);
  621. bnput16("(a*b+f) % a = ", C, i);
  622. }
  623. memcpy(c, d, sizeof(d));
  624. /* Divide by B and check similarly */
  625. t = lbnDiv_16(E,C,i+i,B,i);
  626. if (lbnCmp_16(E,A,i) || lbnCmp_16(C, F, i) || !j) {
  627. bnput16("a = ", A, i);
  628. bnput16("b = ", B, i);
  629. bnput16("f = ", F, i);
  630. bnput16("a * b + f = ", D, i+i);
  631. printf("qhigh = %lX\n", (unsigned long)t);
  632. bnput16("(a*b+f) / b = ", E, i);
  633. bnput16("(a*b+f) % b = ", C, i);
  634. }
  635. /* Check that A*A == A^2 */
  636. lbnMul_16(C,A,i,A,i);
  637. lbnSquare_16(D,A,i);
  638. if (lbnCmp_16(C,D,i+i) || !j) {
  639. bnput16("a*a = ", C, i+i);
  640. bnput16("a^2 = ", D, i+i);
  641. printf("(a * a == a^2) = %d\n",
  642. lbnCmp_16(C,D,i+i));
  643. }
  644. #if 0
  645. /* Compute a GCD */
  646. lbnCopy_16(C,A,i);
  647. lbnCopy_16(D,B,i);
  648. z = lbnGcd_16(C, i, D, i, &k);
  649. if (z < 0)
  650. goto nomem;
  651. /* z = 1 if GCD in D; z = 0 if GCD in C */
  652. /* Approximate check that the GCD came out right */
  653. for (l = 0;
  654. l < sizeof(smallprimes)/sizeof(*smallprimes);
  655. l++)
  656. {
  657. m = smallprimes[l];
  658. t = lbnModQ_16(z ? D : C, k, m);
  659. carry = lbnModQ_16(A, i, m);
  660. borrow = lbnModQ_16(B, i, m);
  661. if (!t != (!carry && !borrow)) {
  662. bnput16("a = ", A, i);
  663. printf("a mod %u = %u\n", m,
  664. (unsigned)carry);
  665. bnput16("b = ", B, i);
  666. printf("b mod %u = %u\n", m,
  667. (unsigned)borrow);
  668. bnput16("gcd(a,b) = ", z ? D : C, k);
  669. printf("gcd(a,b) mod %u = %u\n", m,
  670. (unsigned)t);
  671. }
  672. }
  673. #endif
  674. /*
  675. * Do some Montgomery operations
  676. * Start with A > B, and also place a copy of B into C.
  677. * Then make A odd so it can be a Montgomery modulus.
  678. */
  679. if (lbnCmp_16(A, B, i) < 0) {
  680. memcpy(c, a, sizeof(c));
  681. memcpy(a, b, sizeof(a));
  682. memcpy(b, c, sizeof(b));
  683. } else {
  684. memcpy(c, b, sizeof(c));
  685. }
  686. BIGLITTLE(A[-1],A[0]) |= 1;
  687. /* Convert to and from */
  688. lbnToMont_16(B, i, A, i);
  689. lbnFromMont_16(B, A, i);
  690. if (lbnCmp_16(B, C, i)) {
  691. memcpy(b, c, sizeof(c));
  692. bnput16("mod = ", A, i);
  693. bnput16("input = ", B, i);
  694. lbnToMont_16(B, i, A, i);
  695. bnput16("mont = ", B, i);
  696. lbnFromMont_16(B, A, i);
  697. bnput16("output = ", B, i);
  698. }
  699. /* E = B^5 (mod A), no Montgomery ops */
  700. lbnSquare_16(E, B, i);
  701. (void)lbnDiv_16(BIGLITTLE(E-i,E+i),E,i+i,A,i);
  702. lbnSquare_16(D, E, i);
  703. (void)lbnDiv_16(BIGLITTLE(D-i,D+i),D,i+i,A,i);
  704. lbnMul_16(E, D, i, B, i);
  705. (void)lbnDiv_16(BIGLITTLE(E-i,E+i),E,i+i,A,i);
  706. /* D = B^5, using ExpMod */
  707. BIGLITTLE(F[-1],F[0]) = 5;
  708. z = lbnExpMod_16(D, B, i, F, 1, A, i);
  709. if (z < 0)
  710. goto nomem;
  711. if (lbnCmp_16(D, E, i) || !j) {
  712. bnput16("mod = ", A, i);
  713. bnput16("input = ", B, i);
  714. bnput16("input^5 = ", E, i);
  715. bnput16("input^5 = ", D, i);
  716. printf("a>b (x <=> y) = %d\n",
  717. lbnCmp_16(D,E,i));
  718. }
  719. /* TODO: Test lbnTwoExpMod, lbnDoubleExpMod */
  720. } /* for (i) */
  721. printf("\r%d ", j);
  722. fflush(stdout);
  723. } /* for (j) */
  724. printf("%d iterations of up to %d 16-bit words completed.\n",
  725. j-1, i-1);
  726. return 0;
  727. nomem:
  728. printf("Out of memory\n");
  729. return 1;
  730. }