1 /*	$NetBSD: demo.c,v 1.1.1.2 2014/04/24 12:45:39 pettai Exp $	*/
2 
3 #include <time.h>
4 
5 #ifdef IOWNANATHLON
6 #include <unistd.h>
7 #define SLEEP sleep(4)
8 #else
9 #define SLEEP
10 #endif
11 
12 #include "tommath.h"
13 
ndraw(mp_int * a,char * name)14 void ndraw(mp_int * a, char *name)
15 {
16    char buf[16000];
17 
18    printf("%s: ", name);
19    mp_toradix(a, buf, 10);
20    printf("%s\n", buf);
21 }
22 
draw(mp_int * a)23 static void draw(mp_int * a)
24 {
25    ndraw(a, "");
26 }
27 
28 
29 unsigned long lfsr = 0xAAAAAAAAUL;
30 
lbit(void)31 int lbit(void)
32 {
33    if (lfsr & 0x80000000UL) {
34       lfsr = ((lfsr << 1) ^ 0x8000001BUL) & 0xFFFFFFFFUL;
35       return 1;
36    } else {
37       lfsr <<= 1;
38       return 0;
39    }
40 }
41 
myrng(unsigned char * dst,int len,void * dat)42 int myrng(unsigned char *dst, int len, void *dat)
43 {
44    int x;
45 
46    for (x = 0; x < len; x++)
47       dst[x] = rand() & 0xFF;
48    return len;
49 }
50 
51 
52 
53 char cmd[4096], buf[4096];
main(void)54 int main(void)
55 {
56    mp_int a, b, c, d, e, f;
57    unsigned long expt_n, add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n,
58       gcd_n, lcm_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n, t;
59    unsigned rr;
60    int i, n, err, cnt, ix, old_kara_m, old_kara_s;
61    mp_digit mp;
62 
63 
64    mp_init(&a);
65    mp_init(&b);
66    mp_init(&c);
67    mp_init(&d);
68    mp_init(&e);
69    mp_init(&f);
70 
71    srand(time(NULL));
72 
73 #if 0
74    // test montgomery
75    printf("Testing montgomery...\n");
76    for (i = 1; i < 10; i++) {
77       printf("Testing digit size: %d\n", i);
78       for (n = 0; n < 1000; n++) {
79          mp_rand(&a, i);
80          a.dp[0] |= 1;
81 
82          // let's see if R is right
83          mp_montgomery_calc_normalization(&b, &a);
84          mp_montgomery_setup(&a, &mp);
85 
86          // now test a random reduction
87          for (ix = 0; ix < 100; ix++) {
88              mp_rand(&c, 1 + abs(rand()) % (2*i));
89              mp_copy(&c, &d);
90              mp_copy(&c, &e);
91 
92              mp_mod(&d, &a, &d);
93              mp_montgomery_reduce(&c, &a, mp);
94              mp_mulmod(&c, &b, &a, &c);
95 
96              if (mp_cmp(&c, &d) != MP_EQ) {
97 printf("d = e mod a, c = e MOD a\n");
98 mp_todecimal(&a, buf); printf("a = %s\n", buf);
99 mp_todecimal(&e, buf); printf("e = %s\n", buf);
100 mp_todecimal(&d, buf); printf("d = %s\n", buf);
101 mp_todecimal(&c, buf); printf("c = %s\n", buf);
102 printf("compare no compare!\n"); exit(EXIT_FAILURE); }
103          }
104       }
105    }
106    printf("done\n");
107 
108    // test mp_get_int
109    printf("Testing: mp_get_int\n");
110    for (i = 0; i < 1000; ++i) {
111       t = ((unsigned long) rand() * rand() + 1) & 0xFFFFFFFF;
112       mp_set_int(&a, t);
113       if (t != mp_get_int(&a)) {
114 	 printf("mp_get_int() bad result!\n");
115 	 return 1;
116       }
117    }
118    mp_set_int(&a, 0);
119    if (mp_get_int(&a) != 0) {
120       printf("mp_get_int() bad result!\n");
121       return 1;
122    }
123    mp_set_int(&a, 0xffffffff);
124    if (mp_get_int(&a) != 0xffffffff) {
125       printf("mp_get_int() bad result!\n");
126       return 1;
127    }
128    // test mp_sqrt
129    printf("Testing: mp_sqrt\n");
130    for (i = 0; i < 1000; ++i) {
131       printf("%6d\r", i);
132       fflush(stdout);
133       n = (rand() & 15) + 1;
134       mp_rand(&a, n);
135       if (mp_sqrt(&a, &b) != MP_OKAY) {
136 	 printf("mp_sqrt() error!\n");
137 	 return 1;
138       }
139       mp_n_root(&a, 2, &a);
140       if (mp_cmp_mag(&b, &a) != MP_EQ) {
141 	 printf("mp_sqrt() bad result!\n");
142 	 return 1;
143       }
144    }
145 
146    printf("\nTesting: mp_is_square\n");
147    for (i = 0; i < 1000; ++i) {
148       printf("%6d\r", i);
149       fflush(stdout);
150 
151       /* test mp_is_square false negatives */
152       n = (rand() & 7) + 1;
153       mp_rand(&a, n);
154       mp_sqr(&a, &a);
155       if (mp_is_square(&a, &n) != MP_OKAY) {
156 	 printf("fn:mp_is_square() error!\n");
157 	 return 1;
158       }
159       if (n == 0) {
160 	 printf("fn:mp_is_square() bad result!\n");
161 	 return 1;
162       }
163 
164       /* test for false positives */
165       mp_add_d(&a, 1, &a);
166       if (mp_is_square(&a, &n) != MP_OKAY) {
167 	 printf("fp:mp_is_square() error!\n");
168 	 return 1;
169       }
170       if (n == 1) {
171 	 printf("fp:mp_is_square() bad result!\n");
172 	 return 1;
173       }
174 
175    }
176    printf("\n\n");
177 
178    /* test for size */
179    for (ix = 10; ix < 128; ix++) {
180       printf("Testing (not safe-prime): %9d bits    \r", ix);
181       fflush(stdout);
182       err =
183 	 mp_prime_random_ex(&a, 8, ix,
184 			    (rand() & 1) ? LTM_PRIME_2MSB_OFF :
185 			    LTM_PRIME_2MSB_ON, myrng, NULL);
186       if (err != MP_OKAY) {
187 	 printf("failed with err code %d\n", err);
188 	 return EXIT_FAILURE;
189       }
190       if (mp_count_bits(&a) != ix) {
191 	 printf("Prime is %d not %d bits!!!\n", mp_count_bits(&a), ix);
192 	 return EXIT_FAILURE;
193       }
194    }
195 
196    for (ix = 16; ix < 128; ix++) {
197       printf("Testing (   safe-prime): %9d bits    \r", ix);
198       fflush(stdout);
199       err =
200 	 mp_prime_random_ex(&a, 8, ix,
201 			    ((rand() & 1) ? LTM_PRIME_2MSB_OFF :
202 			     LTM_PRIME_2MSB_ON) | LTM_PRIME_SAFE, myrng,
203 			    NULL);
204       if (err != MP_OKAY) {
205 	 printf("failed with err code %d\n", err);
206 	 return EXIT_FAILURE;
207       }
208       if (mp_count_bits(&a) != ix) {
209 	 printf("Prime is %d not %d bits!!!\n", mp_count_bits(&a), ix);
210 	 return EXIT_FAILURE;
211       }
212       /* let's see if it's really a safe prime */
213       mp_sub_d(&a, 1, &a);
214       mp_div_2(&a, &a);
215       mp_prime_is_prime(&a, 8, &cnt);
216       if (cnt != MP_YES) {
217 	 printf("sub is not prime!\n");
218 	 return EXIT_FAILURE;
219       }
220    }
221 
222    printf("\n\n");
223 
224    mp_read_radix(&a, "123456", 10);
225    mp_toradix_n(&a, buf, 10, 3);
226    printf("a == %s\n", buf);
227    mp_toradix_n(&a, buf, 10, 4);
228    printf("a == %s\n", buf);
229    mp_toradix_n(&a, buf, 10, 30);
230    printf("a == %s\n", buf);
231 
232 
233 #if 0
234    for (;;) {
235       fgets(buf, sizeof(buf), stdin);
236       mp_read_radix(&a, buf, 10);
237       mp_prime_next_prime(&a, 5, 1);
238       mp_toradix(&a, buf, 10);
239       printf("%s, %lu\n", buf, a.dp[0] & 3);
240    }
241 #endif
242 
243    /* test mp_cnt_lsb */
244    printf("testing mp_cnt_lsb...\n");
245    mp_set(&a, 1);
246    for (ix = 0; ix < 1024; ix++) {
247       if (mp_cnt_lsb(&a) != ix) {
248 	 printf("Failed at %d, %d\n", ix, mp_cnt_lsb(&a));
249 	 return 0;
250       }
251       mp_mul_2(&a, &a);
252    }
253 
254 /* test mp_reduce_2k */
255    printf("Testing mp_reduce_2k...\n");
256    for (cnt = 3; cnt <= 128; ++cnt) {
257       mp_digit tmp;
258 
259       mp_2expt(&a, cnt);
260       mp_sub_d(&a, 2, &a);	/* a = 2**cnt - 2 */
261 
262 
263       printf("\nTesting %4d bits", cnt);
264       printf("(%d)", mp_reduce_is_2k(&a));
265       mp_reduce_2k_setup(&a, &tmp);
266       printf("(%d)", tmp);
267       for (ix = 0; ix < 1000; ix++) {
268 	 if (!(ix & 127)) {
269 	    printf(".");
270 	    fflush(stdout);
271 	 }
272 	 mp_rand(&b, (cnt / DIGIT_BIT + 1) * 2);
273 	 mp_copy(&c, &b);
274 	 mp_mod(&c, &a, &c);
275 	 mp_reduce_2k(&b, &a, 2);
276 	 if (mp_cmp(&c, &b)) {
277 	    printf("FAILED\n");
278 	    exit(0);
279 	 }
280       }
281    }
282 
283 /* test mp_div_3  */
284    printf("Testing mp_div_3...\n");
285    mp_set(&d, 3);
286    for (cnt = 0; cnt < 10000;) {
287       mp_digit r1, r2;
288 
289       if (!(++cnt & 127))
290 	 printf("%9d\r", cnt);
291       mp_rand(&a, abs(rand()) % 128 + 1);
292       mp_div(&a, &d, &b, &e);
293       mp_div_3(&a, &c, &r2);
294 
295       if (mp_cmp(&b, &c) || mp_cmp_d(&e, r2)) {
296 	 printf("\n\nmp_div_3 => Failure\n");
297       }
298    }
299    printf("\n\nPassed div_3 testing\n");
300 
301 /* test the DR reduction */
302    printf("testing mp_dr_reduce...\n");
303    for (cnt = 2; cnt < 32; cnt++) {
304       printf("%d digit modulus\n", cnt);
305       mp_grow(&a, cnt);
306       mp_zero(&a);
307       for (ix = 1; ix < cnt; ix++) {
308 	 a.dp[ix] = MP_MASK;
309       }
310       a.used = cnt;
311       a.dp[0] = 3;
312 
313       mp_rand(&b, cnt - 1);
314       mp_copy(&b, &c);
315 
316       rr = 0;
317       do {
318 	 if (!(rr & 127)) {
319 	    printf("%9lu\r", rr);
320 	    fflush(stdout);
321 	 }
322 	 mp_sqr(&b, &b);
323 	 mp_add_d(&b, 1, &b);
324 	 mp_copy(&b, &c);
325 
326 	 mp_mod(&b, &a, &b);
327 	 mp_dr_reduce(&c, &a, (((mp_digit) 1) << DIGIT_BIT) - a.dp[0]);
328 
329 	 if (mp_cmp(&b, &c) != MP_EQ) {
330 	    printf("Failed on trial %lu\n", rr);
331 	    exit(-1);
332 
333 	 }
334       } while (++rr < 500);
335       printf("Passed DR test for %d digits\n", cnt);
336    }
337 
338 #endif
339 
340 /* test the mp_reduce_2k_l code */
341 #if 0
342 #if 0
343 /* first load P with 2^1024 - 0x2A434 B9FDEC95 D8F9D550 FFFFFFFF FFFFFFFF */
344    mp_2expt(&a, 1024);
345    mp_read_radix(&b, "2A434B9FDEC95D8F9D550FFFFFFFFFFFFFFFF", 16);
346    mp_sub(&a, &b, &a);
347 #elif 1
348 /*  p = 2^2048 - 0x1 00000000 00000000 00000000 00000000 4945DDBF 8EA2A91D 5776399B B83E188F  */
349    mp_2expt(&a, 2048);
350    mp_read_radix(&b,
351 		 "1000000000000000000000000000000004945DDBF8EA2A91D5776399BB83E188F",
352 		 16);
353    mp_sub(&a, &b, &a);
354 #endif
355 
356    mp_todecimal(&a, buf);
357    printf("p==%s\n", buf);
358 /* now mp_reduce_is_2k_l() should return */
359    if (mp_reduce_is_2k_l(&a) != 1) {
360       printf("mp_reduce_is_2k_l() return 0, should be 1\n");
361       return EXIT_FAILURE;
362    }
363    mp_reduce_2k_setup_l(&a, &d);
364    /* now do a million square+1 to see if it varies */
365    mp_rand(&b, 64);
366    mp_mod(&b, &a, &b);
367    mp_copy(&b, &c);
368    printf("testing mp_reduce_2k_l...");
369    fflush(stdout);
370    for (cnt = 0; cnt < (1UL << 20); cnt++) {
371       mp_sqr(&b, &b);
372       mp_add_d(&b, 1, &b);
373       mp_reduce_2k_l(&b, &a, &d);
374       mp_sqr(&c, &c);
375       mp_add_d(&c, 1, &c);
376       mp_mod(&c, &a, &c);
377       if (mp_cmp(&b, &c) != MP_EQ) {
378 	 printf("mp_reduce_2k_l() failed at step %lu\n", cnt);
379 	 mp_tohex(&b, buf);
380 	 printf("b == %s\n", buf);
381 	 mp_tohex(&c, buf);
382 	 printf("c == %s\n", buf);
383 	 return EXIT_FAILURE;
384       }
385    }
386    printf("...Passed\n");
387 #endif
388 
389    div2_n = mul2_n = inv_n = expt_n = lcm_n = gcd_n = add_n =
390       sub_n = mul_n = div_n = sqr_n = mul2d_n = div2d_n = cnt = add_d_n =
391       sub_d_n = 0;
392 
393    /* force KARA and TOOM to enable despite cutoffs */
394    KARATSUBA_SQR_CUTOFF = KARATSUBA_MUL_CUTOFF = 8;
395    TOOM_SQR_CUTOFF = TOOM_MUL_CUTOFF = 16;
396 
397    for (;;) {
398       /* randomly clear and re-init one variable, this has the affect of triming the alloc space */
399       switch (abs(rand()) % 7) {
400       case 0:
401 	 mp_clear(&a);
402 	 mp_init(&a);
403 	 break;
404       case 1:
405 	 mp_clear(&b);
406 	 mp_init(&b);
407 	 break;
408       case 2:
409 	 mp_clear(&c);
410 	 mp_init(&c);
411 	 break;
412       case 3:
413 	 mp_clear(&d);
414 	 mp_init(&d);
415 	 break;
416       case 4:
417 	 mp_clear(&e);
418 	 mp_init(&e);
419 	 break;
420       case 5:
421 	 mp_clear(&f);
422 	 mp_init(&f);
423 	 break;
424       case 6:
425 	 break;			/* don't clear any */
426       }
427 
428 
429       printf
430 	 ("%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu ",
431 	  add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n,
432 	  expt_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n);
433       fgets(cmd, 4095, stdin);
434       cmd[strlen(cmd) - 1] = 0;
435       printf("%s  ]\r", cmd);
436       fflush(stdout);
437       if (!strcmp(cmd, "mul2d")) {
438 	 ++mul2d_n;
439 	 fgets(buf, 4095, stdin);
440 	 mp_read_radix(&a, buf, 64);
441 	 fgets(buf, 4095, stdin);
442 	 sscanf(buf, "%d", &rr);
443 	 fgets(buf, 4095, stdin);
444 	 mp_read_radix(&b, buf, 64);
445 
446 	 mp_mul_2d(&a, rr, &a);
447 	 a.sign = b.sign;
448 	 if (mp_cmp(&a, &b) != MP_EQ) {
449 	    printf("mul2d failed, rr == %d\n", rr);
450 	    draw(&a);
451 	    draw(&b);
452 	    return 0;
453 	 }
454       } else if (!strcmp(cmd, "div2d")) {
455 	 ++div2d_n;
456 	 fgets(buf, 4095, stdin);
457 	 mp_read_radix(&a, buf, 64);
458 	 fgets(buf, 4095, stdin);
459 	 sscanf(buf, "%d", &rr);
460 	 fgets(buf, 4095, stdin);
461 	 mp_read_radix(&b, buf, 64);
462 
463 	 mp_div_2d(&a, rr, &a, &e);
464 	 a.sign = b.sign;
465 	 if (a.used == b.used && a.used == 0) {
466 	    a.sign = b.sign = MP_ZPOS;
467 	 }
468 	 if (mp_cmp(&a, &b) != MP_EQ) {
469 	    printf("div2d failed, rr == %d\n", rr);
470 	    draw(&a);
471 	    draw(&b);
472 	    return 0;
473 	 }
474       } else if (!strcmp(cmd, "add")) {
475 	 ++add_n;
476 	 fgets(buf, 4095, stdin);
477 	 mp_read_radix(&a, buf, 64);
478 	 fgets(buf, 4095, stdin);
479 	 mp_read_radix(&b, buf, 64);
480 	 fgets(buf, 4095, stdin);
481 	 mp_read_radix(&c, buf, 64);
482 	 mp_copy(&a, &d);
483 	 mp_add(&d, &b, &d);
484 	 if (mp_cmp(&c, &d) != MP_EQ) {
485 	    printf("add %lu failure!\n", add_n);
486 	    draw(&a);
487 	    draw(&b);
488 	    draw(&c);
489 	    draw(&d);
490 	    return 0;
491 	 }
492 
493 	 /* test the sign/unsigned storage functions */
494 
495 	 rr = mp_signed_bin_size(&c);
496 	 mp_to_signed_bin(&c, (unsigned char *) cmd);
497 	 memset(cmd + rr, rand() & 255, sizeof(cmd) - rr);
498 	 mp_read_signed_bin(&d, (unsigned char *) cmd, rr);
499 	 if (mp_cmp(&c, &d) != MP_EQ) {
500 	    printf("mp_signed_bin failure!\n");
501 	    draw(&c);
502 	    draw(&d);
503 	    return 0;
504 	 }
505 
506 
507 	 rr = mp_unsigned_bin_size(&c);
508 	 mp_to_unsigned_bin(&c, (unsigned char *) cmd);
509 	 memset(cmd + rr, rand() & 255, sizeof(cmd) - rr);
510 	 mp_read_unsigned_bin(&d, (unsigned char *) cmd, rr);
511 	 if (mp_cmp_mag(&c, &d) != MP_EQ) {
512 	    printf("mp_unsigned_bin failure!\n");
513 	    draw(&c);
514 	    draw(&d);
515 	    return 0;
516 	 }
517 
518       } else if (!strcmp(cmd, "sub")) {
519 	 ++sub_n;
520 	 fgets(buf, 4095, stdin);
521 	 mp_read_radix(&a, buf, 64);
522 	 fgets(buf, 4095, stdin);
523 	 mp_read_radix(&b, buf, 64);
524 	 fgets(buf, 4095, stdin);
525 	 mp_read_radix(&c, buf, 64);
526 	 mp_copy(&a, &d);
527 	 mp_sub(&d, &b, &d);
528 	 if (mp_cmp(&c, &d) != MP_EQ) {
529 	    printf("sub %lu failure!\n", sub_n);
530 	    draw(&a);
531 	    draw(&b);
532 	    draw(&c);
533 	    draw(&d);
534 	    return 0;
535 	 }
536       } else if (!strcmp(cmd, "mul")) {
537 	 ++mul_n;
538 	 fgets(buf, 4095, stdin);
539 	 mp_read_radix(&a, buf, 64);
540 	 fgets(buf, 4095, stdin);
541 	 mp_read_radix(&b, buf, 64);
542 	 fgets(buf, 4095, stdin);
543 	 mp_read_radix(&c, buf, 64);
544 	 mp_copy(&a, &d);
545 	 mp_mul(&d, &b, &d);
546 	 if (mp_cmp(&c, &d) != MP_EQ) {
547 	    printf("mul %lu failure!\n", mul_n);
548 	    draw(&a);
549 	    draw(&b);
550 	    draw(&c);
551 	    draw(&d);
552 	    return 0;
553 	 }
554       } else if (!strcmp(cmd, "div")) {
555 	 ++div_n;
556 	 fgets(buf, 4095, stdin);
557 	 mp_read_radix(&a, buf, 64);
558 	 fgets(buf, 4095, stdin);
559 	 mp_read_radix(&b, buf, 64);
560 	 fgets(buf, 4095, stdin);
561 	 mp_read_radix(&c, buf, 64);
562 	 fgets(buf, 4095, stdin);
563 	 mp_read_radix(&d, buf, 64);
564 
565 	 mp_div(&a, &b, &e, &f);
566 	 if (mp_cmp(&c, &e) != MP_EQ || mp_cmp(&d, &f) != MP_EQ) {
567 	    printf("div %lu %d, %d, failure!\n", div_n, mp_cmp(&c, &e),
568 		   mp_cmp(&d, &f));
569 	    draw(&a);
570 	    draw(&b);
571 	    draw(&c);
572 	    draw(&d);
573 	    draw(&e);
574 	    draw(&f);
575 	    return 0;
576 	 }
577 
578       } else if (!strcmp(cmd, "sqr")) {
579 	 ++sqr_n;
580 	 fgets(buf, 4095, stdin);
581 	 mp_read_radix(&a, buf, 64);
582 	 fgets(buf, 4095, stdin);
583 	 mp_read_radix(&b, buf, 64);
584 	 mp_copy(&a, &c);
585 	 mp_sqr(&c, &c);
586 	 if (mp_cmp(&b, &c) != MP_EQ) {
587 	    printf("sqr %lu failure!\n", sqr_n);
588 	    draw(&a);
589 	    draw(&b);
590 	    draw(&c);
591 	    return 0;
592 	 }
593       } else if (!strcmp(cmd, "gcd")) {
594 	 ++gcd_n;
595 	 fgets(buf, 4095, stdin);
596 	 mp_read_radix(&a, buf, 64);
597 	 fgets(buf, 4095, stdin);
598 	 mp_read_radix(&b, buf, 64);
599 	 fgets(buf, 4095, stdin);
600 	 mp_read_radix(&c, buf, 64);
601 	 mp_copy(&a, &d);
602 	 mp_gcd(&d, &b, &d);
603 	 d.sign = c.sign;
604 	 if (mp_cmp(&c, &d) != MP_EQ) {
605 	    printf("gcd %lu failure!\n", gcd_n);
606 	    draw(&a);
607 	    draw(&b);
608 	    draw(&c);
609 	    draw(&d);
610 	    return 0;
611 	 }
612       } else if (!strcmp(cmd, "lcm")) {
613 	 ++lcm_n;
614 	 fgets(buf, 4095, stdin);
615 	 mp_read_radix(&a, buf, 64);
616 	 fgets(buf, 4095, stdin);
617 	 mp_read_radix(&b, buf, 64);
618 	 fgets(buf, 4095, stdin);
619 	 mp_read_radix(&c, buf, 64);
620 	 mp_copy(&a, &d);
621 	 mp_lcm(&d, &b, &d);
622 	 d.sign = c.sign;
623 	 if (mp_cmp(&c, &d) != MP_EQ) {
624 	    printf("lcm %lu failure!\n", lcm_n);
625 	    draw(&a);
626 	    draw(&b);
627 	    draw(&c);
628 	    draw(&d);
629 	    return 0;
630 	 }
631       } else if (!strcmp(cmd, "expt")) {
632 	 ++expt_n;
633 	 fgets(buf, 4095, stdin);
634 	 mp_read_radix(&a, buf, 64);
635 	 fgets(buf, 4095, stdin);
636 	 mp_read_radix(&b, buf, 64);
637 	 fgets(buf, 4095, stdin);
638 	 mp_read_radix(&c, buf, 64);
639 	 fgets(buf, 4095, stdin);
640 	 mp_read_radix(&d, buf, 64);
641 	 mp_copy(&a, &e);
642 	 mp_exptmod(&e, &b, &c, &e);
643 	 if (mp_cmp(&d, &e) != MP_EQ) {
644 	    printf("expt %lu failure!\n", expt_n);
645 	    draw(&a);
646 	    draw(&b);
647 	    draw(&c);
648 	    draw(&d);
649 	    draw(&e);
650 	    return 0;
651 	 }
652       } else if (!strcmp(cmd, "invmod")) {
653 	 ++inv_n;
654 	 fgets(buf, 4095, stdin);
655 	 mp_read_radix(&a, buf, 64);
656 	 fgets(buf, 4095, stdin);
657 	 mp_read_radix(&b, buf, 64);
658 	 fgets(buf, 4095, stdin);
659 	 mp_read_radix(&c, buf, 64);
660 	 mp_invmod(&a, &b, &d);
661 	 mp_mulmod(&d, &a, &b, &e);
662 	 if (mp_cmp_d(&e, 1) != MP_EQ) {
663 	    printf("inv [wrong value from MPI?!] failure\n");
664 	    draw(&a);
665 	    draw(&b);
666 	    draw(&c);
667 	    draw(&d);
668 	    mp_gcd(&a, &b, &e);
669 	    draw(&e);
670 	    return 0;
671 	 }
672 
673       } else if (!strcmp(cmd, "div2")) {
674 	 ++div2_n;
675 	 fgets(buf, 4095, stdin);
676 	 mp_read_radix(&a, buf, 64);
677 	 fgets(buf, 4095, stdin);
678 	 mp_read_radix(&b, buf, 64);
679 	 mp_div_2(&a, &c);
680 	 if (mp_cmp(&c, &b) != MP_EQ) {
681 	    printf("div_2 %lu failure\n", div2_n);
682 	    draw(&a);
683 	    draw(&b);
684 	    draw(&c);
685 	    return 0;
686 	 }
687       } else if (!strcmp(cmd, "mul2")) {
688 	 ++mul2_n;
689 	 fgets(buf, 4095, stdin);
690 	 mp_read_radix(&a, buf, 64);
691 	 fgets(buf, 4095, stdin);
692 	 mp_read_radix(&b, buf, 64);
693 	 mp_mul_2(&a, &c);
694 	 if (mp_cmp(&c, &b) != MP_EQ) {
695 	    printf("mul_2 %lu failure\n", mul2_n);
696 	    draw(&a);
697 	    draw(&b);
698 	    draw(&c);
699 	    return 0;
700 	 }
701       } else if (!strcmp(cmd, "add_d")) {
702 	 ++add_d_n;
703 	 fgets(buf, 4095, stdin);
704 	 mp_read_radix(&a, buf, 64);
705 	 fgets(buf, 4095, stdin);
706 	 sscanf(buf, "%d", &ix);
707 	 fgets(buf, 4095, stdin);
708 	 mp_read_radix(&b, buf, 64);
709 	 mp_add_d(&a, ix, &c);
710 	 if (mp_cmp(&b, &c) != MP_EQ) {
711 	    printf("add_d %lu failure\n", add_d_n);
712 	    draw(&a);
713 	    draw(&b);
714 	    draw(&c);
715 	    printf("d == %d\n", ix);
716 	    return 0;
717 	 }
718       } else if (!strcmp(cmd, "sub_d")) {
719 	 ++sub_d_n;
720 	 fgets(buf, 4095, stdin);
721 	 mp_read_radix(&a, buf, 64);
722 	 fgets(buf, 4095, stdin);
723 	 sscanf(buf, "%d", &ix);
724 	 fgets(buf, 4095, stdin);
725 	 mp_read_radix(&b, buf, 64);
726 	 mp_sub_d(&a, ix, &c);
727 	 if (mp_cmp(&b, &c) != MP_EQ) {
728 	    printf("sub_d %lu failure\n", sub_d_n);
729 	    draw(&a);
730 	    draw(&b);
731 	    draw(&c);
732 	    printf("d == %d\n", ix);
733 	    return 0;
734 	 }
735       }
736    }
737    return 0;
738 }
739 
740 /* Source: /cvs/libtom/libtommath/demo/demo.c,v  */
741 /* Revision: 1.3  */
742 /* Date: 2005/06/24 11:32:07  */
743