/* * shifts with subtractions when the result is greater than b. * * The method is slightly modified to shift B unconditionally upto just under * the leading bit of b. This saves alot of multiple precision shifting. */ int mp_montgomery_calc_normalization (mp_int * a, mp_int * b) { int x, bits, res; /* how many bits of last digit does b use */ bits = mp_count_bits (b) % DIGIT_BIT; if (b->used > 1) { if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { return res; } } else { mp_set(a, 1); bits = 1; } /* now compute C = A * B mod b */ for (x = bits - 1; x < (int)DIGIT_BIT; x++) { if ((res = mp_mul_2 (a, a)) != MP_OKAY) { return res; } if (mp_cmp_mag (a, b) != MP_LT) { if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { return res; } } } return MP_OKAY; }
/** * Generate random number from range: (–2^numberOfBits, 2^numberOfBits>. * * @numberOfBits Number of bits this random integer will have * @return Random integer */ long int fhe_random(unsigned long long int numberOfBits) { mp_int *randomInteger; INIT_MP_INT(mask); mp_set(mask, 1); for (unsigned long long int i = 0; i < numberOfBits; i++) { mp_mul_2(mask, mask); } randomInteger = fhe_new_random_integer(numberOfBits + 1); mp_xor(randomInteger, mask, randomInteger); DESTROY_MP_INT(mask); // Note: need to cast from unsigned to signed return (long int)mp_get_int(randomInteger); }
/** * Generate a numberOfBits-bit long random integer. Note: The most-significant * bit will not be random: it will always be 1. The number of random bits * therefore is numberOfBits - 1. * * @return random number */ mp_int *fhe_new_random_integer(unsigned long long int numberOfBits) { #if defined(__linux__) int c; unsigned int bitmask; unsigned long int i; INIT_MP_INT(randomInteger); INIT_MP_INT(tmp1); /* The whole bytes */ for (bitmask = 0xff, i = numberOfBits; i > 0;) { if ((c = fgetc(randomFile)) == EOF) { perror("Error reading " RANDOM_FILE); exit(EXIT_FAILURE); } /* Ensure the most-significant bit of the random integer is always 1 */ if (i == numberOfBits) { assert(i > 0); c |= 0x1 << ((i < 8 ? i : 8) - 1); } if (i < 8) { // The last few bits will have a bitmask bitmask = 0xff >> (8 - i); } for (unsigned long int j = 0; j < i; j++) { mp_mul_2(randomInteger, randomInteger); } mp_set_int(tmp1, c & bitmask); mp_add(randomInteger, tmp1, randomInteger); /* Decrement; check for underflow */ if (i < 8) { break; } else { i -= 8; } }
/* multiplication using the Toom-Cook 3-way algorithm * * Much more complicated than Karatsuba but has a lower * asymptotic running time of O(N**1.464). This algorithm is * only particularly useful on VERY large inputs * (we're talking 1000s of digits here...). */ int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c) { mp_int w0, w1, w2, w3, w4, tmp1, tmp2, a0, a1, a2, b0, b1, b2; int res, B; /* init temps */ if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &b0, &b1, &b2, &tmp1, &tmp2, NULL)) != MP_OKAY) { return res; } /* B */ B = MIN(a->used, b->used) / 3; /* a = a2 * B**2 + a1 * B + a0 */ if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { goto ERR; } if ((res = mp_copy(a, &a1)) != MP_OKAY) { goto ERR; } mp_rshd(&a1, B); mp_mod_2d(&a1, DIGIT_BIT * B, &a1); if ((res = mp_copy(a, &a2)) != MP_OKAY) { goto ERR; } mp_rshd(&a2, B*2); /* b = b2 * B**2 + b1 * B + b0 */ if ((res = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) { goto ERR; } if ((res = mp_copy(b, &b1)) != MP_OKAY) { goto ERR; } mp_rshd(&b1, B); mp_mod_2d(&b1, DIGIT_BIT * B, &b1); if ((res = mp_copy(b, &b2)) != MP_OKAY) { goto ERR; } mp_rshd(&b2, B*2); /* w0 = a0*b0 */ if ((res = mp_mul(&a0, &b0, &w0)) != MP_OKAY) { goto ERR; } /* w4 = a2 * b2 */ if ((res = mp_mul(&a2, &b2, &w4)) != MP_OKAY) { goto ERR; } /* w1 = (a2 + 2(a1 + 2a0))(b2 + 2(b1 + 2b0)) */ if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_mul_2(&b0, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp2, &b2, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_mul(&tmp1, &tmp2, &w1)) != MP_OKAY) { goto ERR; } /* w3 = (a0 + 2(a1 + 2a2))(b0 + 2(b1 + 2b2)) */ if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_mul_2(&b2, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_mul(&tmp1, &tmp2, &w3)) != MP_OKAY) { goto ERR; } /* w2 = (a2 + a1 + a0)(b2 + b1 + b0) */ if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&b2, &b1, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_mul(&tmp1, &tmp2, &w2)) != MP_OKAY) { goto ERR; } /* now solve the matrix 0 0 0 0 1 1 2 4 8 16 1 1 1 1 1 16 8 4 2 1 1 0 0 0 0 using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication */ /* r1 - r4 */ if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { goto ERR; } /* r3 - r0 */ if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { goto ERR; } /* r1/2 */ if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { goto ERR; } /* r3/2 */ if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { goto ERR; } /* r2 - r0 - r4 */ if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { goto ERR; } if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { goto ERR; } /* r1 - r2 */ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { goto ERR; } /* r3 - r2 */ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { goto ERR; } /* r1 - 8r0 */ if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { goto ERR; } /* r3 - 8r4 */ if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { goto ERR; } /* 3r2 - r1 - r3 */ if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { goto ERR; } if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { goto ERR; } if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { goto ERR; } /* r1 - r2 */ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { goto ERR; } /* r3 - r2 */ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { goto ERR; } /* r1/3 */ if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { goto ERR; } /* r3/3 */ if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { goto ERR; } /* at this point shift W[n] by B*n */ if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { goto ERR; } if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { goto ERR; } if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { goto ERR; } if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&w0, &w1, c)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp1, c, c)) != MP_OKAY) { goto ERR; } ERR: mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &b0, &b1, &b2, &tmp1, &tmp2, NULL); return res; }
/* makes a prime of at least k bits */ int pprime (int k, int li, mp_int * p, mp_int * q) { mp_int a, b, c, n, x, y, z, v; int res, ii; static const mp_digit bases[] = { 2, 3, 5, 7, 11, 13, 17, 19 }; /* single digit ? */ if (k <= (int) DIGIT_BIT) { mp_set (p, prime_digit ()); return MP_OKAY; } if ((res = mp_init (&c)) != MP_OKAY) { return res; } if ((res = mp_init (&v)) != MP_OKAY) { goto LBL_C; } /* product of first 50 primes */ if ((res = mp_read_radix (&v, "19078266889580195013601891820992757757219839668357012055907516904309700014933909014729740190", 10)) != MP_OKAY) { goto LBL_V; } if ((res = mp_init (&a)) != MP_OKAY) { goto LBL_V; } /* set the prime */ mp_set (&a, prime_digit ()); if ((res = mp_init (&b)) != MP_OKAY) { goto LBL_A; } if ((res = mp_init (&n)) != MP_OKAY) { goto LBL_B; } if ((res = mp_init (&x)) != MP_OKAY) { goto LBL_N; } if ((res = mp_init (&y)) != MP_OKAY) { goto LBL_X; } if ((res = mp_init (&z)) != MP_OKAY) { goto LBL_Y; } /* now loop making the single digit */ while (mp_count_bits (&a) < k) { fprintf (stderr, "prime has %4d bits left\r", k - mp_count_bits (&a)); fflush (stderr); top: mp_set (&b, prime_digit ()); /* now compute z = a * b * 2 */ if ((res = mp_mul (&a, &b, &z)) != MP_OKAY) { /* z = a * b */ goto LBL_Z; } if ((res = mp_copy (&z, &c)) != MP_OKAY) { /* c = a * b */ goto LBL_Z; } if ((res = mp_mul_2 (&z, &z)) != MP_OKAY) { /* z = 2 * a * b */ goto LBL_Z; } /* n = z + 1 */ if ((res = mp_add_d (&z, 1, &n)) != MP_OKAY) { /* n = z + 1 */ goto LBL_Z; } /* check (n, v) == 1 */ if ((res = mp_gcd (&n, &v, &y)) != MP_OKAY) { /* y = (n, v) */ goto LBL_Z; } if (mp_cmp_d (&y, 1) != MP_EQ) goto top; /* now try base x=bases[ii] */ for (ii = 0; ii < li; ii++) { mp_set (&x, bases[ii]); /* compute x^a mod n */ if ((res = mp_exptmod (&x, &a, &n, &y)) != MP_OKAY) { /* y = x^a mod n */ goto LBL_Z; } /* if y == 1 loop */ if (mp_cmp_d (&y, 1) == MP_EQ) continue; /* now x^2a mod n */ if ((res = mp_sqrmod (&y, &n, &y)) != MP_OKAY) { /* y = x^2a mod n */ goto LBL_Z; } if (mp_cmp_d (&y, 1) == MP_EQ) continue; /* compute x^b mod n */ if ((res = mp_exptmod (&x, &b, &n, &y)) != MP_OKAY) { /* y = x^b mod n */ goto LBL_Z; } /* if y == 1 loop */ if (mp_cmp_d (&y, 1) == MP_EQ) continue; /* now x^2b mod n */ if ((res = mp_sqrmod (&y, &n, &y)) != MP_OKAY) { /* y = x^2b mod n */ goto LBL_Z; } if (mp_cmp_d (&y, 1) == MP_EQ) continue; /* compute x^c mod n == x^ab mod n */ if ((res = mp_exptmod (&x, &c, &n, &y)) != MP_OKAY) { /* y = x^ab mod n */ goto LBL_Z; } /* if y == 1 loop */ if (mp_cmp_d (&y, 1) == MP_EQ) continue; /* now compute (x^c mod n)^2 */ if ((res = mp_sqrmod (&y, &n, &y)) != MP_OKAY) { /* y = x^2ab mod n */ goto LBL_Z; } /* y should be 1 */ if (mp_cmp_d (&y, 1) != MP_EQ) continue; break; } /* no bases worked? */ if (ii == li) goto top; { char buf[4096]; mp_toradix(&n, buf, 10); printf("Certificate of primality for:\n%s\n\n", buf); mp_toradix(&a, buf, 10); printf("A == \n%s\n\n", buf); mp_toradix(&b, buf, 10); printf("B == \n%s\n\nG == %d\n", buf, bases[ii]); printf("----------------------------------------------------------------\n"); } /* a = n */ mp_copy (&n, &a); } /* get q to be the order of the large prime subgroup */ mp_sub_d (&n, 1, q); mp_div_2 (q, q); mp_div (q, &b, q, NULL); mp_exch (&n, p); res = MP_OKAY; LBL_Z:mp_clear (&z); LBL_Y:mp_clear (&y); LBL_X:mp_clear (&x); LBL_N:mp_clear (&n); LBL_B:mp_clear (&b); LBL_A:mp_clear (&a); LBL_V:mp_clear (&v); LBL_C:mp_clear (&c); return res; }
int main(int argc, char *argv[]) { int n, tmp; long long max; mp_int a, b, c, d, e; #ifdef MTEST_NO_FULLSPEED clock_t t1; #endif char buf[4096]; mp_init(&a); mp_init(&b); mp_init(&c); mp_init(&d); mp_init(&e); if (argc > 1) { max = strtol(argv[1], NULL, 0); if (max < 0) { if (max > -64) { max = (1 << -(max)) + 1; } else { max = 1; } } else if (max == 0) { max = 1; } } else { max = 0; } /* initial (2^n - 1)^2 testing, makes sure the comba multiplier works [it has the new carry code] */ /* mp_set(&a, 1); for (n = 1; n < 8192; n++) { mp_mul(&a, &a, &c); printf("mul\n"); mp_to64(&a, buf); printf("%s\n%s\n", buf, buf); mp_to64(&c, buf); printf("%s\n", buf); mp_add_d(&a, 1, &a); mp_mul_2(&a, &a); mp_sub_d(&a, 1, &a); } */ #ifdef LTM_MTEST_REAL_RAND rng = fopen("/dev/urandom", "rb"); if (rng == NULL) { rng = fopen("/dev/random", "rb"); if (rng == NULL) { fprintf(stderr, "\nWarning: stdin used as random source\n\n"); rng = stdin; } } #else srand(23); #endif #ifdef MTEST_NO_FULLSPEED t1 = clock(); #endif for (;;) { #ifdef MTEST_NO_FULLSPEED if (clock() - t1 > CLOCKS_PER_SEC) { sleep(2); t1 = clock(); } #endif n = getRandChar() % 15; if (max != 0) { --max; if (max == 0) n = 255; } if (n == 0) { /* add tests */ rand_num(&a); rand_num(&b); mp_add(&a, &b, &c); printf("add\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 1) { /* sub tests */ rand_num(&a); rand_num(&b); mp_sub(&a, &b, &c); printf("sub\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 2) { /* mul tests */ rand_num(&a); rand_num(&b); mp_mul(&a, &b, &c); printf("mul\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 3) { /* div tests */ rand_num(&a); rand_num(&b); mp_div(&a, &b, &c, &d); printf("div\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); mp_to64(&d, buf); printf("%s\n", buf); } else if (n == 4) { /* sqr tests */ rand_num(&a); mp_sqr(&a, &b); printf("sqr\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 5) { /* mul_2d test */ rand_num(&a); mp_copy(&a, &b); n = getRandChar() & 63; mp_mul_2d(&b, n, &b); mp_to64(&a, buf); printf("mul2d\n"); printf("%s\n", buf); printf("%d\n", n); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 6) { /* div_2d test */ rand_num(&a); mp_copy(&a, &b); n = getRandChar() & 63; mp_div_2d(&b, n, &b, NULL); mp_to64(&a, buf); printf("div2d\n"); printf("%s\n", buf); printf("%d\n", n); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 7) { /* gcd test */ rand_num(&a); rand_num(&b); a.sign = MP_ZPOS; b.sign = MP_ZPOS; mp_gcd(&a, &b, &c); printf("gcd\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 8) { /* lcm test */ rand_num(&a); rand_num(&b); a.sign = MP_ZPOS; b.sign = MP_ZPOS; mp_lcm(&a, &b, &c); printf("lcm\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 9) { /* exptmod test */ rand_num2(&a); rand_num2(&b); rand_num2(&c); // if (c.dp[0]&1) mp_add_d(&c, 1, &c); a.sign = b.sign = c.sign = 0; mp_exptmod(&a, &b, &c, &d); printf("expt\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); mp_to64(&d, buf); printf("%s\n", buf); } else if (n == 10) { /* invmod test */ do { rand_num2(&a); rand_num2(&b); b.sign = MP_ZPOS; a.sign = MP_ZPOS; mp_gcd(&a, &b, &c); } while (mp_cmp_d(&c, 1) != 0 || mp_cmp_d(&b, 1) == 0); mp_invmod(&a, &b, &c); printf("invmod\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 11) { rand_num(&a); mp_mul_2(&a, &a); mp_div_2(&a, &b); printf("div2\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 12) { rand_num2(&a); mp_mul_2(&a, &b); printf("mul2\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 13) { rand_num2(&a); tmp = abs(rand()) & THE_MASK; mp_add_d(&a, tmp, &b); printf("add_d\n"); mp_to64(&a, buf); printf("%s\n%d\n", buf, tmp); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 14) { rand_num2(&a); tmp = abs(rand()) & THE_MASK; mp_sub_d(&a, tmp, &b); printf("sub_d\n"); mp_to64(&a, buf); printf("%s\n%d\n", buf, tmp); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 255) { printf("exit\n"); break; } } #ifdef LTM_MTEST_REAL_RAND fclose(rng); #endif return 0; }
mp_err mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong, unsigned long * nTries) { mp_digit np; mp_err res; int i = 0; mp_int trial; mp_int q; mp_size num_tests; unsigned char *sieve; ARGCHK(start != 0, MP_BADARG); ARGCHK(nBits > 16, MP_RANGE); sieve = malloc(SIEVE_SIZE); ARGCHK(sieve != NULL, MP_MEM); MP_DIGITS(&trial) = 0; MP_DIGITS(&q) = 0; MP_CHECKOK( mp_init(&trial) ); MP_CHECKOK( mp_init(&q) ); /* values taken from table 4.4, HandBook of Applied Cryptography */ if (nBits >= 1300) { num_tests = 2; } else if (nBits >= 850) { num_tests = 3; } else if (nBits >= 650) { num_tests = 4; } else if (nBits >= 550) { num_tests = 5; } else if (nBits >= 450) { num_tests = 6; } else if (nBits >= 400) { num_tests = 7; } else if (nBits >= 350) { num_tests = 8; } else if (nBits >= 300) { num_tests = 9; } else if (nBits >= 250) { num_tests = 12; } else if (nBits >= 200) { num_tests = 15; } else if (nBits >= 150) { num_tests = 18; } else if (nBits >= 100) { num_tests = 27; } else num_tests = 50; if (strong) --nBits; MP_CHECKOK( mpl_set_bit(start, nBits - 1, 1) ); MP_CHECKOK( mpl_set_bit(start, 0, 1) ); for (i = mpl_significant_bits(start) - 1; i >= nBits; --i) { MP_CHECKOK( mpl_set_bit(start, i, 0) ); } /* start sieveing with prime value of 3. */ MP_CHECKOK(mpp_sieve(start, prime_tab + 1, prime_tab_size - 1, sieve, SIEVE_SIZE) ); #ifdef DEBUG_SIEVE res = 0; for (i = 0; i < SIEVE_SIZE; ++i) { if (!sieve[i]) ++res; } fprintf(stderr,"sieve found %d potential primes.\n", res); #define FPUTC(x,y) fputc(x,y) #else #define FPUTC(x,y) #endif res = MP_NO; for(i = 0; i < SIEVE_SIZE; ++i) { if (sieve[i]) /* this number is composite */ continue; MP_CHECKOK( mp_add_d(start, 2 * i, &trial) ); FPUTC('.', stderr); /* run a Fermat test */ res = mpp_fermat(&trial, 2); if (res != MP_OKAY) { if (res == MP_NO) continue; /* was composite */ goto CLEANUP; } FPUTC('+', stderr); /* If that passed, run some Miller-Rabin tests */ res = mpp_pprime(&trial, num_tests); if (res != MP_OKAY) { if (res == MP_NO) continue; /* was composite */ goto CLEANUP; } FPUTC('!', stderr); if (!strong) break; /* success !! */ /* At this point, we have strong evidence that our candidate is itself prime. If we want a strong prime, we need now to test q = 2p + 1 for primality... */ MP_CHECKOK( mp_mul_2(&trial, &q) ); MP_CHECKOK( mp_add_d(&q, 1, &q) ); /* Test q for small prime divisors ... */ np = prime_tab_size; res = mpp_divis_primes(&q, &np); if (res == MP_YES) { /* is composite */ mp_clear(&q); continue; } if (res != MP_NO) goto CLEANUP; /* And test with Fermat, as with its parent ... */ res = mpp_fermat(&q, 2); if (res != MP_YES) { mp_clear(&q); if (res == MP_NO) continue; /* was composite */ goto CLEANUP; } /* And test with Miller-Rabin, as with its parent ... */ res = mpp_pprime(&q, num_tests); if (res != MP_YES) { mp_clear(&q); if (res == MP_NO) continue; /* was composite */ goto CLEANUP; } /* If it passed, we've got a winner */ mp_exch(&q, &trial); mp_clear(&q); break; } /* end of loop through sieved values */ if (res == MP_YES) mp_exch(&trial, start); CLEANUP: mp_clear(&trial); mp_clear(&q); if (nTries) *nTries += i; if (sieve != NULL) { memset(sieve, 0, SIEVE_SIZE); free (sieve); } return res; }
int main(void) { mp_int a, b, c, d, e, f; unsigned long expt_n, add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n, t; unsigned rr; int i, n, err, cnt, ix, old_kara_m, old_kara_s; mp_digit mp; mp_init(&a); mp_init(&b); mp_init(&c); mp_init(&d); mp_init(&e); mp_init(&f); srand(time(NULL)); #if 0 // test montgomery printf("Testing montgomery...\n"); for (i = 1; i < 10; i++) { printf("Testing digit size: %d\n", i); for (n = 0; n < 1000; n++) { mp_rand(&a, i); a.dp[0] |= 1; // let's see if R is right mp_montgomery_calc_normalization(&b, &a); mp_montgomery_setup(&a, &mp); // now test a random reduction for (ix = 0; ix < 100; ix++) { mp_rand(&c, 1 + abs(rand()) % (2*i)); mp_copy(&c, &d); mp_copy(&c, &e); mp_mod(&d, &a, &d); mp_montgomery_reduce(&c, &a, mp); mp_mulmod(&c, &b, &a, &c); if (mp_cmp(&c, &d) != MP_EQ) { printf("d = e mod a, c = e MOD a\n"); mp_todecimal(&a, buf); printf("a = %s\n", buf); mp_todecimal(&e, buf); printf("e = %s\n", buf); mp_todecimal(&d, buf); printf("d = %s\n", buf); mp_todecimal(&c, buf); printf("c = %s\n", buf); printf("compare no compare!\n"); exit(EXIT_FAILURE); } } } } printf("done\n"); // test mp_get_int printf("Testing: mp_get_int\n"); for (i = 0; i < 1000; ++i) { t = ((unsigned long) rand() * rand() + 1) & 0xFFFFFFFF; mp_set_int(&a, t); if (t != mp_get_int(&a)) { printf("mp_get_int() bad result!\n"); return 1; } } mp_set_int(&a, 0); if (mp_get_int(&a) != 0) { printf("mp_get_int() bad result!\n"); return 1; } mp_set_int(&a, 0xffffffff); if (mp_get_int(&a) != 0xffffffff) { printf("mp_get_int() bad result!\n"); return 1; } // test mp_sqrt printf("Testing: mp_sqrt\n"); for (i = 0; i < 1000; ++i) { printf("%6d\r", i); fflush(stdout); n = (rand() & 15) + 1; mp_rand(&a, n); if (mp_sqrt(&a, &b) != MP_OKAY) { printf("mp_sqrt() error!\n"); return 1; } mp_n_root(&a, 2, &a); if (mp_cmp_mag(&b, &a) != MP_EQ) { printf("mp_sqrt() bad result!\n"); return 1; } } printf("\nTesting: mp_is_square\n"); for (i = 0; i < 1000; ++i) { printf("%6d\r", i); fflush(stdout); /* test mp_is_square false negatives */ n = (rand() & 7) + 1; mp_rand(&a, n); mp_sqr(&a, &a); if (mp_is_square(&a, &n) != MP_OKAY) { printf("fn:mp_is_square() error!\n"); return 1; } if (n == 0) { printf("fn:mp_is_square() bad result!\n"); return 1; } /* test for false positives */ mp_add_d(&a, 1, &a); if (mp_is_square(&a, &n) != MP_OKAY) { printf("fp:mp_is_square() error!\n"); return 1; } if (n == 1) { printf("fp:mp_is_square() bad result!\n"); return 1; } } printf("\n\n"); /* test for size */ for (ix = 10; ix < 128; ix++) { printf("Testing (not safe-prime): %9d bits \r", ix); fflush(stdout); err = mp_prime_random_ex(&a, 8, ix, (rand() & 1) ? LTM_PRIME_2MSB_OFF : LTM_PRIME_2MSB_ON, myrng, NULL); if (err != MP_OKAY) { printf("failed with err code %d\n", err); return EXIT_FAILURE; } if (mp_count_bits(&a) != ix) { printf("Prime is %d not %d bits!!!\n", mp_count_bits(&a), ix); return EXIT_FAILURE; } } for (ix = 16; ix < 128; ix++) { printf("Testing ( safe-prime): %9d bits \r", ix); fflush(stdout); err = mp_prime_random_ex(&a, 8, ix, ((rand() & 1) ? LTM_PRIME_2MSB_OFF : LTM_PRIME_2MSB_ON) | LTM_PRIME_SAFE, myrng, NULL); if (err != MP_OKAY) { printf("failed with err code %d\n", err); return EXIT_FAILURE; } if (mp_count_bits(&a) != ix) { printf("Prime is %d not %d bits!!!\n", mp_count_bits(&a), ix); return EXIT_FAILURE; } /* let's see if it's really a safe prime */ mp_sub_d(&a, 1, &a); mp_div_2(&a, &a); mp_prime_is_prime(&a, 8, &cnt); if (cnt != MP_YES) { printf("sub is not prime!\n"); return EXIT_FAILURE; } } printf("\n\n"); mp_read_radix(&a, "123456", 10); mp_toradix_n(&a, buf, 10, 3); printf("a == %s\n", buf); mp_toradix_n(&a, buf, 10, 4); printf("a == %s\n", buf); mp_toradix_n(&a, buf, 10, 30); printf("a == %s\n", buf); #if 0 for (;;) { fgets(buf, sizeof(buf), stdin); mp_read_radix(&a, buf, 10); mp_prime_next_prime(&a, 5, 1); mp_toradix(&a, buf, 10); printf("%s, %lu\n", buf, a.dp[0] & 3); } #endif /* test mp_cnt_lsb */ printf("testing mp_cnt_lsb...\n"); mp_set(&a, 1); for (ix = 0; ix < 1024; ix++) { if (mp_cnt_lsb(&a) != ix) { printf("Failed at %d, %d\n", ix, mp_cnt_lsb(&a)); return 0; } mp_mul_2(&a, &a); } /* test mp_reduce_2k */ printf("Testing mp_reduce_2k...\n"); for (cnt = 3; cnt <= 128; ++cnt) { mp_digit tmp; mp_2expt(&a, cnt); mp_sub_d(&a, 2, &a); /* a = 2**cnt - 2 */ printf("\nTesting %4d bits", cnt); printf("(%d)", mp_reduce_is_2k(&a)); mp_reduce_2k_setup(&a, &tmp); printf("(%d)", tmp); for (ix = 0; ix < 1000; ix++) { if (!(ix & 127)) { printf("."); fflush(stdout); } mp_rand(&b, (cnt / DIGIT_BIT + 1) * 2); mp_copy(&c, &b); mp_mod(&c, &a, &c); mp_reduce_2k(&b, &a, 2); if (mp_cmp(&c, &b)) { printf("FAILED\n"); exit(0); } } } /* test mp_div_3 */ printf("Testing mp_div_3...\n"); mp_set(&d, 3); for (cnt = 0; cnt < 10000;) { mp_digit r1, r2; if (!(++cnt & 127)) printf("%9d\r", cnt); mp_rand(&a, abs(rand()) % 128 + 1); mp_div(&a, &d, &b, &e); mp_div_3(&a, &c, &r2); if (mp_cmp(&b, &c) || mp_cmp_d(&e, r2)) { printf("\n\nmp_div_3 => Failure\n"); } } printf("\n\nPassed div_3 testing\n"); /* test the DR reduction */ printf("testing mp_dr_reduce...\n"); for (cnt = 2; cnt < 32; cnt++) { printf("%d digit modulus\n", cnt); mp_grow(&a, cnt); mp_zero(&a); for (ix = 1; ix < cnt; ix++) { a.dp[ix] = MP_MASK; } a.used = cnt; a.dp[0] = 3; mp_rand(&b, cnt - 1); mp_copy(&b, &c); rr = 0; do { if (!(rr & 127)) { printf("%9lu\r", rr); fflush(stdout); } mp_sqr(&b, &b); mp_add_d(&b, 1, &b); mp_copy(&b, &c); mp_mod(&b, &a, &b); mp_dr_reduce(&c, &a, (((mp_digit) 1) << DIGIT_BIT) - a.dp[0]); if (mp_cmp(&b, &c) != MP_EQ) { printf("Failed on trial %lu\n", rr); exit(-1); } } while (++rr < 500); printf("Passed DR test for %d digits\n", cnt); } #endif /* test the mp_reduce_2k_l code */ #if 0 #if 0 /* first load P with 2^1024 - 0x2A434 B9FDEC95 D8F9D550 FFFFFFFF FFFFFFFF */ mp_2expt(&a, 1024); mp_read_radix(&b, "2A434B9FDEC95D8F9D550FFFFFFFFFFFFFFFF", 16); mp_sub(&a, &b, &a); #elif 1 /* p = 2^2048 - 0x1 00000000 00000000 00000000 00000000 4945DDBF 8EA2A91D 5776399B B83E188F */ mp_2expt(&a, 2048); mp_read_radix(&b, "1000000000000000000000000000000004945DDBF8EA2A91D5776399BB83E188F", 16); mp_sub(&a, &b, &a); #endif mp_todecimal(&a, buf); printf("p==%s\n", buf); /* now mp_reduce_is_2k_l() should return */ if (mp_reduce_is_2k_l(&a) != 1) { printf("mp_reduce_is_2k_l() return 0, should be 1\n"); return EXIT_FAILURE; } mp_reduce_2k_setup_l(&a, &d); /* now do a million square+1 to see if it varies */ mp_rand(&b, 64); mp_mod(&b, &a, &b); mp_copy(&b, &c); printf("testing mp_reduce_2k_l..."); fflush(stdout); for (cnt = 0; cnt < (1UL << 20); cnt++) { mp_sqr(&b, &b); mp_add_d(&b, 1, &b); mp_reduce_2k_l(&b, &a, &d); mp_sqr(&c, &c); mp_add_d(&c, 1, &c); mp_mod(&c, &a, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("mp_reduce_2k_l() failed at step %lu\n", cnt); mp_tohex(&b, buf); printf("b == %s\n", buf); mp_tohex(&c, buf); printf("c == %s\n", buf); return EXIT_FAILURE; } } printf("...Passed\n"); #endif div2_n = mul2_n = inv_n = expt_n = lcm_n = gcd_n = add_n = sub_n = mul_n = div_n = sqr_n = mul2d_n = div2d_n = cnt = add_d_n = sub_d_n = 0; /* force KARA and TOOM to enable despite cutoffs */ KARATSUBA_SQR_CUTOFF = KARATSUBA_MUL_CUTOFF = 8; TOOM_SQR_CUTOFF = TOOM_MUL_CUTOFF = 16; for (;;) { /* randomly clear and re-init one variable, this has the affect of triming the alloc space */ switch (abs(rand()) % 7) { case 0: mp_clear(&a); mp_init(&a); break; case 1: mp_clear(&b); mp_init(&b); break; case 2: mp_clear(&c); mp_init(&c); break; case 3: mp_clear(&d); mp_init(&d); break; case 4: mp_clear(&e); mp_init(&e); break; case 5: mp_clear(&f); mp_init(&f); break; case 6: break; /* don't clear any */ } printf ("%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu ", add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, expt_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n); fgets(cmd, 4095, stdin); cmd[strlen(cmd) - 1] = 0; printf("%s ]\r", cmd); fflush(stdout); if (!strcmp(cmd, "mul2d")) { ++mul2d_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); sscanf(buf, "%d", &rr); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_mul_2d(&a, rr, &a); a.sign = b.sign; if (mp_cmp(&a, &b) != MP_EQ) { printf("mul2d failed, rr == %d\n", rr); draw(&a); draw(&b); return 0; } } else if (!strcmp(cmd, "div2d")) { ++div2d_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); sscanf(buf, "%d", &rr); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_div_2d(&a, rr, &a, &e); a.sign = b.sign; if (a.used == b.used && a.used == 0) { a.sign = b.sign = MP_ZPOS; } if (mp_cmp(&a, &b) != MP_EQ) { printf("div2d failed, rr == %d\n", rr); draw(&a); draw(&b); return 0; } } else if (!strcmp(cmd, "add")) { ++add_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_add(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { printf("add %lu failure!\n", add_n); draw(&a); draw(&b); draw(&c); draw(&d); return 0; } /* test the sign/unsigned storage functions */ rr = mp_signed_bin_size(&c); mp_to_signed_bin(&c, (unsigned char *) cmd); memset(cmd + rr, rand() & 255, sizeof(cmd) - rr); mp_read_signed_bin(&d, (unsigned char *) cmd, rr); if (mp_cmp(&c, &d) != MP_EQ) { printf("mp_signed_bin failure!\n"); draw(&c); draw(&d); return 0; } rr = mp_unsigned_bin_size(&c); mp_to_unsigned_bin(&c, (unsigned char *) cmd); memset(cmd + rr, rand() & 255, sizeof(cmd) - rr); mp_read_unsigned_bin(&d, (unsigned char *) cmd, rr); if (mp_cmp_mag(&c, &d) != MP_EQ) { printf("mp_unsigned_bin failure!\n"); draw(&c); draw(&d); return 0; } } else if (!strcmp(cmd, "sub")) { ++sub_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_sub(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { printf("sub %lu failure!\n", sub_n); draw(&a); draw(&b); draw(&c); draw(&d); return 0; } } else if (!strcmp(cmd, "mul")) { ++mul_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_mul(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { printf("mul %lu failure!\n", mul_n); draw(&a); draw(&b); draw(&c); draw(&d); return 0; } } else if (!strcmp(cmd, "div")) { ++div_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&d, buf, 64); mp_div(&a, &b, &e, &f); if (mp_cmp(&c, &e) != MP_EQ || mp_cmp(&d, &f) != MP_EQ) { printf("div %lu %d, %d, failure!\n", div_n, mp_cmp(&c, &e), mp_cmp(&d, &f)); draw(&a); draw(&b); draw(&c); draw(&d); draw(&e); draw(&f); return 0; } } else if (!strcmp(cmd, "sqr")) { ++sqr_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_copy(&a, &c); mp_sqr(&c, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("sqr %lu failure!\n", sqr_n); draw(&a); draw(&b); draw(&c); return 0; } } else if (!strcmp(cmd, "gcd")) { ++gcd_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_gcd(&d, &b, &d); d.sign = c.sign; if (mp_cmp(&c, &d) != MP_EQ) { printf("gcd %lu failure!\n", gcd_n); draw(&a); draw(&b); draw(&c); draw(&d); return 0; } } else if (!strcmp(cmd, "lcm")) { ++lcm_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_lcm(&d, &b, &d); d.sign = c.sign; if (mp_cmp(&c, &d) != MP_EQ) { printf("lcm %lu failure!\n", lcm_n); draw(&a); draw(&b); draw(&c); draw(&d); return 0; } } else if (!strcmp(cmd, "expt")) { ++expt_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&d, buf, 64); mp_copy(&a, &e); mp_exptmod(&e, &b, &c, &e); if (mp_cmp(&d, &e) != MP_EQ) { printf("expt %lu failure!\n", expt_n); draw(&a); draw(&b); draw(&c); draw(&d); draw(&e); return 0; } } else if (!strcmp(cmd, "invmod")) { ++inv_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_invmod(&a, &b, &d); mp_mulmod(&d, &a, &b, &e); if (mp_cmp_d(&e, 1) != MP_EQ) { printf("inv [wrong value from MPI?!] failure\n"); draw(&a); draw(&b); draw(&c); draw(&d); mp_gcd(&a, &b, &e); draw(&e); return 0; } } else if (!strcmp(cmd, "div2")) { ++div2_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_div_2(&a, &c); if (mp_cmp(&c, &b) != MP_EQ) { printf("div_2 %lu failure\n", div2_n); draw(&a); draw(&b); draw(&c); return 0; } } else if (!strcmp(cmd, "mul2")) { ++mul2_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_mul_2(&a, &c); if (mp_cmp(&c, &b) != MP_EQ) { printf("mul_2 %lu failure\n", mul2_n); draw(&a); draw(&b); draw(&c); return 0; } } else if (!strcmp(cmd, "add_d")) { ++add_d_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); sscanf(buf, "%d", &ix); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_add_d(&a, ix, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("add_d %lu failure\n", add_d_n); draw(&a); draw(&b); draw(&c); printf("d == %d\n", ix); return 0; } } else if (!strcmp(cmd, "sub_d")) { ++sub_d_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); sscanf(buf, "%d", &ix); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_sub_d(&a, ix, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("sub_d %lu failure\n", sub_d_n); draw(&a); draw(&b); draw(&c); printf("d == %d\n", ix); return 0; } } } return 0; }
int main(void) { ulong64 tt, gg, CLK_PER_SEC; FILE *log, *logb, *logc, *logd; mp_int a, b, c, d, e, f; int n, cnt, ix, old_kara_m, old_kara_s; unsigned rr; mp_init(&a); mp_init(&b); mp_init(&c); mp_init(&d); mp_init(&e); mp_init(&f); srand(time(NULL)); /* temp. turn off TOOM */ TOOM_MUL_CUTOFF = TOOM_SQR_CUTOFF = 100000; CLK_PER_SEC = TIMFUNC(); sleep(1); CLK_PER_SEC = TIMFUNC() - CLK_PER_SEC; printf("CLK_PER_SEC == %llu\n", CLK_PER_SEC); goto exptmod; log = fopen("logs/add.log", "w"); for (cnt = 8; cnt <= 128; cnt += 8) { SLEEP; mp_rand(&a, cnt); mp_rand(&b, cnt); rr = 0; tt = -1; do { gg = TIMFUNC(); DO(mp_add(&a, &b, &c)); gg = (TIMFUNC() - gg) >> 1; if (tt > gg) tt = gg; } while (++rr < 100000); printf("Adding\t\t%4d-bit => %9llu/sec, %9llu cycles\n", mp_count_bits(&a), CLK_PER_SEC / tt, tt); fprintf(log, "%d %9llu\n", cnt * DIGIT_BIT, tt); fflush(log); } fclose(log); log = fopen("logs/sub.log", "w"); for (cnt = 8; cnt <= 128; cnt += 8) { SLEEP; mp_rand(&a, cnt); mp_rand(&b, cnt); rr = 0; tt = -1; do { gg = TIMFUNC(); DO(mp_sub(&a, &b, &c)); gg = (TIMFUNC() - gg) >> 1; if (tt > gg) tt = gg; } while (++rr < 100000); printf("Subtracting\t\t%4d-bit => %9llu/sec, %9llu cycles\n", mp_count_bits(&a), CLK_PER_SEC / tt, tt); fprintf(log, "%d %9llu\n", cnt * DIGIT_BIT, tt); fflush(log); } fclose(log); /* do mult/square twice, first without karatsuba and second with */ multtest: old_kara_m = KARATSUBA_MUL_CUTOFF; old_kara_s = KARATSUBA_SQR_CUTOFF; for (ix = 0; ix < 2; ix++) { printf("With%s Karatsuba\n", (ix == 0) ? "out" : ""); KARATSUBA_MUL_CUTOFF = (ix == 0) ? 9999 : old_kara_m; KARATSUBA_SQR_CUTOFF = (ix == 0) ? 9999 : old_kara_s; log = fopen((ix == 0) ? "logs/mult.log" : "logs/mult_kara.log", "w"); for (cnt = 4; cnt <= 10240 / DIGIT_BIT; cnt += 2) { SLEEP; mp_rand(&a, cnt); mp_rand(&b, cnt); rr = 0; tt = -1; do { gg = TIMFUNC(); DO(mp_mul(&a, &b, &c)); gg = (TIMFUNC() - gg) >> 1; if (tt > gg) tt = gg; } while (++rr < 100); printf("Multiplying\t%4d-bit => %9llu/sec, %9llu cycles\n", mp_count_bits(&a), CLK_PER_SEC / tt, tt); fprintf(log, "%d %9llu\n", mp_count_bits(&a), tt); fflush(log); } fclose(log); log = fopen((ix == 0) ? "logs/sqr.log" : "logs/sqr_kara.log", "w"); for (cnt = 4; cnt <= 10240 / DIGIT_BIT; cnt += 2) { SLEEP; mp_rand(&a, cnt); rr = 0; tt = -1; do { gg = TIMFUNC(); DO(mp_sqr(&a, &b)); gg = (TIMFUNC() - gg) >> 1; if (tt > gg) tt = gg; } while (++rr < 100); printf("Squaring\t%4d-bit => %9llu/sec, %9llu cycles\n", mp_count_bits(&a), CLK_PER_SEC / tt, tt); fprintf(log, "%d %9llu\n", mp_count_bits(&a), tt); fflush(log); } fclose(log); } exptmod: { char *primes[] = { /* 2K large moduli */ "179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586239334100047359817950870678242457666208137217", "32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638099733077152121140120031150424541696791951097529546801429027668869927491725169", "1044388881413152506691752710716624382579964249047383780384233483283953907971557456848826811934997558340890106714439262837987573438185793607263236087851365277945956976543709998340361590134383718314428070011855946226376318839397712745672334684344586617496807908705803704071284048740118609114467977783598029006686938976881787785946905630190260940599579453432823469303026696443059025015972399867714215541693835559885291486318237914434496734087811872639496475100189041349008417061675093668333850551032972088269550769983616369411933015213796825837188091833656751221318492846368125550225998300412344784862595674492194617023806505913245610825731835380087608622102834270197698202313169017678006675195485079921636419370285375124784014907159135459982790513399611551794271106831134090584272884279791554849782954323534517065223269061394905987693002122963395687782878948440616007412945674919823050571642377154816321380631045902916136926708342856440730447899971901781465763473223850267253059899795996090799469201774624817718449867455659250178329070473119433165550807568221846571746373296884912819520317457002440926616910874148385078411929804522981857338977648103126085902995208257421855249796721729039744118165938433694823325696642096892124547425283", /* 2K moduli mersenne primes */ "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", "531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127", "10407932194664399081925240327364085538615262247266704805319112350403608059673360298012239441732324184842421613954281007791383566248323464908139906605677320762924129509389220345773183349661583550472959420547689811211693677147548478866962501384438260291732348885311160828538416585028255604666224831890918801847068222203140521026698435488732958028878050869736186900714720710555703168729087", "1475979915214180235084898622737381736312066145333169775147771216478570297878078949377407337049389289382748507531496480477281264838760259191814463365330269540496961201113430156902396093989090226259326935025281409614983499388222831448598601834318536230923772641390209490231836446899608210795482963763094236630945410832793769905399982457186322944729636418890623372171723742105636440368218459649632948538696905872650486914434637457507280441823676813517852099348660847172579408422316678097670224011990280170474894487426924742108823536808485072502240519452587542875349976558572670229633962575212637477897785501552646522609988869914013540483809865681250419497686697771007", "259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071", "190797007524439073807468042969529173669356994749940177394741882673528979787005053706368049835514900244303495954950709725762186311224148828811920216904542206960744666169364221195289538436845390250168663932838805192055137154390912666527533007309292687539092257043362517857366624699975402375462954490293259233303137330643531556539739921926201438606439020075174723029056838272505051571967594608350063404495977660656269020823960825567012344189908927956646011998057988548630107637380993519826582389781888135705408653045219655801758081251164080554609057468028203308718724654081055323215860189611391296030471108443146745671967766308925858547271507311563765171008318248647110097614890313562856541784154881743146033909602737947385055355960331855614540900081456378659068370317267696980001187750995491090350108417050917991562167972281070161305972518044872048331306383715094854938415738549894606070722584737978176686422134354526989443028353644037187375385397838259511833166416134323695660367676897722287918773420968982326089026150031515424165462111337527431154890666327374921446276833564519776797633875503548665093914556482031482248883127023777039667707976559857333357013727342079099064400455741830654320379350833236245819348824064783585692924881021978332974949906122664421376034687815350484991", /* DR moduli */ "14059105607947488696282932836518693308967803494693489478439861164411992439598399594747002144074658928593502845729752797260025831423419686528151609940203368612079", "101745825697019260773923519755878567461315282017759829107608914364075275235254395622580447400994175578963163918967182013639660669771108475957692810857098847138903161308502419410142185759152435680068435915159402496058513611411688900243039", "736335108039604595805923406147184530889923370574768772191969612422073040099331944991573923112581267542507986451953227192970402893063850485730703075899286013451337291468249027691733891486704001513279827771740183629161065194874727962517148100775228363421083691764065477590823919364012917984605619526140821797602431", "38564998830736521417281865696453025806593491967131023221754800625044118265468851210705360385717536794615180260494208076605798671660719333199513807806252394423283413430106003596332513246682903994829528690198205120921557533726473585751382193953592127439965050261476810842071573684505878854588706623484573925925903505747545471088867712185004135201289273405614415899438276535626346098904241020877974002916168099951885406379295536200413493190419727789712076165162175783", "542189391331696172661670440619180536749994166415993334151601745392193484590296600979602378676624808129613777993466242203025054573692562689251250471628358318743978285860720148446448885701001277560572526947619392551574490839286458454994488665744991822837769918095117129546414124448777033941223565831420390846864429504774477949153794689948747680362212954278693335653935890352619041936727463717926744868338358149568368643403037768649616778526013610493696186055899318268339432671541328195724261329606699831016666359440874843103020666106568222401047720269951530296879490444224546654729111504346660859907296364097126834834235287147", "1487259134814709264092032648525971038895865645148901180585340454985524155135260217788758027400478312256339496385275012465661575576202252063145698732079880294664220579764848767704076761853197216563262660046602703973050798218246170835962005598561669706844469447435461092542265792444947706769615695252256130901271870341005768912974433684521436211263358097522726462083917939091760026658925757076733484173202927141441492573799914240222628795405623953109131594523623353044898339481494120112723445689647986475279242446083151413667587008191682564376412347964146113898565886683139407005941383669325997475076910488086663256335689181157957571445067490187939553165903773554290260531009121879044170766615232300936675369451260747671432073394867530820527479172464106442450727640226503746586340279816318821395210726268291535648506190714616083163403189943334431056876038286530365757187367147446004855912033137386225053275419626102417236133948503", "1095121115716677802856811290392395128588168592409109494900178008967955253005183831872715423151551999734857184538199864469605657805519106717529655044054833197687459782636297255219742994736751541815269727940751860670268774903340296040006114013971309257028332849679096824800250742691718610670812374272414086863715763724622797509437062518082383056050144624962776302147890521249477060215148275163688301275847155316042279405557632639366066847442861422164832655874655824221577849928863023018366835675399949740429332468186340518172487073360822220449055340582568461568645259954873303616953776393853174845132081121976327462740354930744487429617202585015510744298530101547706821590188733515880733527449780963163909830077616357506845523215289297624086914545378511082534229620116563260168494523906566709418166011112754529766183554579321224940951177394088465596712620076240067370589036924024728375076210477267488679008016579588696191194060127319035195370137160936882402244399699172017835144537488486396906144217720028992863941288217185353914991583400421682751000603596655790990815525126154394344641336397793791497068253936771017031980867706707490224041075826337383538651825493679503771934836094655802776331664261631740148281763487765852746577808019633679", /* generic unrestricted moduli */ "17933601194860113372237070562165128350027320072176844226673287945873370751245439587792371960615073855669274087805055507977323024886880985062002853331424203", "2893527720709661239493896562339544088620375736490408468011883030469939904368086092336458298221245707898933583190713188177399401852627749210994595974791782790253946539043962213027074922559572312141181787434278708783207966459019479487", "347743159439876626079252796797422223177535447388206607607181663903045907591201940478223621722118173270898487582987137708656414344685816179420855160986340457973820182883508387588163122354089264395604796675278966117567294812714812796820596564876450716066283126720010859041484786529056457896367683122960411136319", "47266428956356393164697365098120418976400602706072312735924071745438532218237979333351774907308168340693326687317443721193266215155735814510792148768576498491199122744351399489453533553203833318691678263241941706256996197460424029012419012634671862283532342656309677173602509498417976091509154360039893165037637034737020327399910409885798185771003505320583967737293415979917317338985837385734747478364242020380416892056650841470869294527543597349250299539682430605173321029026555546832473048600327036845781970289288898317888427517364945316709081173840186150794397479045034008257793436817683392375274635794835245695887", "436463808505957768574894870394349739623346440601945961161254440072143298152040105676491048248110146278752857839930515766167441407021501229924721335644557342265864606569000117714935185566842453630868849121480179691838399545644365571106757731317371758557990781880691336695584799313313687287468894148823761785582982549586183756806449017542622267874275103877481475534991201849912222670102069951687572917937634467778042874315463238062009202992087620963771759666448266532858079402669920025224220613419441069718482837399612644978839925207109870840278194042158748845445131729137117098529028886770063736487420613144045836803985635654192482395882603511950547826439092832800532152534003936926017612446606135655146445620623395788978726744728503058670046885876251527122350275750995227", "11424167473351836398078306042624362277956429440521137061889702611766348760692206243140413411077394583180726863277012016602279290144126785129569474909173584789822341986742719230331946072730319555984484911716797058875905400999504305877245849119687509023232790273637466821052576859232452982061831009770786031785669030271542286603956118755585683996118896215213488875253101894663403069677745948305893849505434201763745232895780711972432011344857521691017896316861403206449421332243658855453435784006517202894181640562433575390821384210960117518650374602256601091379644034244332285065935413233557998331562749140202965844219336298970011513882564935538704289446968322281451907487362046511461221329799897350993370560697505809686438782036235372137015731304779072430260986460269894522159103008260495503005267165927542949439526272736586626709581721032189532726389643625590680105784844246152702670169304203783072275089194754889511973916207", "1214855636816562637502584060163403830270705000634713483015101384881871978446801224798536155406895823305035467591632531067547890948695117172076954220727075688048751022421198712032848890056357845974246560748347918630050853933697792254955890439720297560693579400297062396904306270145886830719309296352765295712183040773146419022875165382778007040109957609739589875590885701126197906063620133954893216612678838507540777138437797705602453719559017633986486649523611975865005712371194067612263330335590526176087004421363598470302731349138773205901447704682181517904064735636518462452242791676541725292378925568296858010151852326316777511935037531017413910506921922450666933202278489024521263798482237150056835746454842662048692127173834433089016107854491097456725016327709663199738238442164843147132789153725513257167915555162094970853584447993125488607696008169807374736711297007473812256272245489405898470297178738029484459690836250560495461579533254473316340608217876781986188705928270735695752830825527963838355419762516246028680280988020401914551825487349990306976304093109384451438813251211051597392127491464898797406789175453067960072008590614886532333015881171367104445044718144312416815712216611576221546455968770801413440778423979", NULL }; log = fopen("logs/expt.log", "w"); logb = fopen("logs/expt_dr.log", "w"); logc = fopen("logs/expt_2k.log", "w"); logd = fopen("logs/expt_2kl.log", "w"); for (n = 0; primes[n]; n++) { SLEEP; mp_read_radix(&a, primes[n], 10); mp_zero(&b); for (rr = 0; rr < (unsigned) mp_count_bits(&a); rr++) { mp_mul_2(&b, &b); b.dp[0] |= lbit(); b.used += 1; } mp_sub_d(&a, 1, &c); mp_mod(&b, &c, &b); mp_set(&c, 3); rr = 0; tt = -1; do { gg = TIMFUNC(); DO(mp_exptmod(&c, &b, &a, &d)); gg = (TIMFUNC() - gg) >> 1; if (tt > gg) tt = gg; } while (++rr < 10); mp_sub_d(&a, 1, &e); mp_sub(&e, &b, &b); mp_exptmod(&c, &b, &a, &e); /* c^(p-1-b) mod a */ mp_mulmod(&e, &d, &a, &d); /* c^b * c^(p-1-b) == c^p-1 == 1 */ if (mp_cmp_d(&d, 1)) { printf("Different (%d)!!!\n", mp_count_bits(&a)); draw(&d); exit(0); } printf("Exponentiating\t%4d-bit => %9llu/sec, %9llu cycles\n", mp_count_bits(&a), CLK_PER_SEC / tt, tt); fprintf(n < 4 ? logd : (n < 9) ? logc : (n < 16) ? logb : log, "%d %9llu\n", mp_count_bits(&a), tt); } } fclose(log); fclose(logb); fclose(logc); fclose(logd); log = fopen("logs/invmod.log", "w"); for (cnt = 4; cnt <= 128; cnt += 4) { SLEEP; mp_rand(&a, cnt); mp_rand(&b, cnt); do { mp_add_d(&b, 1, &b); mp_gcd(&a, &b, &c); } while (mp_cmp_d(&c, 1) != MP_EQ); rr = 0; tt = -1; do { gg = TIMFUNC(); DO(mp_invmod(&b, &a, &c)); gg = (TIMFUNC() - gg) >> 1; if (tt > gg) tt = gg; } while (++rr < 1000); mp_mulmod(&b, &c, &a, &d); if (mp_cmp_d(&d, 1) != MP_EQ) { printf("Failed to invert\n"); return 0; } printf("Inverting mod\t%4d-bit => %9llu/sec, %9llu cycles\n", mp_count_bits(&a), CLK_PER_SEC / tt, tt); fprintf(log, "%d %9llu\n", cnt * DIGIT_BIT, tt); } fclose(log); return 0; }
int main(void) { int n, tmp; mp_int a, b, c, d, e; clock_t t1; char buf[4096]; mp_init(&a); mp_init(&b); mp_init(&c); mp_init(&d); mp_init(&e); /* initial (2^n - 1)^2 testing, makes sure the comba multiplier works [it has the new carry code] */ /* mp_set(&a, 1); for (n = 1; n < 8192; n++) { mp_mul(&a, &a, &c); printf("mul\n"); mp_to64(&a, buf); printf("%s\n%s\n", buf, buf); mp_to64(&c, buf); printf("%s\n", buf); mp_add_d(&a, 1, &a); mp_mul_2(&a, &a); mp_sub_d(&a, 1, &a); } */ rng = fopen("/dev/urandom", "rb"); if (rng == NULL) { rng = fopen("/dev/random", "rb"); if (rng == NULL) { fprintf(stderr, "\nWarning: stdin used as random source\n\n"); rng = stdin; } } t1 = clock(); for (;;) { #if 0 if (clock() - t1 > CLOCKS_PER_SEC) { sleep(2); t1 = clock(); } #endif n = fgetc(rng) % 15; if (n == 0) { /* add tests */ rand_num(&a); rand_num(&b); mp_add(&a, &b, &c); printf("add\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 1) { /* sub tests */ rand_num(&a); rand_num(&b); mp_sub(&a, &b, &c); printf("sub\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 2) { /* mul tests */ rand_num(&a); rand_num(&b); mp_mul(&a, &b, &c); printf("mul\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 3) { /* div tests */ rand_num(&a); rand_num(&b); mp_div(&a, &b, &c, &d); printf("div\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); mp_to64(&d, buf); printf("%s\n", buf); } else if (n == 4) { /* sqr tests */ rand_num(&a); mp_sqr(&a, &b); printf("sqr\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 5) { /* mul_2d test */ rand_num(&a); mp_copy(&a, &b); n = fgetc(rng) & 63; mp_mul_2d(&b, n, &b); mp_to64(&a, buf); printf("mul2d\n"); printf("%s\n", buf); printf("%d\n", n); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 6) { /* div_2d test */ rand_num(&a); mp_copy(&a, &b); n = fgetc(rng) & 63; mp_div_2d(&b, n, &b, NULL); mp_to64(&a, buf); printf("div2d\n"); printf("%s\n", buf); printf("%d\n", n); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 7) { /* gcd test */ rand_num(&a); rand_num(&b); a.sign = MP_ZPOS; b.sign = MP_ZPOS; mp_gcd(&a, &b, &c); printf("gcd\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 8) { /* lcm test */ rand_num(&a); rand_num(&b); a.sign = MP_ZPOS; b.sign = MP_ZPOS; mp_lcm(&a, &b, &c); printf("lcm\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 9) { /* exptmod test */ rand_num2(&a); rand_num2(&b); rand_num2(&c); // if (c.dp[0]&1) mp_add_d(&c, 1, &c); a.sign = b.sign = c.sign = 0; mp_exptmod(&a, &b, &c, &d); printf("expt\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); mp_to64(&d, buf); printf("%s\n", buf); } else if (n == 10) { /* invmod test */ rand_num2(&a); rand_num2(&b); b.sign = MP_ZPOS; a.sign = MP_ZPOS; mp_gcd(&a, &b, &c); if (mp_cmp_d(&c, 1) != 0) continue; if (mp_cmp_d(&b, 1) == 0) continue; mp_invmod(&a, &b, &c); printf("invmod\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 11) { rand_num(&a); mp_mul_2(&a, &a); mp_div_2(&a, &b); printf("div2\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 12) { rand_num2(&a); mp_mul_2(&a, &b); printf("mul2\n"); mp_to64(&a, buf); printf("%s\n", buf); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 13) { rand_num2(&a); tmp = abs(rand()) & THE_MASK; mp_add_d(&a, tmp, &b); printf("add_d\n"); mp_to64(&a, buf); printf("%s\n%d\n", buf, tmp); mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 14) { rand_num2(&a); tmp = abs(rand()) & THE_MASK; mp_sub_d(&a, tmp, &b); printf("sub_d\n"); mp_to64(&a, buf); printf("%s\n%d\n", buf, tmp); mp_to64(&b, buf); printf("%s\n", buf); } } fclose(rng); return 0; }
/* squaring using Toom-Cook 3-way algorithm */ int mp_toom_sqr(const mp_int *a, mp_int *b) { mp_int w0, w1, w2, w3, w4, tmp1, a0, a1, a2; int res, B; /* init temps */ if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL)) != MP_OKAY) { return res; } /* B */ B = a->used / 3; /* a = a2 * B**2 + a1 * B + a0 */ if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_copy(a, &a1)) != MP_OKAY) { goto LBL_ERR; } mp_rshd(&a1, B); if ((res = mp_mod_2d(&a1, DIGIT_BIT * B, &a1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_copy(a, &a2)) != MP_OKAY) { goto LBL_ERR; } mp_rshd(&a2, B*2); /* w0 = a0*a0 */ if ((res = mp_sqr(&a0, &w0)) != MP_OKAY) { goto LBL_ERR; } /* w4 = a2 * a2 */ if ((res = mp_sqr(&a2, &w4)) != MP_OKAY) { goto LBL_ERR; } /* w1 = (a2 + 2(a1 + 2a0))**2 */ if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sqr(&tmp1, &w1)) != MP_OKAY) { goto LBL_ERR; } /* w3 = (a0 + 2(a1 + 2a2))**2 */ if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sqr(&tmp1, &w3)) != MP_OKAY) { goto LBL_ERR; } /* w2 = (a2 + a1 + a0)**2 */ if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sqr(&tmp1, &w2)) != MP_OKAY) { goto LBL_ERR; } /* now solve the matrix 0 0 0 0 1 1 2 4 8 16 1 1 1 1 1 16 8 4 2 1 1 0 0 0 0 using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication. */ /* r1 - r4 */ if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { goto LBL_ERR; } /* r3 - r0 */ if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { goto LBL_ERR; } /* r1/2 */ if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { goto LBL_ERR; } /* r3/2 */ if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { goto LBL_ERR; } /* r2 - r0 - r4 */ if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { goto LBL_ERR; } /* r1 - r2 */ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { goto LBL_ERR; } /* r3 - r2 */ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { goto LBL_ERR; } /* r1 - 8r0 */ if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { goto LBL_ERR; } /* r3 - 8r4 */ if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { goto LBL_ERR; } /* 3r2 - r1 - r3 */ if ((res = mp_mul_d(&w2, 3uL, &w2)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { goto LBL_ERR; } /* r1 - r2 */ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { goto LBL_ERR; } /* r3 - r2 */ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { goto LBL_ERR; } /* r1/3 */ if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { goto LBL_ERR; } /* r3/3 */ if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { goto LBL_ERR; } /* at this point shift W[n] by B*n */ if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_add(&w0, &w1, b)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_add(&tmp1, b, b)) != MP_OKAY) { goto LBL_ERR; } LBL_ERR: mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL); return res; }
/** Create a DSA key @param prng An active PRNG state @param wprng The index of the PRNG desired @param group_size Size of the multiplicative group (octets) @param modulus_size Size of the modulus (octets) @param key [out] Where to store the created key @return CRYPT_OK if successful, upon error this function will free all allocated memory */ int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key) { mp_int tmp, tmp2; int err, res; unsigned char *buf; LTC_ARGCHK(key != NULL); /* check prng */ if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } /* check size */ if (group_size >= MDSA_MAX_GROUP || group_size <= 15 || group_size >= modulus_size || (modulus_size - group_size) >= MDSA_DELTA) { return CRYPT_INVALID_ARG; } /* allocate ram */ buf = XMALLOC(MDSA_DELTA); if (buf == NULL) { return CRYPT_MEM; } /* init mp_ints */ if ((err = mp_init_multi(&tmp, &tmp2, &key->g, &key->q, &key->p, &key->x, &key->y, NULL)) != MP_OKAY) { err = mpi_to_ltc_error(err); goto LBL_ERR; } /* make our prime q */ if ((err = rand_prime(&key->q, group_size*8, prng, wprng)) != CRYPT_OK) { goto LBL_ERR; } /* double q */ if ((err = mp_mul_2(&key->q, &tmp)) != MP_OKAY) { goto error; } /* now make a random string and multply it against q */ if (prng_descriptor[wprng].read(buf+1, modulus_size - group_size, prng) != (unsigned long)(modulus_size - group_size)) { err = CRYPT_ERROR_READPRNG; goto LBL_ERR; } /* force magnitude */ buf[0] = 1; /* force even */ buf[modulus_size - group_size] &= ~1; if ((err = mp_read_unsigned_bin(&tmp2, buf, modulus_size - group_size+1)) != MP_OKAY) { goto error; } if ((err = mp_mul(&key->q, &tmp2, &key->p)) != MP_OKAY) { goto error; } if ((err = mp_add_d(&key->p, 1, &key->p)) != MP_OKAY) { goto error; } /* now loop until p is prime */ for (;;) { if ((err = is_prime(&key->p, &res)) != CRYPT_OK) { goto LBL_ERR; } if (res == MP_YES) break; /* add 2q to p and 2 to tmp2 */ if ((err = mp_add(&tmp, &key->p, &key->p)) != MP_OKAY) { goto error; } if ((err = mp_add_d(&tmp2, 2, &tmp2)) != MP_OKAY) { goto error; } } /* now p = (q * tmp2) + 1 is prime, find a value g for which g^tmp2 != 1 */ mp_set(&key->g, 1); do { if ((err = mp_add_d(&key->g, 1, &key->g)) != MP_OKAY) { goto error; } if ((err = mp_exptmod(&key->g, &tmp2, &key->p, &tmp)) != MP_OKAY) { goto error; } } while (mp_cmp_d(&tmp, 1) == MP_EQ); /* at this point tmp generates a group of order q mod p */ mp_exch(&tmp, &key->g); /* so now we have our DH structure, generator g, order q, modulus p Now we need a random exponent [mod q] and it's power g^x mod p */ do { if (prng_descriptor[wprng].read(buf, group_size, prng) != (unsigned long)group_size) { err = CRYPT_ERROR_READPRNG; goto LBL_ERR; } if ((err = mp_read_unsigned_bin(&key->x, buf, group_size)) != MP_OKAY) { goto error; } } while (mp_cmp_d(&key->x, 1) != MP_GT); if ((err = mp_exptmod(&key->g, &key->x, &key->p, &key->y)) != MP_OKAY) { goto error; } key->type = PK_PRIVATE; key->qord = group_size; /* shrink the ram required */ if ((err = mp_shrink(&key->g)) != MP_OKAY) { goto error; } if ((err = mp_shrink(&key->p)) != MP_OKAY) { goto error; } if ((err = mp_shrink(&key->q)) != MP_OKAY) { goto error; } if ((err = mp_shrink(&key->x)) != MP_OKAY) { goto error; } if ((err = mp_shrink(&key->y)) != MP_OKAY) { goto error; } #ifdef LTC_CLEAN_STACK zeromem(buf, MDSA_DELTA); #endif err = CRYPT_OK; goto done; error: err = mpi_to_ltc_error(err); LBL_ERR: mp_clear_multi(&key->g, &key->q, &key->p, &key->x, &key->y, NULL); done: mp_clear_multi(&tmp, &tmp2, NULL); XFREE(buf); return err; }
/* Strong Lucas-Selfridge test. returns MP_YES if it is a strong L-S prime, MP_NO if it is composite Code ported from Thomas Ray Nicely's implementation of the BPSW test at http://www.trnicely.net/misc/bpsw.html Freeware copyright (C) 2016 Thomas R. Nicely <http://www.trnicely.net>. Released into the public domain by the author, who disclaims any legal liability arising from its use The multi-line comments are made by Thomas R. Nicely and are copied verbatim. Additional comments marked "CZ" (without the quotes) are by the code-portist. (If that name sounds familiar, he is the guy who found the fdiv bug in the Pentium (P5x, I think) Intel processor) */ int mp_prime_strong_lucas_selfridge(const mp_int *a, int *result) { /* CZ TODO: choose better variable names! */ mp_int Dz, gcd, Np1, Uz, Vz, U2mz, V2mz, Qmz, Q2mz, Qkdz, T1z, T2z, T3z, T4z, Q2kdz; /* CZ TODO: Some of them need the full 32 bit, hence the (temporary) exclusion of MP_8BIT */ int32_t D, Ds, J, sign, P, Q, r, s, u, Nbits; int e; int isset; *result = MP_NO; /* Find the first element D in the sequence {5, -7, 9, -11, 13, ...} such that Jacobi(D,N) = -1 (Selfridge's algorithm). Theory indicates that, if N is not a perfect square, D will "nearly always" be "small." Just in case, an overflow trap for D is included. */ if ((e = mp_init_multi(&Dz, &gcd, &Np1, &Uz, &Vz, &U2mz, &V2mz, &Qmz, &Q2mz, &Qkdz, &T1z, &T2z, &T3z, &T4z, &Q2kdz, NULL)) != MP_OKAY) { return e; } D = 5; sign = 1; for (;;) { Ds = sign * D; sign = -sign; if ((e = mp_set_long(&Dz, (unsigned long)D)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_gcd(a, &Dz, &gcd)) != MP_OKAY) { goto LBL_LS_ERR; } /* if 1 < GCD < N then N is composite with factor "D", and Jacobi(D,N) is technically undefined (but often returned as zero). */ if ((mp_cmp_d(&gcd, 1uL) == MP_GT) && (mp_cmp(&gcd, a) == MP_LT)) { goto LBL_LS_ERR; } if (Ds < 0) { Dz.sign = MP_NEG; } if ((e = mp_kronecker(&Dz, a, &J)) != MP_OKAY) { goto LBL_LS_ERR; } if (J == -1) { break; } D += 2; if (D > (INT_MAX - 2)) { e = MP_VAL; goto LBL_LS_ERR; } } P = 1; /* Selfridge's choice */ Q = (1 - Ds) / 4; /* Required so D = P*P - 4*Q */ /* NOTE: The conditions (a) N does not divide Q, and (b) D is square-free or not a perfect square, are included by some authors; e.g., "Prime numbers and computer methods for factorization," Hans Riesel (2nd ed., 1994, Birkhauser, Boston), p. 130. For this particular application of Lucas sequences, these conditions were found to be immaterial. */ /* Now calculate N - Jacobi(D,N) = N + 1 (even), and calculate the odd positive integer d and positive integer s for which N + 1 = 2^s*d (similar to the step for N - 1 in Miller's test). The strong Lucas-Selfridge test then returns N as a strong Lucas probable prime (slprp) if any of the following conditions is met: U_d=0, V_d=0, V_2d=0, V_4d=0, V_8d=0, V_16d=0, ..., etc., ending with V_{2^(s-1)*d}=V_{(N+1)/2}=0 (all equalities mod N). Thus d is the highest index of U that must be computed (since V_2m is independent of U), compared to U_{N+1} for the standard Lucas-Selfridge test; and no index of V beyond (N+1)/2 is required, just as in the standard Lucas-Selfridge test. However, the quantity Q^d must be computed for use (if necessary) in the latter stages of the test. The result is that the strong Lucas-Selfridge test has a running time only slightly greater (order of 10 %) than that of the standard Lucas-Selfridge test, while producing only (roughly) 30 % as many pseudoprimes (and every strong Lucas pseudoprime is also a standard Lucas pseudoprime). Thus the evidence indicates that the strong Lucas-Selfridge test is more effective than the standard Lucas-Selfridge test, and a Baillie-PSW test based on the strong Lucas-Selfridge test should be more reliable. */ if ((e = mp_add_d(a, 1uL, &Np1)) != MP_OKAY) { goto LBL_LS_ERR; } s = mp_cnt_lsb(&Np1); /* CZ * This should round towards zero because * Thomas R. Nicely used GMP's mpz_tdiv_q_2exp() * and mp_div_2d() is equivalent. Additionally: * dividing an even number by two does not produce * any leftovers. */ if ((e = mp_div_2d(&Np1, s, &Dz, NULL)) != MP_OKAY) { goto LBL_LS_ERR; } /* We must now compute U_d and V_d. Since d is odd, the accumulated values U and V are initialized to U_1 and V_1 (if the target index were even, U and V would be initialized instead to U_0=0 and V_0=2). The values of U_2m and V_2m are also initialized to U_1 and V_1; the FOR loop calculates in succession U_2 and V_2, U_4 and V_4, U_8 and V_8, etc. If the corresponding bits (1, 2, 3, ...) of t are on (the zero bit having been accounted for in the initialization of U and V), these values are then combined with the previous totals for U and V, using the composition formulas for addition of indices. */ mp_set(&Uz, 1uL); /* U=U_1 */ mp_set(&Vz, (mp_digit)P); /* V=V_1 */ mp_set(&U2mz, 1uL); /* U_1 */ mp_set(&V2mz, (mp_digit)P); /* V_1 */ if (Q < 0) { Q = -Q; if ((e = mp_set_long(&Qmz, (unsigned long)Q)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) { goto LBL_LS_ERR; } /* Initializes calculation of Q^d */ if ((e = mp_set_long(&Qkdz, (unsigned long)Q)) != MP_OKAY) { goto LBL_LS_ERR; } Qmz.sign = MP_NEG; Q2mz.sign = MP_NEG; Qkdz.sign = MP_NEG; Q = -Q; } else { if ((e = mp_set_long(&Qmz, (unsigned long)Q)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) { goto LBL_LS_ERR; } /* Initializes calculation of Q^d */ if ((e = mp_set_long(&Qkdz, (unsigned long)Q)) != MP_OKAY) { goto LBL_LS_ERR; } } Nbits = mp_count_bits(&Dz); for (u = 1; u < Nbits; u++) { /* zero bit off, already accounted for */ /* Formulas for doubling of indices (carried out mod N). Note that * the indices denoted as "2m" are actually powers of 2, specifically * 2^(ul-1) beginning each loop and 2^ul ending each loop. * * U_2m = U_m*V_m * V_2m = V_m*V_m - 2*Q^m */ if ((e = mp_mul(&U2mz, &V2mz, &U2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&U2mz, a, &U2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_sqr(&V2mz, &V2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_sub(&V2mz, &Q2mz, &V2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&V2mz, a, &V2mz)) != MP_OKAY) { goto LBL_LS_ERR; } /* Must calculate powers of Q for use in V_2m, also for Q^d later */ if ((e = mp_sqr(&Qmz, &Qmz)) != MP_OKAY) { goto LBL_LS_ERR; } /* prevents overflow */ /* CZ still necessary without a fixed prealloc'd mem.? */ if ((e = mp_mod(&Qmz, a, &Qmz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((isset = mp_get_bit(&Dz, u)) == MP_VAL) { e = isset; goto LBL_LS_ERR; } if (isset == MP_YES) { /* Formulas for addition of indices (carried out mod N); * * U_(m+n) = (U_m*V_n + U_n*V_m)/2 * V_(m+n) = (V_m*V_n + D*U_m*U_n)/2 * * Be careful with division by 2 (mod N)! */ if ((e = mp_mul(&U2mz, &Vz, &T1z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul(&Uz, &V2mz, &T2z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul(&V2mz, &Vz, &T3z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul(&U2mz, &Uz, &T4z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = s_mp_mul_si(&T4z, (long)Ds, &T4z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_add(&T1z, &T2z, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } if (mp_isodd(&Uz) != MP_NO) { if ((e = mp_add(&Uz, a, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } } /* CZ * This should round towards negative infinity because * Thomas R. Nicely used GMP's mpz_fdiv_q_2exp(). * But mp_div_2() does not do so, it is truncating instead. */ if ((e = mp_div_2(&Uz, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((Uz.sign == MP_NEG) && (mp_isodd(&Uz) != MP_NO)) { if ((e = mp_sub_d(&Uz, 1uL, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } } if ((e = mp_add(&T3z, &T4z, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if (mp_isodd(&Vz) != MP_NO) { if ((e = mp_add(&Vz, a, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } } if ((e = mp_div_2(&Vz, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((Vz.sign == MP_NEG) && (mp_isodd(&Vz) != MP_NO)) { if ((e = mp_sub_d(&Vz, 1uL, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } } if ((e = mp_mod(&Uz, a, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&Vz, a, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } /* Calculating Q^d for later use */ if ((e = mp_mul(&Qkdz, &Qmz, &Qkdz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) { goto LBL_LS_ERR; } } } /* If U_d or V_d is congruent to 0 mod N, then N is a prime or a strong Lucas pseudoprime. */ if ((mp_iszero(&Uz) != MP_NO) || (mp_iszero(&Vz) != MP_NO)) { *result = MP_YES; goto LBL_LS_ERR; } /* NOTE: Ribenboim ("The new book of prime number records," 3rd ed., 1995/6) omits the condition V0 on p.142, but includes it on p. 130. The condition is NECESSARY; otherwise the test will return false negatives---e.g., the primes 29 and 2000029 will be returned as composite. */ /* Otherwise, we must compute V_2d, V_4d, V_8d, ..., V_{2^(s-1)*d} by repeated use of the formula V_2m = V_m*V_m - 2*Q^m. If any of these are congruent to 0 mod N, then N is a prime or a strong Lucas pseudoprime. */ /* Initialize 2*Q^(d*2^r) for V_2m */ if ((e = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) { goto LBL_LS_ERR; } for (r = 1; r < s; r++) { if ((e = mp_sqr(&Vz, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_sub(&Vz, &Q2kdz, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&Vz, a, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if (mp_iszero(&Vz) != MP_NO) { *result = MP_YES; goto LBL_LS_ERR; } /* Calculate Q^{d*2^r} for next r (final iteration irrelevant). */ if (r < (s - 1)) { if ((e = mp_sqr(&Qkdz, &Qkdz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) { goto LBL_LS_ERR; } } } LBL_LS_ERR: mp_clear_multi(&Q2kdz, &T4z, &T3z, &T2z, &T1z, &Qkdz, &Q2mz, &Qmz, &V2mz, &U2mz, &Vz, &Uz, &Np1, &gcd, &Dz, NULL); return e; }
int main(void) { unsigned rr; int cnt, ix; #if LTM_DEMO_TEST_VS_MTEST unsigned long expt_n, add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n; char* ret; #else unsigned long s, t; unsigned long long q, r; mp_digit mp; int i, n, err, should; #endif if (mp_init_multi(&a, &b, &c, &d, &e, &f, NULL)!= MP_OKAY) return EXIT_FAILURE; atexit(_cleanup); #if defined(LTM_DEMO_REAL_RAND) if (!fd_urandom) { fd_urandom = fopen("/dev/urandom", "r"); if (!fd_urandom) { #if !defined(_WIN32) fprintf(stderr, "\ncould not open /dev/urandom\n"); #endif } } #endif srand(LTM_DEMO_RAND_SEED); #ifdef MP_8BIT printf("Digit size 8 Bit \n"); #endif #ifdef MP_16BIT printf("Digit size 16 Bit \n"); #endif #ifdef MP_32BIT printf("Digit size 32 Bit \n"); #endif #ifdef MP_64BIT printf("Digit size 64 Bit \n"); #endif printf("Size of mp_digit: %u\n", (unsigned int)sizeof(mp_digit)); printf("Size of mp_word: %u\n", (unsigned int)sizeof(mp_word)); printf("DIGIT_BIT: %d\n", DIGIT_BIT); printf("MP_PREC: %d\n", MP_PREC); #if LTM_DEMO_TEST_VS_MTEST == 0 // trivial stuff // a: 0->5 mp_set_int(&a, 5); // a: 5-> b: -5 mp_neg(&a, &b); if (mp_cmp(&a, &b) != MP_GT) { return EXIT_FAILURE; } if (mp_cmp(&b, &a) != MP_LT) { return EXIT_FAILURE; } // a: 5-> a: -5 mp_neg(&a, &a); if (mp_cmp(&b, &a) != MP_EQ) { return EXIT_FAILURE; } // a: -5-> b: 5 mp_abs(&a, &b); if (mp_isneg(&b) != MP_NO) { return EXIT_FAILURE; } // a: -5-> b: -4 mp_add_d(&a, 1, &b); if (mp_isneg(&b) != MP_YES) { return EXIT_FAILURE; } if (mp_get_int(&b) != 4) { return EXIT_FAILURE; } // a: -5-> b: 1 mp_add_d(&a, 6, &b); if (mp_get_int(&b) != 1) { return EXIT_FAILURE; } // a: -5-> a: 1 mp_add_d(&a, 6, &a); if (mp_get_int(&a) != 1) { return EXIT_FAILURE; } mp_zero(&a); // a: 0-> a: 6 mp_add_d(&a, 6, &a); if (mp_get_int(&a) != 6) { return EXIT_FAILURE; } mp_set_int(&a, 0); mp_set_int(&b, 1); if ((err = mp_jacobi(&a, &b, &i)) != MP_OKAY) { printf("Failed executing mp_jacobi(0 | 1) %s.\n", mp_error_to_string(err)); return EXIT_FAILURE; } if (i != 1) { printf("Failed trivial mp_jacobi(0 | 1) %d != 1\n", i); return EXIT_FAILURE; } for (cnt = 0; cnt < (int)(sizeof(jacobi)/sizeof(jacobi[0])); ++cnt) { mp_set_int(&b, jacobi[cnt].n); /* only test positive values of a */ for (n = -5; n <= 10; ++n) { mp_set_int(&a, abs(n)); should = MP_OKAY; if (n < 0) { mp_neg(&a, &a); /* Until #44 is fixed the negative a's must fail */ should = MP_VAL; } if ((err = mp_jacobi(&a, &b, &i)) != should) { printf("Failed executing mp_jacobi(%d | %lu) %s.\n", n, jacobi[cnt].n, mp_error_to_string(err)); return EXIT_FAILURE; } if (err == MP_OKAY && i != jacobi[cnt].c[n + 5]) { printf("Failed trivial mp_jacobi(%d | %lu) %d != %d\n", n, jacobi[cnt].n, i, jacobi[cnt].c[n + 5]); return EXIT_FAILURE; } } } // test mp_get_int printf("\n\nTesting: mp_get_int"); for (i = 0; i < 1000; ++i) { t = ((unsigned long) rand () * rand () + 1) & 0xFFFFFFFF; mp_set_int (&a, t); if (t != mp_get_int (&a)) { printf ("\nmp_get_int() bad result!"); return EXIT_FAILURE; } } mp_set_int(&a, 0); if (mp_get_int(&a) != 0) { printf("\nmp_get_int() bad result!"); return EXIT_FAILURE; } mp_set_int(&a, 0xffffffff); if (mp_get_int(&a) != 0xffffffff) { printf("\nmp_get_int() bad result!"); return EXIT_FAILURE; } printf("\n\nTesting: mp_get_long\n"); for (i = 0; i < (int)(sizeof(unsigned long)*CHAR_BIT) - 1; ++i) { t = (1ULL << (i+1)) - 1; if (!t) t = -1; printf(" t = 0x%lx i = %d\r", t, i); do { if (mp_set_long(&a, t) != MP_OKAY) { printf("\nmp_set_long() error!"); return EXIT_FAILURE; } s = mp_get_long(&a); if (s != t) { printf("\nmp_get_long() bad result! 0x%lx != 0x%lx", s, t); return EXIT_FAILURE; } t <<= 1; } while(t); } printf("\n\nTesting: mp_get_long_long\n"); for (i = 0; i < (int)(sizeof(unsigned long long)*CHAR_BIT) - 1; ++i) { r = (1ULL << (i+1)) - 1; if (!r) r = -1; printf(" r = 0x%llx i = %d\r", r, i); do { if (mp_set_long_long(&a, r) != MP_OKAY) { printf("\nmp_set_long_long() error!"); return EXIT_FAILURE; } q = mp_get_long_long(&a); if (q != r) { printf("\nmp_get_long_long() bad result! 0x%llx != 0x%llx", q, r); return EXIT_FAILURE; } r <<= 1; } while(r); } // test mp_sqrt printf("\n\nTesting: mp_sqrt\n"); for (i = 0; i < 1000; ++i) { printf ("%6d\r", i); fflush (stdout); n = (rand () & 15) + 1; mp_rand (&a, n); if (mp_sqrt (&a, &b) != MP_OKAY) { printf ("\nmp_sqrt() error!"); return EXIT_FAILURE; } mp_n_root_ex (&a, 2, &c, 0); mp_n_root_ex (&a, 2, &d, 1); if (mp_cmp_mag (&c, &d) != MP_EQ) { printf ("\nmp_n_root_ex() bad result!"); return EXIT_FAILURE; } if (mp_cmp_mag (&b, &c) != MP_EQ) { printf ("mp_sqrt() bad result!\n"); return EXIT_FAILURE; } } printf("\n\nTesting: mp_is_square\n"); for (i = 0; i < 1000; ++i) { printf ("%6d\r", i); fflush (stdout); /* test mp_is_square false negatives */ n = (rand () & 7) + 1; mp_rand (&a, n); mp_sqr (&a, &a); if (mp_is_square (&a, &n) != MP_OKAY) { printf ("\nfn:mp_is_square() error!"); return EXIT_FAILURE; } if (n == 0) { printf ("\nfn:mp_is_square() bad result!"); return EXIT_FAILURE; } /* test for false positives */ mp_add_d (&a, 1, &a); if (mp_is_square (&a, &n) != MP_OKAY) { printf ("\nfp:mp_is_square() error!"); return EXIT_FAILURE; } if (n == 1) { printf ("\nfp:mp_is_square() bad result!"); return EXIT_FAILURE; } } printf("\n\n"); // r^2 = n (mod p) for (i = 0; i < (int)(sizeof(sqrtmod_prime)/sizeof(sqrtmod_prime[0])); ++i) { mp_set_int(&a, sqrtmod_prime[i].p); mp_set_int(&b, sqrtmod_prime[i].n); if (mp_sqrtmod_prime(&b, &a, &c) != MP_OKAY) { printf("Failed executing %d. mp_sqrtmod_prime\n", (i+1)); return EXIT_FAILURE; } if (mp_cmp_d(&c, sqrtmod_prime[i].r) != MP_EQ) { printf("Failed %d. trivial mp_sqrtmod_prime\n", (i+1)); ndraw(&c, "r"); return EXIT_FAILURE; } } /* test for size */ for (ix = 10; ix < 128; ix++) { printf ("Testing (not safe-prime): %9d bits \r", ix); fflush (stdout); err = mp_prime_random_ex (&a, 8, ix, (rand () & 1) ? 0 : LTM_PRIME_2MSB_ON, myrng, NULL); if (err != MP_OKAY) { printf ("failed with err code %d\n", err); return EXIT_FAILURE; } if (mp_count_bits (&a) != ix) { printf ("Prime is %d not %d bits!!!\n", mp_count_bits (&a), ix); return EXIT_FAILURE; } } printf("\n"); for (ix = 16; ix < 128; ix++) { printf ("Testing ( safe-prime): %9d bits \r", ix); fflush (stdout); err = mp_prime_random_ex ( &a, 8, ix, ((rand () & 1) ? 0 : LTM_PRIME_2MSB_ON) | LTM_PRIME_SAFE, myrng, NULL); if (err != MP_OKAY) { printf ("failed with err code %d\n", err); return EXIT_FAILURE; } if (mp_count_bits (&a) != ix) { printf ("Prime is %d not %d bits!!!\n", mp_count_bits (&a), ix); return EXIT_FAILURE; } /* let's see if it's really a safe prime */ mp_sub_d (&a, 1, &a); mp_div_2 (&a, &a); mp_prime_is_prime (&a, 8, &cnt); if (cnt != MP_YES) { printf ("sub is not prime!\n"); return EXIT_FAILURE; } } printf("\n\n"); // test montgomery printf("Testing: montgomery...\n"); for (i = 1; i <= 10; i++) { if (i == 10) i = 1000; printf(" digit size: %2d\r", i); fflush(stdout); for (n = 0; n < 1000; n++) { mp_rand(&a, i); a.dp[0] |= 1; // let's see if R is right mp_montgomery_calc_normalization(&b, &a); mp_montgomery_setup(&a, &mp); // now test a random reduction for (ix = 0; ix < 100; ix++) { mp_rand(&c, 1 + abs(rand()) % (2*i)); mp_copy(&c, &d); mp_copy(&c, &e); mp_mod(&d, &a, &d); mp_montgomery_reduce(&c, &a, mp); mp_mulmod(&c, &b, &a, &c); if (mp_cmp(&c, &d) != MP_EQ) { printf("d = e mod a, c = e MOD a\n"); mp_todecimal(&a, buf); printf("a = %s\n", buf); mp_todecimal(&e, buf); printf("e = %s\n", buf); mp_todecimal(&d, buf); printf("d = %s\n", buf); mp_todecimal(&c, buf); printf("c = %s\n", buf); printf("compare no compare!\n"); return EXIT_FAILURE; } /* only one big montgomery reduction */ if (i > 10) { n = 1000; ix = 100; } } } } printf("\n\n"); mp_read_radix(&a, "123456", 10); mp_toradix_n(&a, buf, 10, 3); printf("a == %s\n", buf); mp_toradix_n(&a, buf, 10, 4); printf("a == %s\n", buf); mp_toradix_n(&a, buf, 10, 30); printf("a == %s\n", buf); #if 0 for (;;) { fgets(buf, sizeof(buf), stdin); mp_read_radix(&a, buf, 10); mp_prime_next_prime(&a, 5, 1); mp_toradix(&a, buf, 10); printf("%s, %lu\n", buf, a.dp[0] & 3); } #endif /* test mp_cnt_lsb */ printf("\n\nTesting: mp_cnt_lsb"); mp_set(&a, 1); for (ix = 0; ix < 1024; ix++) { if (mp_cnt_lsb (&a) != ix) { printf ("Failed at %d, %d\n", ix, mp_cnt_lsb (&a)); return EXIT_FAILURE; } mp_mul_2 (&a, &a); } /* test mp_reduce_2k */ printf("\n\nTesting: mp_reduce_2k\n"); for (cnt = 3; cnt <= 128; ++cnt) { mp_digit tmp; mp_2expt (&a, cnt); mp_sub_d (&a, 2, &a); /* a = 2**cnt - 2 */ printf ("\r %4d bits", cnt); printf ("(%d)", mp_reduce_is_2k (&a)); mp_reduce_2k_setup (&a, &tmp); printf ("(%lu)", (unsigned long) tmp); for (ix = 0; ix < 1000; ix++) { if (!(ix & 127)) { printf ("."); fflush (stdout); } mp_rand (&b, (cnt / DIGIT_BIT + 1) * 2); mp_copy (&c, &b); mp_mod (&c, &a, &c); mp_reduce_2k (&b, &a, 2); if (mp_cmp (&c, &b)) { printf ("FAILED\n"); return EXIT_FAILURE; } } } /* test mp_div_3 */ printf("\n\nTesting: mp_div_3...\n"); mp_set(&d, 3); for (cnt = 0; cnt < 10000;) { mp_digit r2; if (!(++cnt & 127)) { printf("%9d\r", cnt); fflush(stdout); } mp_rand(&a, abs(rand()) % 128 + 1); mp_div(&a, &d, &b, &e); mp_div_3(&a, &c, &r2); if (mp_cmp(&b, &c) || mp_cmp_d(&e, r2)) { printf("\nmp_div_3 => Failure\n"); } } printf("\nPassed div_3 testing"); /* test the DR reduction */ printf("\n\nTesting: mp_dr_reduce...\n"); for (cnt = 2; cnt < 32; cnt++) { printf ("\r%d digit modulus", cnt); mp_grow (&a, cnt); mp_zero (&a); for (ix = 1; ix < cnt; ix++) { a.dp[ix] = MP_MASK; } a.used = cnt; a.dp[0] = 3; mp_rand (&b, cnt - 1); mp_copy (&b, &c); rr = 0; do { if (!(rr & 127)) { printf ("."); fflush (stdout); } mp_sqr (&b, &b); mp_add_d (&b, 1, &b); mp_copy (&b, &c); mp_mod (&b, &a, &b); mp_dr_setup(&a, &mp), mp_dr_reduce (&c, &a, mp); if (mp_cmp (&b, &c) != MP_EQ) { printf ("Failed on trial %u\n", rr); return EXIT_FAILURE; } } while (++rr < 500); printf (" passed"); fflush (stdout); } #if LTM_DEMO_TEST_REDUCE_2K_L /* test the mp_reduce_2k_l code */ #if LTM_DEMO_TEST_REDUCE_2K_L == 1 /* first load P with 2^1024 - 0x2A434 B9FDEC95 D8F9D550 FFFFFFFF FFFFFFFF */ mp_2expt(&a, 1024); mp_read_radix(&b, "2A434B9FDEC95D8F9D550FFFFFFFFFFFFFFFF", 16); mp_sub(&a, &b, &a); #elif LTM_DEMO_TEST_REDUCE_2K_L == 2 /* p = 2^2048 - 0x1 00000000 00000000 00000000 00000000 4945DDBF 8EA2A91D 5776399B B83E188F */ mp_2expt(&a, 2048); mp_read_radix(&b, "1000000000000000000000000000000004945DDBF8EA2A91D5776399BB83E188F", 16); mp_sub(&a, &b, &a); #else #error oops #endif mp_todecimal(&a, buf); printf("\n\np==%s\n", buf); /* now mp_reduce_is_2k_l() should return */ if (mp_reduce_is_2k_l(&a) != 1) { printf("mp_reduce_is_2k_l() return 0, should be 1\n"); return EXIT_FAILURE; } mp_reduce_2k_setup_l(&a, &d); /* now do a million square+1 to see if it varies */ mp_rand(&b, 64); mp_mod(&b, &a, &b); mp_copy(&b, &c); printf("Testing: mp_reduce_2k_l..."); fflush(stdout); for (cnt = 0; cnt < (int)(1UL << 20); cnt++) { mp_sqr(&b, &b); mp_add_d(&b, 1, &b); mp_reduce_2k_l(&b, &a, &d); mp_sqr(&c, &c); mp_add_d(&c, 1, &c); mp_mod(&c, &a, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("mp_reduce_2k_l() failed at step %d\n", cnt); mp_tohex(&b, buf); printf("b == %s\n", buf); mp_tohex(&c, buf); printf("c == %s\n", buf); return EXIT_FAILURE; } } printf("...Passed\n"); #endif /* LTM_DEMO_TEST_REDUCE_2K_L */ #else div2_n = mul2_n = inv_n = expt_n = lcm_n = gcd_n = add_n = sub_n = mul_n = div_n = sqr_n = mul2d_n = div2d_n = cnt = add_d_n = sub_d_n = 0; /* force KARA and TOOM to enable despite cutoffs */ KARATSUBA_SQR_CUTOFF = KARATSUBA_MUL_CUTOFF = 8; TOOM_SQR_CUTOFF = TOOM_MUL_CUTOFF = 16; for (;;) { /* randomly clear and re-init one variable, this has the affect of triming the alloc space */ switch (abs(rand()) % 7) { case 0: mp_clear(&a); mp_init(&a); break; case 1: mp_clear(&b); mp_init(&b); break; case 2: mp_clear(&c); mp_init(&c); break; case 3: mp_clear(&d); mp_init(&d); break; case 4: mp_clear(&e); mp_init(&e); break; case 5: mp_clear(&f); mp_init(&f); break; case 6: break; /* don't clear any */ } printf ("%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu ", add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, expt_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n); ret=fgets(cmd, 4095, stdin); if(!ret){_panic(__LINE__);} cmd[strlen(cmd) - 1] = 0; printf("%-6s ]\r", cmd); fflush(stdout); if (!strcmp(cmd, "mul2d")) { ++mul2d_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} sscanf(buf, "%d", &rr); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_mul_2d(&a, rr, &a); a.sign = b.sign; if (mp_cmp(&a, &b) != MP_EQ) { printf("mul2d failed, rr == %d\n", rr); draw(&a); draw(&b); return EXIT_FAILURE; } } else if (!strcmp(cmd, "div2d")) { ++div2d_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} sscanf(buf, "%d", &rr); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_div_2d(&a, rr, &a, &e); a.sign = b.sign; if (a.used == b.used && a.used == 0) { a.sign = b.sign = MP_ZPOS; } if (mp_cmp(&a, &b) != MP_EQ) { printf("div2d failed, rr == %d\n", rr); draw(&a); draw(&b); return EXIT_FAILURE; } } else if (!strcmp(cmd, "add")) { ++add_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_add(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { printf("add %lu failure!\n", add_n); draw(&a); draw(&b); draw(&c); draw(&d); return EXIT_FAILURE; } /* test the sign/unsigned storage functions */ rr = mp_signed_bin_size(&c); mp_to_signed_bin(&c, (unsigned char *) cmd); memset(cmd + rr, rand() & 255, sizeof(cmd) - rr); mp_read_signed_bin(&d, (unsigned char *) cmd, rr); if (mp_cmp(&c, &d) != MP_EQ) { printf("mp_signed_bin failure!\n"); draw(&c); draw(&d); return EXIT_FAILURE; } rr = mp_unsigned_bin_size(&c); mp_to_unsigned_bin(&c, (unsigned char *) cmd); memset(cmd + rr, rand() & 255, sizeof(cmd) - rr); mp_read_unsigned_bin(&d, (unsigned char *) cmd, rr); if (mp_cmp_mag(&c, &d) != MP_EQ) { printf("mp_unsigned_bin failure!\n"); draw(&c); draw(&d); return EXIT_FAILURE; } } else if (!strcmp(cmd, "sub")) { ++sub_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_sub(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { printf("sub %lu failure!\n", sub_n); draw(&a); draw(&b); draw(&c); draw(&d); return EXIT_FAILURE; } } else if (!strcmp(cmd, "mul")) { ++mul_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_mul(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { printf("mul %lu failure!\n", mul_n); draw(&a); draw(&b); draw(&c); draw(&d); return EXIT_FAILURE; } } else if (!strcmp(cmd, "div")) { ++div_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&d, buf, 64); mp_div(&a, &b, &e, &f); if (mp_cmp(&c, &e) != MP_EQ || mp_cmp(&d, &f) != MP_EQ) { printf("div %lu %d, %d, failure!\n", div_n, mp_cmp(&c, &e), mp_cmp(&d, &f)); draw(&a); draw(&b); draw(&c); draw(&d); draw(&e); draw(&f); return EXIT_FAILURE; } } else if (!strcmp(cmd, "sqr")) { ++sqr_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_copy(&a, &c); mp_sqr(&c, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("sqr %lu failure!\n", sqr_n); draw(&a); draw(&b); draw(&c); return EXIT_FAILURE; } } else if (!strcmp(cmd, "gcd")) { ++gcd_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_gcd(&d, &b, &d); d.sign = c.sign; if (mp_cmp(&c, &d) != MP_EQ) { printf("gcd %lu failure!\n", gcd_n); draw(&a); draw(&b); draw(&c); draw(&d); return EXIT_FAILURE; } } else if (!strcmp(cmd, "lcm")) { ++lcm_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_lcm(&d, &b, &d); d.sign = c.sign; if (mp_cmp(&c, &d) != MP_EQ) { printf("lcm %lu failure!\n", lcm_n); draw(&a); draw(&b); draw(&c); draw(&d); return EXIT_FAILURE; } } else if (!strcmp(cmd, "expt")) { ++expt_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&d, buf, 64); mp_copy(&a, &e); mp_exptmod(&e, &b, &c, &e); if (mp_cmp(&d, &e) != MP_EQ) { printf("expt %lu failure!\n", expt_n); draw(&a); draw(&b); draw(&c); draw(&d); draw(&e); return EXIT_FAILURE; } } else if (!strcmp(cmd, "invmod")) { ++inv_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); mp_invmod(&a, &b, &d); mp_mulmod(&d, &a, &b, &e); if (mp_cmp_d(&e, 1) != MP_EQ) { printf("inv [wrong value from MPI?!] failure\n"); draw(&a); draw(&b); draw(&c); draw(&d); draw(&e); mp_gcd(&a, &b, &e); draw(&e); return EXIT_FAILURE; } } else if (!strcmp(cmd, "div2")) { ++div2_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_div_2(&a, &c); if (mp_cmp(&c, &b) != MP_EQ) { printf("div_2 %lu failure\n", div2_n); draw(&a); draw(&b); draw(&c); return EXIT_FAILURE; } } else if (!strcmp(cmd, "mul2")) { ++mul2_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_mul_2(&a, &c); if (mp_cmp(&c, &b) != MP_EQ) { printf("mul_2 %lu failure\n", mul2_n); draw(&a); draw(&b); draw(&c); return EXIT_FAILURE; } } else if (!strcmp(cmd, "add_d")) { ++add_d_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} sscanf(buf, "%d", &ix); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_add_d(&a, ix, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("add_d %lu failure\n", add_d_n); draw(&a); draw(&b); draw(&c); printf("d == %d\n", ix); return EXIT_FAILURE; } } else if (!strcmp(cmd, "sub_d")) { ++sub_d_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} sscanf(buf, "%d", &ix); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_sub_d(&a, ix, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("sub_d %lu failure\n", sub_d_n); draw(&a); draw(&b); draw(&c); printf("d == %d\n", ix); return EXIT_FAILURE; } } else if (!strcmp(cmd, "exit")) { printf("\nokay, exiting now\n"); break; } } #endif return 0; }