/* reads a unsigned char array, assumes the msb is stored first [big endian] */ int mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c) { int res; /* make sure there are at least two digits */ if (a->alloc < 2) { if ((res = mp_grow(a, 2)) != MP_OKAY) { return res; } } /* zero the int */ mp_zero(a); /* read the bytes in */ while (c-- > 0) { if ((res = mp_mul_2d(a, 8, a)) != MP_OKAY) { return res; } #ifndef MP_8BIT a->dp[0] |= *b++; a->used += 1; #else a->dp[0] = (*b & MP_MASK); a->dp[1] |= ((*b++ >> 7) & 1u); a->used += 2; #endif } mp_clamp(a); return MP_OKAY; }
/* set a 32-bit const */ int mp_set_int (mp_int * a, unsigned long b) { int x, res; mp_zero (a); /* set four bits at a time */ for (x = 0; x < 8; x++) { /* shift the number up four bits */ if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) { return res; } /* OR in the top four bits of the source */ a->dp[0] |= (b >> 28) & 15; /* shift the source up to the next four bits */ b <<= 4; /* ensure that digits are not clamped off */ a->used += 1; } mp_clamp (a); return MP_OKAY; }
static void from_num(MVMnum64 d, mp_int *a) { MVMnum64 d_digit = pow(2, DIGIT_BIT); MVMnum64 da = fabs(d); MVMnum64 upper; MVMnum64 lower; MVMnum64 lowest; MVMnum64 rest; int digits = 0; mp_zero(a); while (da > d_digit * d_digit * d_digit) {; da /= d_digit; digits++; } mp_grow(a, digits + 3); /* populate the top 3 digits */ upper = da / (d_digit*d_digit); rest = fmod(da, d_digit*d_digit); lower = rest / d_digit; lowest = fmod(rest,d_digit ); if (upper >= 1) { mp_set_long(a, (unsigned long) upper); mp_mul_2d(a, DIGIT_BIT , a); DIGIT(a, 0) = (mp_digit) lower; mp_mul_2d(a, DIGIT_BIT , a); } else { if (lower >= 1) { mp_set_long(a, (unsigned long) lower); mp_mul_2d(a, DIGIT_BIT , a); a->used = 2; } else { a->used = 1; } } DIGIT(a, 0) = (mp_digit) lowest; /* shift the rest */ mp_mul_2d(a, DIGIT_BIT * digits, a); if (d < 0) mp_neg(a, a); mp_clamp(a); mp_shrink(a); }
Object* UnMarshaller::get_positive_varint() { bool done; unsigned long val = get_varint(&done); bool is_fixnum = done; mp_int mp_val; // do we need to switch to bignum math? if(!done) { int shift = sizeof(long) * 7; mp_int a; mp_init_set_int(&mp_val, val); mp_init(&a); #if (__WORDSIZE == 64) // mp_(init_)set_int can only deal with 32 bit values, // so the above call only copied the lower 32 bits of _val_. // Handle the upper 32 bits as well: mp_set_int(&a, val >> 32); mp_mul_2d(&a, 32, &a); mp_add(&a, &mp_val, &mp_val); #endif while(!done) { unsigned int byte = stream.get(); mp_set_int(&a, byte & ~128); mp_mul_2d(&a, shift, &a); mp_add(&a, &mp_val, &mp_val); shift += 7; done = byte < 128; } mp_clear(&a); }
static void two_complement_shl(mp_int *result, mp_int *value, MVMint64 count) { if (count >= 0) { mp_mul_2d(value, count, result); } else if (MP_NEG == SIGN(value)) { /* fake two's complement semantics on top of sign-magnitude * algorithm appears to work [citation needed] */ mp_add_d(value, 1, result); mp_div_2d(result, -count, result, NULL); mp_sub_d(result, 1, result); } else { mp_div_2d(value, -count, result, NULL); } }
/* based on gmp's mpz_import. * see http://gmplib.org/manual/Integer-Import-and-Export.html */ int mp_import(mp_int* rop, size_t count, int order, size_t size, int endian, size_t nails, const void* op) { int result; size_t odd_nails, nail_bytes, i, j; unsigned char odd_nail_mask; mp_zero(rop); if (endian == 0) { union { unsigned int i; char c[4]; } lint; lint.i = 0x01020304; endian = (lint.c[0] == 4) ? -1 : 1; } odd_nails = (nails % 8); odd_nail_mask = 0xff; for (i = 0; i < odd_nails; ++i) { odd_nail_mask ^= (1 << (7 - i)); } nail_bytes = nails / 8; for (i = 0; i < count; ++i) { for (j = 0; j < (size - nail_bytes); ++j) { unsigned char byte = *( (unsigned char*)op + (((order == 1) ? i : ((count - 1) - i)) * size) + ((endian == 1) ? (j + nail_bytes) : (((size - 1) - j) - nail_bytes)) ); if ( (result = mp_mul_2d(rop, ((j == 0) ? (8 - odd_nails) : 8), rop)) != MP_OKAY) { return result; } rop->dp[0] |= (j == 0) ? (byte & odd_nail_mask) : byte; rop->used += 1; } } mp_clamp(rop); return MP_OKAY; }
unsigned char *cli_decodesig(const char *sig, unsigned int plen, mp_int e, mp_int n) { int i, slen = strlen(sig), dec; unsigned char *plain; mp_int r, p, c; mp_init(&r); mp_init(&c); for(i = 0; i < slen; i++) { if((dec = cli_ndecode(sig[i])) < 0) { mp_clear(&r); mp_clear(&c); return NULL; } mp_set_int(&r, dec); mp_mul_2d(&r, 6 * i, &r); mp_add(&r, &c, &c); } plain = (unsigned char *) cli_calloc(plen + 1, sizeof(unsigned char)); if(!plain) { cli_errmsg("cli_decodesig: Can't allocate memory for 'plain'\n"); mp_clear(&r); mp_clear(&c); return NULL; } mp_init(&p); mp_exptmod(&c, &e, &n, &p); /* plain = cipher^e mod n */ mp_clear(&c); mp_set_int(&c, 256); for(i = plen - 1; i >= 0; i--) { /* reverse */ mp_div(&p, &c, &p, &r); plain[i] = mp_get_int(&r); } mp_clear(&c); mp_clear(&p); mp_clear(&r); return plain; }
/* reads a unsigned char array, assumes the msb is stored first [big endian] */ int mp_read_unsigned_bin (mp_int * a, unsigned char *b, int c) { int res; mp_zero (a); while (c-- > 0) { if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { return res; } if (DIGIT_BIT != 7) { a->dp[0] |= *b++; a->used += 1; } else { a->dp[0] = (*b & MP_MASK); a->dp[1] |= ((*b++ >> 7U) & 1); a->used += 2; } } mp_clamp (a); return MP_OKAY; }
int mpf_normalize(mp_float *a) { long cb, diff; int err; mp_digit c; /* sanity */ if (a->radix < 2) { return MP_VAL; } cb = mp_count_bits(&(a->mantissa)); if (cb > a->radix) { diff = cb - a->radix; a->exp += diff; /* round it, add 1 after shift if diff-1'th bit is 1 */ c = a->mantissa.dp[diff/DIGIT_BIT] & (1U<<(diff%DIGIT_BIT)); if ((err = mp_div_2d(&(a->mantissa), diff, &(a->mantissa), NULL)) != MP_OKAY) { return err; } if (c != 0) { return mp_add_d(&(a->mantissa), 1, &(a->mantissa)); } else { return MP_OKAY; } } else if (cb < a->radix) { if (mp_iszero(&(a->mantissa)) == MP_YES) { return mpf_const_0(a); } else { diff = a->radix - cb; a->exp -= diff; return mp_mul_2d(&(a->mantissa), diff, &(a->mantissa)); } } return MP_OKAY; }
void bn_double2int (double a, mp_int *b) { const unsigned int FRAC_BITS = 52; int ret, exp; long int val; double frac; mp_int upper, number; assert (a >= 0); ret = mp_init_multi (b, &number, &upper, NULL); if (ret != MP_OKAY) Fatal (1, error, "Error initializing number"); mp_set (&upper, 1); frac = frexp (a, &exp); ret = mp_mul_2d (&upper, exp, &upper); if (ret != MP_OKAY) Fatal (1, error, "Error initializing number"); for (unsigned int i = 0; i < FRAC_BITS; i++) { frac = frac * 2; val = lround (floor (frac)); assert (val == 0 || val == 1); frac = frac - lround (floor (frac)); if (val == 1) { mp_div_2d (&upper, i + 1, &number, NULL); if (ret != MP_OKAY) Fatal (1, error, "Error dividing numbers"); mp_add (b, &number, b); if (ret != MP_OKAY) Fatal (1, error, "Error adding numbers"); } } mp_clear_multi (&number, &upper, NULL); }
/* Taken from mp_set_long, but portably accepts a 64-bit number. */ int MVM_bigint_mp_set_uint64(mp_int * a, MVMuint64 b) { int x, res; mp_zero (a); /* set four bits at a time */ for (x = 0; x < sizeof(MVMuint64) * 2; x++) { /* shift the number up four bits */ if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) { return res; } /* OR in the top four bits of the source */ a->dp[0] |= (b >> ((sizeof(MVMuint64)) * 8 - 4)) & 15; /* shift the source up to the next four bits */ b <<= 4; /* ensure that digits are not clamped off */ a->used += 1; } mp_clamp(a); return MP_OKAY; }
int mp_toom_cook_5_mul(mp_int *a, mp_int *b, mp_int *c) { mp_int w1, w2, w3, w4, w5, w6, w7, w8, w9; mp_int tmp1, tmp2; mp_int a0, a1, a2, a3, a4; mp_int b0, b1, b2, b3, b4; int e = MP_OKAY; int B, count, sign; B = (MAX(a->used, b->used)) / 5; sign = (a->sign != b->sign) ? MP_NEG : MP_ZPOS; if (MIN(a->used, b->used) < TOOM_COOK_5_MUL_CO) { if ((e = mp_mul(a, b, c)) != MP_OKAY) { return e; } c->sign = sign; return MP_OKAY; } if ((e = mp_init_multi(&w1, &w2, &w3, &w4, &w5, &w6, &w7, &w8, &w9, &tmp1, &tmp2, //&a0, &a1, &a2, &a3, &a4, &b0, &b1, &b2, &b3, &b4, NULL)) != MP_OKAY) { goto ERR0; //goto ERR; } if ((e = mp_init_size(&a0, B)) != MP_OKAY) { goto ERRa0; } if ((e = mp_init_size(&a1, B)) != MP_OKAY) { goto ERRa1; } if ((e = mp_init_size(&a2, B)) != MP_OKAY) { goto ERRa2; } if ((e = mp_init_size(&a3, B)) != MP_OKAY) { goto ERRa3; } if ((e = mp_init_size(&a4, B)) != MP_OKAY) { goto ERRa4; } if ((e = mp_init_size(&b0, B)) != MP_OKAY) { goto ERRb0; } if ((e = mp_init_size(&b1, B)) != MP_OKAY) { goto ERRb1; } if ((e = mp_init_size(&b2, B)) != MP_OKAY) { goto ERRb2; } if ((e = mp_init_size(&b3, B)) != MP_OKAY) { goto ERRb3; } if ((e = mp_init_size(&b4, B)) != MP_OKAY) { goto ERRb4; } // A = a4*x^4 + a3*x^3 + a2*x^2 + a1*x + a0 for (count = 0; count < a->used; count++) { switch (count / B) { case 0: a0.dp[count] = a->dp[count]; a0.used++; break; case 1: a1.dp[count - B] = a->dp[count]; a1.used++; break; case 2: a2.dp[count - 2 * B] = a->dp[count]; a2.used++; break; case 3: a3.dp[count - 3 * B] = a->dp[count]; a3.used++; break; case 4: a4.dp[count - 4 * B] = a->dp[count]; a4.used++; break; default: a4.dp[count - 4 * B] = a->dp[count]; a4.used++; break; } } mp_clamp(&a0); mp_clamp(&a1); mp_clamp(&a2); mp_clamp(&a3); mp_clamp(&a4); // B = b4*x^4 + b3*x^3 + b2*x^2 + b1*x + b0 for (count = 0; count < b->used; count++) { switch (count / B) { case 0: b0.dp[count] = b->dp[count]; b0.used++; break; case 1: b1.dp[count - B] = b->dp[count]; b1.used++; break; case 2: b2.dp[count - 2 * B] = b->dp[count]; b2.used++; break; case 3: b3.dp[count - 3 * B] = b->dp[count]; b3.used++; break; case 4: b4.dp[count - 4 * B] = b->dp[count]; b4.used++; break; default: b4.dp[count - 4 * B] = b->dp[count]; b4.used++; break; } } mp_clamp(&b0); mp_clamp(&b1); mp_clamp(&b2); mp_clamp(&b3); mp_clamp(&b4); /* if ((e = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { goto ERR; } if ((e = mp_copy(a, &a1)) != MP_OKAY) { goto ERR; } mp_rshd(&a1, B); mp_mod_2d(&a1, DIGIT_BIT * B, &a1); if ((e = mp_copy(a, &a2)) != MP_OKAY) { goto ERR; } mp_rshd(&a2, B * 2); mp_mod_2d(&a2, DIGIT_BIT * B, &a2); if ((e = mp_copy(a, &a3)) != MP_OKAY) { goto ERR; } mp_rshd(&a3, B * 3); mp_mod_2d(&a3, DIGIT_BIT * B, &a3); if ((e = mp_copy(a, &a4)) != MP_OKAY) { goto ERR; } mp_rshd(&a4, B * 4); if ((e = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) { goto ERR; } if ((e = mp_copy(a, &b1)) != MP_OKAY) { goto ERR; } mp_rshd(&b1, B); mp_mod_2d(&b1, DIGIT_BIT * B, &b1); if ((e = mp_copy(b, &b2)) != MP_OKAY) { goto ERR; } mp_rshd(&b2, B * 2); mp_mod_2d(&b2, DIGIT_BIT * B, &b2); if ((e = mp_copy(b, &b3)) != MP_OKAY) { goto ERR; } mp_rshd(&b3, B * 3); mp_mod_2d(&b3, DIGIT_BIT * B, &b3); if ((e = mp_copy(b, &b4)) != MP_OKAY) { goto ERR; } mp_rshd(&b4, B * 4); */ // S1 = a4*b4 if ((e = mp_mul(&a4, &b4, &w1)) != MP_OKAY) { goto ERR; } // S9 = a0*b0 if ((e = mp_mul(&a0, &b0, &w9)) != MP_OKAY) { goto ERR; } // S2 = (a0- 2*a1 +4*a2 -8*a3 +16*a4) if ((e = mp_mul_2d(&a1, 1, &tmp1)) != MP_OKAY) { goto ERR; } // 2*a1 = tmp1 if ((e = mp_sub(&a0, &tmp1, &w2)) != MP_OKAY) { goto ERR; } // a0- 2*a1 = a0 - tmp1 = w2 if ((e = mp_mul_2d(&a2, 2, &tmp1)) != MP_OKAY) { goto ERR; } // 4*a2 = tmp1 if ((e = mp_add(&w2, &tmp1, &w2)) != MP_OKAY) { goto ERR; } // a0- 2*a1 +4*a2 = w2 + tmp1 = w2 if ((e = mp_mul_2d(&a3, 3, &tmp1)) != MP_OKAY) { goto ERR; } // 8*a3 = tmp1 if ((e = mp_sub(&w2, &tmp1, &w2)) != MP_OKAY) { goto ERR; } // a0- 2*a1 +4*a2 -8*a3 = w2 - tmp1 = w2 if ((e = mp_mul_2d(&a4, 4, &tmp1)) != MP_OKAY) { goto ERR; } // 16*a4 = tmp1 if ((e = mp_add(&w2, &tmp1, &w2)) != MP_OKAY) { goto ERR; } // a0- 2*a1 +4*a2 -8*a3 +16*a4 = w2 + tmp1 = w2 // * (b0- 2*b1 +4*b2 -8*b3 +16*b4) if ((e = mp_mul_2d(&b1, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&b0, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b3, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b4, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp2, &w2, &w2)) != MP_OKAY) { goto ERR; } // S5 = (a0+ 2*a1+ 4*a2+ 8*a3+ 16*a4) if ((e = mp_mul_2d(&a1, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&a0, &tmp1, &w5)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w5, &tmp1, &w5)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a3, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w5, &tmp1, &w5)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a4, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w5, &tmp1, &w5)) != MP_OKAY) { goto ERR; } // *(b0+ 2*b1+ 4*b2+ 8*b3+ 16*b4) if ((e = mp_mul_2d(&b1, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&b0, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b3, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b4, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp2, &w5, &w5)) != MP_OKAY) { goto ERR; } // S3 = (a4+ 2*a3+ 4*a2+ 8*a1+ 16*a0) if ((e = mp_mul_2d(&a3, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&a4, &tmp1, &w3)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w3, &tmp1, &w3)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a1, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w3, &tmp1, &w3)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a0, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w3, &tmp1, &w3)) != MP_OKAY) { goto ERR; } // * (b4+ 2*b3+ 4*b2+ 8*b1+ 16*b0) if ((e = mp_mul_2d(&b3, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&b4, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b1, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b0, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp2, &w3, &w3)) != MP_OKAY) { goto ERR; } // S8 = (a4- 2*a3+ 4*a2- 8*a1+ 16*a0) if ((e = mp_mul_2d(&a3, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&a4, &tmp1, &w8)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w8, &tmp1, &w8)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a1, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w8, &tmp1, &w8)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a0, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w8, &tmp1, &w8)) != MP_OKAY) { goto ERR; } //* (b4- 2*b3+ 4*b2- 8*b1+ 16*b0) if ((e = mp_mul_2d(&b3, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&b4, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b1, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b0, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp2, &w8, &w8)) != MP_OKAY) { goto ERR; } // S4 = (a0+ 4*a1+ 16*a2+ 64*a3+ 256*a4) if ((e = mp_mul_2d(&a1, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&a0, &tmp1, &w4)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a2, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a3, 6, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a4, 8, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } //* (b0+ 4*b1+ 16*b2+ 64*b3+ 256*b4) if ((e = mp_mul_2d(&b1, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&b0, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b2, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b3, 6, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b4, 8, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp2, &w4, &w4)) != MP_OKAY) { goto ERR; } // S6 = (a0- a1+ a2- a3 +a4) if ((e = mp_sub(&a0, &a1, &w6)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w6, &a2, &w6)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w6, &a3, &w6)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w6, &a4, &w6)) != MP_OKAY) { goto ERR; } // * (b0- b1+ b2- b3+ b4) if ((e = mp_sub(&b0, &b1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &b2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&tmp1, &b3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &b4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp1, &w6, &w6)) != MP_OKAY) { goto ERR; } // S7 = (a0+ a1+ a2+ a3+ a4) if ((e = mp_add(&a0, &a1, &w7)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w7, &a2, &w7)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w7, &a3, &w7)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w7, &a4, &w7)) != MP_OKAY) { goto ERR; } // * (b0+ b1+ b2+ b3+ b4) if ((e = mp_add(&b0, &b1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &b2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &b3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &b4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp1, &w7, &w7)) != MP_OKAY) { goto ERR; } // S6 -= S7 if ((e = mp_sub(&w6, &w7, &w6)) != MP_OKAY) { goto ERR; } // S2 -= S5 if ((e = mp_sub(&w2, &w5, &w2)) != MP_OKAY) { goto ERR; } // S4 -= S9 if ((e = mp_sub(&w4, &w9, &w4)) != MP_OKAY) { goto ERR; } // S4 -= (2^16*S1) if ((e = mp_mul_2d(&w1, 16, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } // S8 -= S3 if ((e = mp_sub(&w8, &w3, &w8)) != MP_OKAY) { goto ERR; } // S6 /= 2 if ((e = mp_div_2d(&w6, 1, &w6, NULL)) != MP_OKAY) { goto ERR; } // S5 *= 2 if ((e = mp_mul_2d(&w5, 1, &w5)) != MP_OKAY) { goto ERR; } // S5 += S2 if ((e = mp_add(&w5, &w2, &w5)) != MP_OKAY) { goto ERR; } // S2 = -S2 if ((e = mp_neg(&w2, &w2)) != MP_OKAY) { goto ERR; } // S8 = -S8 if ((e = mp_neg(&w8, &w8)) != MP_OKAY) { goto ERR; } // S7 += S6 if ((e = mp_add(&w7, &w6, &w7)) != MP_OKAY) { goto ERR; } // S6 = -S6 if ((e = mp_neg(&w6, &w6)) != MP_OKAY) { goto ERR; } // S3 -= S7 if ((e = mp_sub(&w3, &w7, &w3)) != MP_OKAY) { goto ERR; } // S5 -= (512*S7) if ((e = mp_mul_2d(&w7, 9, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w5, &tmp1, &w5)) != MP_OKAY) { goto ERR; } // S3 *= 2 if ((e = mp_mul_2d(&w3, 1, &w3)) != MP_OKAY) { goto ERR; } // S3 -= S8 if ((e = mp_sub(&w3, &w8, &w3)) != MP_OKAY) { goto ERR; } // S7 -= S1 if ((e = mp_sub(&w7, &w1, &w7)) != MP_OKAY) { goto ERR; } // S7 -= S9 if ((e = mp_sub(&w7, &w9, &w7)) != MP_OKAY) { goto ERR; } // S8 += S2 if ((e = mp_add(&w8, &w2, &w8)) != MP_OKAY) { goto ERR; } // S5 += S3 if ((e = mp_add(&w5, &w3, &w5)) != MP_OKAY) { goto ERR; } // S8 -= (80*S6) if ((e = mp_mul_d(&w6, 80, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w8, &tmp1, &w8)) != MP_OKAY) { goto ERR; } // S3 -= (510*S9) if ((e = mp_mul_d(&w9, 510, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { goto ERR; } // S4 -= S2 if ((e = mp_sub(&w4, &w2, &w4)) != MP_OKAY) { goto ERR; } // S3 *= 3 if ((e = mp_mul_d(&w3, 3, &w3)) != MP_OKAY) { goto ERR; } // S3 += S5 if ((e = mp_add(&w3, &w5, &w3)) != MP_OKAY) { goto ERR; } // S8 /= 180 \\ division by 180 if ((e = mp_div_d(&w8, 180, &w8, NULL)) != MP_OKAY) { goto ERR; } // S5 += (378*S7) if ((e = mp_mul_d(&w7, 378, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w5, &tmp1, &w5)) != MP_OKAY) { goto ERR; } // S2 /= 4 if ((e = mp_div_2d(&w2, 2, &w2, NULL)) != MP_OKAY) { goto ERR; } // S6 -= S2 if ((e = mp_sub(&w6, &w2, &w6)) != MP_OKAY) { goto ERR; } // S5 /= (-72) \\ division by -72 if ((e = mp_div_d(&w5, 72, &w5, NULL)) != MP_OKAY) { goto ERR; } if (&w5.sign == MP_ZPOS) (&w5)->sign = MP_NEG; (&w5)->sign = MP_ZPOS; // S3 /= (-360) \\ division by -360 if ((e = mp_div_d(&w3, 360, &w3, NULL)) != MP_OKAY) { goto ERR; } if (&w3.sign == MP_ZPOS) (&w3)->sign = MP_NEG; (&w3)->sign = MP_ZPOS; // S2 -= S8 if ((e = mp_sub(&w2, &w8, &w2)) != MP_OKAY) { goto ERR; } // S7 -= S3 if ((e = mp_sub(&w7, &w3, &w7)) != MP_OKAY) { goto ERR; } // S4 -= (256*S5) if ((e = mp_mul_2d(&w5, 8, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } // S3 -= S5 if ((e = mp_sub(&w3, &w5, &w3)) != MP_OKAY) { goto ERR; } // S4 -= (4096*S3) if ((e = mp_mul_2d(&w3, 12, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } // S4 -= (16*S7) if ((e = mp_mul_2d(&w7, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } // S4 += (256*S6) if ((e = mp_mul_2d(&w6, 8, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } // S6 += S2 if ((e = mp_add(&w6, &w2, &w6)) != MP_OKAY) { goto ERR; } // S2 *= 180 if ((e = mp_mul_d(&w2, 180, &w2)) != MP_OKAY) { goto ERR; } // S2 += S4 if ((e = mp_add(&w2, &w4, &w2)) != MP_OKAY) { goto ERR; } // S2 /= 11340 \\ division by 11340 if ((e = mp_div_d(&w2, 11340, &w2, NULL)) != MP_OKAY) { goto ERR; } // S4 += (720*S6) if ((e = mp_mul_d(&w6, 720, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } // S4 /= (-2160) \\ division by -2160 if ((e = mp_div_d(&w4, 2160, &w4, NULL)) != MP_OKAY) { goto ERR; } if (&w4.sign == MP_ZPOS) (&w4)->sign = MP_NEG; (&w4)->sign = MP_ZPOS; // S6 -= S4 if ((e = mp_sub(&w6, &w4, &w6)) != MP_OKAY) { goto ERR; } // S8 -= S2 if ((e = mp_sub(&w8, &w2, &w8)) != MP_OKAY) { goto ERR; } // P = S1*x^8 + S2*x^7 + S3*x^6 + S4*x^5 + S5*x^4 + S6*x^3 + S7*x^2 + S8*x + S9 if ((e = mp_copy(&w9, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w8, B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w8, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w7, 2 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w7, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w6, 3 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w6, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w5, 4 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w5, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w4, 5 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w3, 6 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w2, 7 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w1, 8 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w1, c)) != MP_OKAY) { goto ERR; } // P - A*B \\ == zero c->sign = sign; ERR: ERRb4: mp_clear(&b4); ERRb3: mp_clear(&b3); ERRb2: mp_clear(&b2); ERRb1: mp_clear(&b1); ERRb0: mp_clear(&b0); ERRa4: mp_clear(&a4); ERRa3: mp_clear(&a3); ERRa2: mp_clear(&a2); ERRa1: mp_clear(&a1); ERRa0: mp_clear(&a0); ERR0: mp_clear_multi(&w1, &w2, &w3, &w4, &w5, &w6, &w7, &w8, &w9, &tmp1, &tmp2, // &a0, &a1, &a2, &a3, &a4, &b0, &b1, &b2, &b3, &b4, NULL); return e; }
/* two complement and */ int mp_tc_and(const mp_int *a, const mp_int *b, mp_int *c) { int res = MP_OKAY, bits, abits, bbits; int sa = a->sign, sb = b->sign; mp_int *mx = NULL, _mx, acpy, bcpy; if ((sa == MP_NEG) || (sb == MP_NEG)) { abits = mp_count_bits(a); bbits = mp_count_bits(b); bits = MP_MAX(abits, bbits); res = mp_init_set_int(&_mx, 1uL); if (res != MP_OKAY) { goto end; } mx = &_mx; res = mp_mul_2d(mx, bits + 1, mx); if (res != MP_OKAY) { goto end; } if (sa == MP_NEG) { res = mp_init(&acpy); if (res != MP_OKAY) { goto end; } res = mp_add(mx, a, &acpy); if (res != MP_OKAY) { mp_clear(&acpy); goto end; } a = &acpy; } if (sb == MP_NEG) { res = mp_init(&bcpy); if (res != MP_OKAY) { goto end; } res = mp_add(mx, b, &bcpy); if (res != MP_OKAY) { mp_clear(&bcpy); goto end; } b = &bcpy; } } res = mp_and(a, b, c); if ((sa == MP_NEG) && (sb == MP_NEG) && (res == MP_OKAY)) { res = mp_sub(c, mx, c); } end: if (a == &acpy) { mp_clear(&acpy); } if (b == &bcpy) { mp_clear(&bcpy); } if (mx == &_mx) { mp_clear(mx); } return res; }
/* slower bit-bang division... also smaller */ int mp_div MPA(mp_int * a, mp_int * b, mp_int * c, mp_int * d) { mp_int ta, tb, tq, q; int res, n, n2; /* is divisor zero ? */ if (mp_iszero (b) == 1) { return MP_VAL; } /* if a < b then q=0, r = a */ if (mp_cmp_mag (a, b) == MP_LT) { if (d != NULL) { res = mp_copy (a, d); } else { res = MP_OKAY; } if (c != NULL) { mp_zero (c); } return res; } /* init our temps */ if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) { return res; } mp_set(&tq, 1); n = mp_count_bits(a) - mp_count_bits(b); if (((res = mp_abs(a, &ta)) != MP_OKAY) || ((res = mp_abs(b, &tb)) != MP_OKAY) || ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { goto LBL_ERR; } while (n-- >= 0) { if (mp_cmp(&tb, &ta) != MP_GT) { if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { goto LBL_ERR; } } if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) { goto LBL_ERR; } } /* now q == quotient and ta == remainder */ n = a->sign; n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG); if (c != NULL) { mp_exch(c, &q); c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2; } if (d != NULL) { mp_exch(d, &ta); d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; } LBL_ERR: mp_clear_multi(&ta, &tb, &tq, &q, NULL); return res; }
// http://www.jjj.de/fxt/#fxtbook static int machin_ln_10(mp_float * a) { int err; long oldeps, eps; mp_int c1, c2, c3, a1, a2, a3, sum, zero, t1, t2, P, Q, R, EPS; oldeps = a->radix; eps = (oldeps + MP_DIGIT_BIT); // TODO: error calculation! err = MP_OKAY; if ((err = mp_init_multi(&c1, &c2, &c3, &a1, &a2, &a3, &sum, &zero, &t1, &t2, &EPS, &P, &Q, &R, NULL)) != MP_OKAY) { return err; } if ((err = mp_set_int(&EPS, (unsigned long) (eps))) != MP_OKAY) { goto _ERR; } // using acoth instead of atanh to make things simpler // atanh(x) = acoth(1/x) for x > 1 // coefficients due to P. Sebah "Machin like formulae for logarithm" (1997) // http://numbers.computation.free.fr/Constants/PiProgram/userconstants.html mp_set(&c1, 46); mp_set(&c2, 34); mp_set(&c3, 20); mp_set(&a1, 31); mp_set(&a2, 49); mp_set(&a3, 161); // http://oeis.org/A175607 mp_zero(&sum); mp_zero(&zero); if ((err = mp_acoth_binary_splitting(&a1, &zero, &EPS, &P, &Q, &R)) != MP_OKAY) { goto _ERR; } if ((err = mp_add(&P, &Q, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul_2d(&t1, eps, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&Q, &a1, &t2)) != MP_OKAY) { goto _ERR; } if ((err = mp_div(&t1, &t2, &t1, NULL)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&t1, &c1, &sum)) != MP_OKAY) { goto _ERR; } if ((err = mp_acoth_binary_splitting(&a2, &zero, &EPS, &P, &Q, &R)) != MP_OKAY) { goto _ERR; } if ((err = mp_add(&P, &Q, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul_2d(&t1, eps, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&Q, &a2, &t2)) != MP_OKAY) { goto _ERR; } if ((err = mp_div(&t1, &t2, &t1, NULL)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&t1, &c2, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_add(&sum, &t1, &sum)) != MP_OKAY) { goto _ERR; } if ((err = mp_acoth_binary_splitting(&a3, &zero, &EPS, &P, &Q, &R)) != MP_OKAY) { goto _ERR; } if ((err = mp_add(&P, &Q, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul_2d(&t1, eps, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&Q, &a3, &t2)) != MP_OKAY) { goto _ERR; } if ((err = mp_div(&t1, &t2, &t1, NULL)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&t1, &c3, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_add(&sum, &t1, &sum)) != MP_OKAY) { goto _ERR; } if ((err = mpf_from_mp_int(&sum, a)) != MP_OKAY) { goto _ERR; } a->exp -= eps; _ERR: mp_clear_multi(&c1, &c2, &c3, &a1, &a2, &a3, &sum, &zero, &t1, &t2, &EPS, &P, &Q, &R, NULL); return err; }
/* 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; }
/* integer signed division. * c*b + d == a [e.g. a/b, c=quotient, d=remainder] * HAC pp.598 Algorithm 14.20 * * Note that the description in HAC is horribly * incomplete. For example, it doesn't consider * the case where digits are removed from 'x' in * the inner loop. It also doesn't consider the * case that y has fewer than three digits, etc.. * * The overall algorithm is as described as * 14.20 from HAC but fixed to treat these cases. */ int mp_div MPA(mp_int * a, mp_int * b, mp_int * c, mp_int * d) { mp_int q, x, y, t1, t2; int res, n, t, i, norm, neg; /* is divisor zero ? */ if (mp_iszero (b) == 1) { return MP_VAL; } /* if a < b then q=0, r = a */ if (mp_cmp_mag (a, b) == MP_LT) { if (d != NULL) { res = mp_copy (MPST, a, d); } else { res = MP_OKAY; } if (c != NULL) { mp_zero (c); } return res; } if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { return res; } q.used = a->used + 2; if ((res = mp_init (&t1)) != MP_OKAY) { goto LBL_Q; } if ((res = mp_init (&t2)) != MP_OKAY) { goto LBL_T1; } if ((res = mp_init_copy (MPST, &x, a)) != MP_OKAY) { goto LBL_T2; } if ((res = mp_init_copy (MPST, &y, b)) != MP_OKAY) { goto LBL_X; } /* fix the sign */ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; x.sign = y.sign = MP_ZPOS; /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ norm = mp_count_bits(&y) % DIGIT_BIT; if (norm < (int)(DIGIT_BIT-1)) { norm = (DIGIT_BIT-1) - norm; if ((res = mp_mul_2d (MPST, &x, norm, &x)) != MP_OKAY) { goto LBL_Y; } if ((res = mp_mul_2d (MPST, &y, norm, &y)) != MP_OKAY) { goto LBL_Y; } } else { norm = 0; } /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ n = x.used - 1; t = y.used - 1; /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ if ((res = mp_lshd (MPST, &y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ goto LBL_Y; } while (mp_cmp (&x, &y) != MP_LT) { ++(q.dp[n - t]); if ((res = mp_sub (MPST, &x, &y, &x)) != MP_OKAY) { goto LBL_Y; } } /* reset y by shifting it back down */ mp_rshd (&y, n - t); /* step 3. for i from n down to (t + 1) */ for (i = n; i >= (t + 1); i--) { if (i > x.used) { continue; } /* step 3.1 if xi == yt then set q{i-t-1} to b-1, * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ if (x.dp[i] == y.dp[t]) { q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); } else { mp_word tmp; tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); tmp |= ((mp_word) x.dp[i - 1]); tmp /= ((mp_word) y.dp[t]); if (tmp > (mp_word) MP_MASK) tmp = MP_MASK; q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); } /* while (q{i-t-1} * (yt * b + y{t-1})) > xi * b**2 + xi-1 * b + xi-2 do q{i-t-1} -= 1; */ q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; do { q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; /* find left hand */ mp_zero (&t1); t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; t1.dp[1] = y.dp[t]; t1.used = 2; if ((res = mp_mul_d (MPST, &t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { goto LBL_Y; } /* find right hand */ t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; t2.dp[2] = x.dp[i]; t2.used = 3; } while (mp_cmp_mag(&t1, &t2) == MP_GT); /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ if ((res = mp_mul_d (MPST, &y, q.dp[i - t - 1], &t1)) != MP_OKAY) { goto LBL_Y; } if ((res = mp_lshd (MPST, &t1, i - t - 1)) != MP_OKAY) { goto LBL_Y; } if ((res = mp_sub (MPST, &x, &t1, &x)) != MP_OKAY) { goto LBL_Y; } /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ if (x.sign == MP_NEG) { if ((res = mp_copy (MPST, &y, &t1)) != MP_OKAY) { goto LBL_Y; } if ((res = mp_lshd (MPST, &t1, i - t - 1)) != MP_OKAY) { goto LBL_Y; } if ((res = mp_add (MPST, &x, &t1, &x)) != MP_OKAY) { goto LBL_Y; } q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; } } /* now q is the quotient and x is the remainder * [which we have to normalize] */ /* get sign before writing to c */ x.sign = x.used == 0 ? MP_ZPOS : a->sign; if (c != NULL) { mp_clamp (&q); mp_managed_copy (MPST, &q, c); c->sign = neg; } if (d != NULL) { mp_div_2d (MPST, &x, norm, &x, NULL); mp_managed_copy (MPST, &x, d); } res = MP_OKAY; LBL_Y:mp_clear (&y); LBL_X:mp_clear (&x); LBL_T2:mp_clear (&t2); LBL_T1:mp_clear (&t1); LBL_Q:mp_clear (&q); return res; }
/* Greatest Common Divisor using the binary method [Algorithm B, page 338, vol2 of TAOCP] */ int mp_gcd (mp_int * a, mp_int * b, mp_int * c) { mp_int u, v, t; int k, res, neg; /* either zero than gcd is the largest */ if (mp_iszero (a) == 1 && mp_iszero (b) == 0) { return mp_copy (b, c); } if (mp_iszero (a) == 0 && mp_iszero (b) == 1) { return mp_copy (a, c); } if (mp_iszero (a) == 1 && mp_iszero (b) == 1) { mp_set (c, 1); return MP_OKAY; } /* if both are negative they share (-1) as a common divisor */ neg = (a->sign == b->sign) ? a->sign : MP_ZPOS; if ((res = mp_init_copy (&u, a)) != MP_OKAY) { return res; } if ((res = mp_init_copy (&v, b)) != MP_OKAY) { goto __U; } /* must be positive for the remainder of the algorithm */ u.sign = v.sign = MP_ZPOS; if ((res = mp_init (&t)) != MP_OKAY) { goto __V; } /* B1. Find power of two */ k = 0; while (mp_iseven(&u) == 1 && mp_iseven(&v) == 1) { ++k; if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { goto __T; } if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { goto __T; } } /* B2. Initialize */ if (mp_isodd(&u) == 1) { /* t = -v */ if ((res = mp_copy (&v, &t)) != MP_OKAY) { goto __T; } t.sign = MP_NEG; } else { /* t = u */ if ((res = mp_copy (&u, &t)) != MP_OKAY) { goto __T; } } do { /* B3 (and B4). Halve t, if even */ while (t.used != 0 && mp_iseven(&t) == 1) { if ((res = mp_div_2 (&t, &t)) != MP_OKAY) { goto __T; } } /* B5. if t>0 then u=t otherwise v=-t */ if (t.used != 0 && t.sign != MP_NEG) { if ((res = mp_copy (&t, &u)) != MP_OKAY) { goto __T; } } else { if ((res = mp_copy (&t, &v)) != MP_OKAY) { goto __T; } v.sign = (v.sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; } /* B6. t = u - v, if t != 0 loop otherwise terminate */ if ((res = mp_sub (&u, &v, &t)) != MP_OKAY) { goto __T; } } while (mp_iszero(&t) == 0); /* multiply by 2^k which we divided out at the beginning */ if ((res = mp_mul_2d (&u, k, &u)) != MP_OKAY) { goto __T; } mp_exch (&u, c); c->sign = neg; res = MP_OKAY; __T: mp_clear (&t); __V: mp_clear (&u); __U: mp_clear (&v); return res; }
/* 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; }
/* two complement or */ int mp_tc_or(const mp_int *a, const mp_int *b, mp_int *c) { int res = MP_OKAY, bits; int as = mp_isneg(a), bs = mp_isneg(b); mp_int *mx = NULL, _mx, acpy, bcpy; if ((as != MP_NO) || (bs != MP_NO)) { bits = MAX(mp_count_bits(a), mp_count_bits(b)); res = mp_init_set_int(&_mx, 1uL); if (res != MP_OKAY) { goto end; } mx = &_mx; res = mp_mul_2d(mx, bits + 1, mx); if (res != MP_OKAY) { goto end; } if (as != MP_NO) { res = mp_init(&acpy); if (res != MP_OKAY) { goto end; } res = mp_add(mx, a, &acpy); if (res != MP_OKAY) { mp_clear(&acpy); goto end; } a = &acpy; } if (bs != MP_NO) { res = mp_init(&bcpy); if (res != MP_OKAY) { goto end; } res = mp_add(mx, b, &bcpy); if (res != MP_OKAY) { mp_clear(&bcpy); goto end; } b = &bcpy; } } res = mp_or(a, b, c); if (((as != MP_NO) || (bs != MP_NO)) && (res == MP_OKAY)) { res = mp_sub(c, mx, c); } end: if (a == &acpy) { mp_clear(&acpy); } if (b == &bcpy) { mp_clear(&bcpy); } if (mx == &_mx) { mp_clear(mx); } return res; }
/* Greatest Common Divisor using the binary method */ int mp_gcd (mp_int * a, mp_int * b, mp_int * c) { mp_int u, v; int k, u_lsb, v_lsb, res; /* either zero than gcd is the largest */ if (mp_iszero (a) == MP_YES) { return mp_abs (b, c); } if (mp_iszero (b) == MP_YES) { return mp_abs (a, c); } /* get copies of a and b we can modify */ if ((res = mp_init_copy (&u, a)) != MP_OKAY) { return res; } if ((res = mp_init_copy (&v, b)) != MP_OKAY) { goto LBL_U; } /* must be positive for the remainder of the algorithm */ u.sign = v.sign = MP_ZPOS; /* B1. Find the common power of two for u and v */ u_lsb = mp_cnt_lsb(&u); v_lsb = mp_cnt_lsb(&v); k = MIN(u_lsb, v_lsb); if (k > 0) { /* divide the power of two out */ if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) { goto LBL_V; } if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) { goto LBL_V; } } /* divide any remaining factors of two out */ if (u_lsb != k) { if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) { goto LBL_V; } } if (v_lsb != k) { if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) { goto LBL_V; } } while (mp_iszero(&v) == MP_NO) { /* make sure v is the largest */ if (mp_cmp_mag(&u, &v) == MP_GT) { /* swap u and v to make sure v is >= u */ mp_exch(&u, &v); } /* subtract smallest from largest */ if ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) { goto LBL_V; } /* Divide out all factors of two */ if ((res = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) { goto LBL_V; } } /* multiply by 2**k which we divided out at the beginning */ if ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) { goto LBL_V; } c->sign = MP_ZPOS; res = MP_OKAY; LBL_V:mp_clear (&u); LBL_U:mp_clear (&v); 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; }
//http://numbers.computation.free.fr/Constants/Algorithms/splitting.html int mp_acoth_binary_splitting(mp_int * q, mp_int * a, mp_int * b, mp_int * P, mp_int * Q, mp_int * R) { int err; mp_int p1, q1, r1, p2, q2, r2, t1, t2, one; if ((err = mp_init_multi(&p1, &q1, &r1, &p2, &q2, &r2, &t1, &t2, &one, NULL)) != MP_OKAY) { return err; } err = MP_OKAY; mp_set(&one, 1); if ((err = mp_sub(b, a, &t1)) != MP_OKAY) { goto _ERR; } if (mp_cmp(&t1, &one) == MP_EQ) { if ((err = mp_mul_2d(a, 1, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_add_d(&t1, 3, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_set_int(P, 1)) != MP_OKAY) { goto _ERR; } if ((err = mp_sqr(q, &t2)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&t1, &t2, Q)) != MP_OKAY) { goto _ERR; } if ((err = mp_copy(&t1, R)) != MP_OKAY) { goto _ERR; } goto _ERR; } if ((err = mp_add(a, b, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_div_2d(&t1, 1, &t1, NULL)) != MP_OKAY) { goto _ERR; } if ((err = mp_acoth_binary_splitting(q, a, &t1, &p1, &q1, &r1)) != MP_OKAY) { goto _ERR; } if ((err = mp_acoth_binary_splitting(q, &t1, b, &p2, &q2, &r2)) != MP_OKAY) { goto _ERR; } //P = q2*p1 + r1*p2 if ((err = mp_mul(&q2, &p1, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&r1, &p2, &t2)) != MP_OKAY) { goto _ERR; } if ((err = mp_add(&t1, &t2, P)) != MP_OKAY) { goto _ERR; } //Q = q1*q2 if ((err = mp_mul(&q1, &q2, Q)) != MP_OKAY) { goto _ERR; } //R = r1*r2 if ((err = mp_mul(&r1, &r2, R)) != MP_OKAY) { goto _ERR; } _ERR: mp_clear_multi(&p1, &q1, &r1, &p2, &q2, &r2, &t1, &t2, &one, NULL); return err; }
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; }
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) { 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; }