void bn_sqra_low(dig_t *c, const dig_t *a, int size) { dig_t carry, digit = *a; carry = bn_mula_low(c, a, digit, size); bn_add1_low(c + size, c + size, carry, size); if (size > 1) { carry = bn_mula_low(c + 1, a + 1, digit, size - 1); bn_add1_low(c + size, c + size, carry, size); } }
void fp_rdc_monty_basic(fp_t c, dv_t a) { int i; dig_t r, c0, c1, *tmp, u0; const dig_t *p = NULL; tmp = a; u0 = *(fp_prime_get_rdc()); p = fp_prime_get(); c1 = 0; for (i = 0; i < FP_DIGS; i++, tmp++) { r = (dig_t)(*tmp * u0); c0 = fp_mula_low(tmp, fp_prime_get(), r); /* We must use this because the size (FP_DIGS - i) is variable. */ c1 += bn_add1_low(tmp + FP_DIGS, tmp + FP_DIGS, c0, FP_DIGS - i); } fp_copy(c, a + FP_DIGS); for (i = 0; i < c1; i++) { fp_subn_low(c, c, p); } if (fp_cmpn_low(c, p) != CMP_LT) { fp_subn_low(c, c, p); } }
void bn_sub_dig(bn_t c, bn_t a, dig_t b) { dig_t carry; bn_grow(c, a->used); /* If a < 0, compute c = -(|a| + b). */ if (a->sign == BN_NEG) { carry = bn_add1_low(c->dp, a->dp, b, a->used); if (carry) { bn_grow(c, a->used + 1); c->dp[a->used] = carry; } c->used = a->used + carry; c->sign = BN_NEG; } else { /* If a > 0 && |a| >= b, compute c = (|a| - b). */ if (a->used > 1 || a->dp[0] >= b) { carry = bn_sub1_low(c->dp, a->dp, b, a->used); c->used = a->used; c->sign = BN_POS; } else { /* If a > 0 && a < b. */ if (a->used == 1) { c->dp[0] = b - a->dp[0]; } else { c->dp[0] = b; } c->used = 1; c->sign = BN_NEG; } } bn_trim(c); }
/** * Adds two multiple precision integers, where a >= b. * * @param[out] c - the result. * @param[in] a - the first multiple precision integer to add. * @param[in] b - the second multiple precision integer to add. */ static void bn_add_imp(bn_t c, bn_t a, bn_t b) { int max, min; dig_t carry; max = a->used; min = b->used; /* Grow the result. */ bn_grow(c, max); if (a->used == b->used) { carry = bn_addn_low(c->dp, a->dp, b->dp, max); } else { carry = bn_addn_low(c->dp, a->dp, b->dp, min); carry = bn_add1_low(c->dp + min, a->dp + min, carry, max - min); } if (carry) { bn_grow(c, max + 1); c->dp[max] = carry; } c->used = max + carry; bn_trim(c); }
/** * Multiplies two prime field elements using recursive Karatsuba * multiplication. * * @param[out] c - the result. * @param[in] a - the first prime field element. * @param[in] b - the second prime field element. * @param[in] size - the number of digits to multiply. * @param[in] level - the number of Karatsuba steps to apply. */ static void fp_mul_karat_imp(dv_t c, const fp_t a, const fp_t b, int size, int level) { int i, h, h1; dv_t a1, b1, a0b0, a1b1, t; dig_t carry; /* Compute half the digits of a or b. */ h = size >> 1; h1 = size - h; dv_null(a1); dv_null(b1); dv_null(a0b0); dv_null(a1b1); TRY { /* Allocate the temp variables. */ dv_new(a1); dv_new(b1); dv_new(a0b0); dv_new(a1b1); dv_new(t); dv_zero(a1, h1 + 1); dv_zero(b1, h1 + 1); dv_zero(a0b0, 2 * h); dv_zero(a1b1, 2 * h1); dv_zero(t, 2 * h1 + 1); /* a0b0 = a0 * b0 and a1b1 = a1 * b1 */ if (level <= 1) { #if FP_MUL == BASIC for (i = 0; i < h; i++) { carry = bn_mula_low(a0b0 + i, a, *(b + i), h); *(a0b0 + i + h) = carry; } for (i = 0; i < h1; i++) { carry = bn_mula_low(a1b1 + i, a + h, *(b + h + i), h1); *(a1b1 + i + h1) = carry; } #elif FP_MUL == COMBA || FP_MUL == INTEG bn_muln_low(a0b0, a, b, h); bn_muln_low(a1b1, a + h, b + h, h1); #endif } else { fp_mul_karat_imp(a0b0, a, b, h, level - 1); fp_mul_karat_imp(a1b1, a + h, b + h, h1, level - 1); } for (i = 0; i < 2 * h; i++) { c[i] = a0b0[i]; } for (i = 0; i < 2 * h1 + 1; i++) { c[2 * h + i] = a1b1[i]; } /* a1 = (a1 + a0) */ carry = bn_addn_low(a1, a, a + h, h); bn_add1_low(a1 + h, a1 + h, carry, 2); if (h1 > h) { bn_add1_low(a1 + h, a1 + h, *(a + 2 * h), 2); } /* b1 = (b1 + b0) */ carry = bn_addn_low(b1, b, b + h, h); bn_add1_low(b1 + h, b1 + h, carry, 2); if (h1 > h) { bn_add1_low(b1 + h, b1 + h, *(b + 2 * h), 2); } if (level <= 1) { /* t = (a1 + a0)*(b1 + b0) */ #if FP_MUL == BASIC for (i = 0; i < h1 + 1; i++) { carry = bn_mula_low(t + i, a1, *(b1 + i), h1 + 1); *(t + i + h1 + 1) = carry; } #elif FP_MUL == COMBA || FP_MUL == INTEG bn_muln_low(t, a1, b1, h1 + 1); #endif } else { fp_mul_karat_imp(t, a1, b1, h1 + 1, level - 1); } /* t = t - (a0*b0 << h digits) */ carry = bn_subn_low(t, t, a0b0, 2 * h); bn_sub1_low(t + 2 * h, t + 2 * h, carry, 2 * (h1 + 1) - 2 * h); /* t = t - (a1*b1 << h digits) */ carry = bn_subn_low(t, t, a1b1, 2 * h1); bn_sub1_low(t + 2 * h1, t + 2 * h1, carry, 2 * (h1 + 1) - 2 * h1); /* c = c + [(a1 + a0)*(b1 + b0) << digits] */ c += h; carry = bn_addn_low(c, c, t, 2 * (h1 + 1)); c += 2 * (h1 + 1); bn_add1_low(c, c, carry, 2 * size - h - 2 * (h1 + 1)); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { dv_free(a1); dv_free(b1); dv_free(a0b0); dv_free(a1b1); dv_free(t); } }
/** * Computes the square of a multiple precision integer using recursive Karatsuba * squaring. * * @param[out] c - the result. * @param[in] a - the prime field element to square. * @param[in] size - the number of digits to square. * @param[in] level - the number of Karatsuba steps to apply. */ static void fp_sqr_karat_imp(dv_t c, const fp_t a, int size, int level) { int i, h, h1; dv_t t0, t1, a0a0, a1a1; dig_t carry; /* Compute half the digits of a or b. */ h = size >> 1; h1 = size - h; dv_null(t0); dv_null(t1); dv_null(a0a0); dv_null(a1a1); TRY { /* Allocate the temp variables. */ dv_new(t0); dv_new(t1); dv_new(a0a0); dv_new(a1a1); dv_zero(t0, 2 * h1); dv_zero(t1, 2 * (h1 + 1)); dv_zero(a0a0, 2 * h); dv_zero(a1a1, 2 * h1); if (level <= 1) { /* a0a0 = a0 * a0 and a1a1 = a1 * a1 */ #if FP_SQR == BASIC for (i = 0; i < h; i++) { bn_sqra_low(a0a0 + (2 * i), a + i, h - i); } for (i = 0; i < h1; i++) { bn_sqra_low(a1a1 + (2 * i), a + h + i, h1 - i); } #elif FP_SQR == COMBA || FP_SQR == INTEG bn_sqrn_low(a0a0, a, h); bn_sqrn_low(a1a1, a + h, h1); #elif FP_SQR == MULTP bn_muln_low(a0a0, a, a, h); bn_muln_low(a1a1, a + h, a + h, h1); #endif } else { fp_sqr_karat_imp(a0a0, a, h, level - 1); fp_sqr_karat_imp(a1a1, a + h, h1, level - 1); } /* t2 = a1 * a1 << 2*h digits + a0 * a0. */ for (i = 0; i < 2 * h; i++) { c[i] = a0a0[i]; } for (i = 0; i < 2 * h1; i++) { c[2 * h + i] = a1a1[i]; } /* t = (a1 + a0) */ carry = bn_addn_low(t0, a, a + h, h); carry = bn_add1_low(t0 + h, t0 + h, carry, 2); if (h1 > h) { carry = bn_add1_low(t0 + h, t0 + h, *(a + 2 * h), 2); } if (level <= 1) { /* a1a1 = (a1 + a0)*(a1 + a0) */ #if FP_SQR == BASIC for (i = 0; i < h1 + 1; i++) { bn_sqra_low(t1 + (2 * i), t0 + i, h1 + 1 - i); } #elif FP_SQR == COMBA || FP_SQR == INTEG bn_sqrn_low(t1, t0, h1 + 1); #elif FP_SQR == MULTP bn_muln_low(t1, t0, t0, h1 + 1); #endif } else { fp_sqr_karat_imp(t1, t0, h1 + 1, level - 1); } /* t = t - (a0*a0 << h digits) */ carry = bn_subn_low(t1, t1, a0a0, 2 * h); bn_sub1_low(t1 + 2 * h, t1 + 2 * h, carry, 2 * (h1 + 1) - 2 * h); /* t = t - (a1*a1 << h digits) */ carry = bn_subn_low(t1, t1, a1a1, 2 * h1); bn_sub1_low(t1 + 2 * h, t1 + 2 * h, carry, 2 * (h1 + 1) - 2 * h); /* c = c + [(a1 + a0)*(a1 + a0) << digits] */ c += h; carry = bn_addn_low(c, c, t1, 2 * (h1 + 1)); c += 2 * (h1 + 1); carry = bn_add1_low(c, c, carry, 2 * size - h - 2 * (h1 + 1)); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { dv_free(t0); dv_free(t1); dv_free(a0a0); dv_free(a1a1); } }
void bn_divn_low(dig_t *c, dig_t *d, dig_t *a, int sa, dig_t *b, int sb) { int norm, i, n, t, sd; dig_t carry, t1[3], t2[3]; /* Normalize x and y so that the leading digit of y is bigger than * 2^(BN_DIGIT-1). */ norm = util_bits_dig(b[sb - 1]) % BN_DIGIT; if (norm < (int)(BN_DIGIT - 1)) { norm = (BN_DIGIT - 1) - norm; carry = bn_lshb_low(a, a, sa, norm); if (carry) { a[sa++] = carry; } carry = bn_lshb_low(b, b, sb, norm); if (carry) { b[sb++] = carry; } } else { norm = 0; } n = sa - 1; t = sb - 1; /* Shift y so that the most significant digit of y is aligned with the * most significant digit of x. */ bn_lshd_low(b, b, sb, (n - t)); /* Find the most significant digit of the quotient. */ while (bn_cmpn_low(a, b, sa) != CMP_LT) { c[n - t]++; bn_subn_low(a, a, b, sa); } /* Shift y back. */ bn_rshd_low(b, b, sb + (n - t), (n - t)); /* Find the remaining digits. */ for (i = n; i >= (t + 1); i--) { if (i > sa) { continue; } if (a[i] == b[t]) { c[i - t - 1] = ((((dbl_t)1) << BN_DIGIT) - 1); } else { dbl_t tmp; tmp = ((dbl_t)a[i]) << ((dbl_t)BN_DIGIT); tmp |= (dbl_t)(a[i - 1]); tmp /= (dbl_t)(b[t]); c[i - t - 1] = (dig_t)tmp; } c[i - t - 1]++; do { c[i - t - 1]--; t1[0] = (t - 1 < 0) ? 0 : b[t - 1]; t1[1] = b[t]; carry = bn_mul1_low(t1, t1, c[i - t - 1], 2); t1[2] = carry; t2[0] = (i - 2 < 0) ? 0 : a[i - 2]; t2[1] = (i - 1 < 0) ? 0 : a[i - 1]; t2[2] = a[i]; } while (bn_cmpn_low(t1, t2, 3) == CMP_GT); carry = bn_mul1_low(d, b, c[i - t - 1], sb); sd = sb; if (carry) { d[sd++] = carry; } carry = bn_subn_low(a + (i - t - 1), a + (i - t - 1), d, sd); sd += (i - t - 1); if (sa - sd > 0) { carry = bn_sub1_low(a + sd, a + sd, carry, sa - sd); } if (carry) { sd = sb + (i - t - 1); carry = bn_addn_low(a + (i - t - 1), a + (i - t - 1), b, sb); carry = bn_add1_low(a + sd, a + sd, carry, sa - sd); c[i - t - 1]--; } } /* Remainder should be not be longer than the divisor. */ bn_rshb_low(d, a, sb, norm); }