void fp2_mulc_low(dv2_t c, fp2_t a, fp2_t b) { align dig_t t0[2 * FP_DIGS], t1[2 * FP_DIGS], t2[2 * FP_DIGS]; /* Karatsuba algorithm. */ /* t0 = a_0 + a_1, t1 = b_0 + b_1. */ fp_addn_low(t0, a[0], a[1]); fp_addn_low(t1, b[0], b[1]); /* c_0 = a_0 * b_0, c_1 = a_1 * b_1, t2 = (a_0 + a_1) * (b_0 + b_1). */ fp_muln_low(c[0], a[0], b[0]); fp_muln_low(c[1], a[1], b[1]); fp_muln_low(t2, t0, t1); /* t0 = (a_0 * b_0) + (a_1 * b_1). */ fp_addd_low(t0, c[0], c[1]); /* c_0 = (a_0 * b_0) + u^2 * (a_1 * b_1). */ fp_subd_low(c[0], c[0], c[1]); #ifndef FP_QNRES /* t1 = u^2 * (a_1 * b_1). */ for (int i = -1; i > fp_prime_get_qnr(); i--) { fp_subd_low(c[0], c[0], c[1]); } #endif /* c_1 = (t2 - t0). */ fp_subd_low(c[1], t2, t0); /* c_0 = c_0 + 2^N * p/4. */ bn_lshb_low(c[0] + FP_DIGS - 1, c[0] + FP_DIGS - 1, FP_DIGS + 1, 2); fp_addn_low(c[0] + FP_DIGS, c[0] + FP_DIGS, fp_prime_get()); bn_rshb_low(c[0] + FP_DIGS - 1, c[0] + FP_DIGS - 1, FP_DIGS + 1, 2); }
void bn_lsh(bn_t c, bn_t a, int bits) { int digits; dig_t carry; bn_copy(c, a); if (bits <= 0) { return; } SPLIT(bits, digits, bits, BN_DIG_LOG); if (bits > 0) { if (bn_bits(c) + bits > c->used * (int)BN_DIGIT) { bn_grow(c, c->used + digits + 1); } } else { bn_grow(c, c->used + digits); } if (digits > 0) { bn_lshd_low(c->dp, a->dp, a->used, digits); } c->used = a->used + digits; c->sign = a->sign; if (bits > 0) { if (c != a) { carry = bn_lshb_low(c->dp + digits, a->dp, a->used, bits); } else { carry = bn_lshb_low(c->dp + digits, c->dp + digits, c->used, bits); } if (carry != 0) { c->dp[c->used] = carry; (c->used)++; } } bn_trim(c); }
void fp_rdcs_low(dig_t *c, dig_t *a, dig_t *m) { align dig_t q[2 * FP_DIGS], _q[2 * FP_DIGS]; align dig_t _r[2 * FP_DIGS], r[2 * FP_DIGS], t[2 * FP_DIGS]; int *sform, len; int first, i, j, b0, d0, b1, d1; dig_t carry; sform = fp_prime_get_sps(&len); SPLIT(b0, d0, FP_BITS, FP_DIG_LOG); first = (d0) + (b0 == 0 ? 0 : 1); /* q = floor(a/b^k) */ dv_zero(q, 2 * FP_DIGS); bn_rshd_low(q, a, 2 * FP_DIGS, d0); if (b0 > 0) { bn_rshb_low(q, q, 2 * FP_DIGS, b0); } /* r = a - qb^k. */ dv_copy(r, a, first); if (b0 > 0) { r[first - 1] &= MASK(b0); } carry = 0; while (!fp_is_zero(q)) { dv_zero(_q, 2 * FP_DIGS); for (i = len - 1; i > 0; i--) { j = (sform[i] < 0 ? -sform[i] : sform[i]); SPLIT(b1, d1, j, FP_DIG_LOG); dv_zero(t, 2 * FP_DIGS); bn_lshd_low(t, q, FP_DIGS, d1); if (b1 > 0) { bn_lshb_low(t, t, 2 * FP_DIGS, b1); } if (sform[i] > 0) { bn_subn_low(_q, _q, t, 2 * FP_DIGS); } else { bn_addn_low(_q, _q, t, 2 * FP_DIGS); } } if (sform[0] > 0) { bn_subn_low(_q, _q, q, 2 * FP_DIGS); } else { bn_addn_low(_q, _q, q, 2 * FP_DIGS); } bn_rshd_low(q, _q, 2 * FP_DIGS, d0); if (b0 > 0) { bn_rshb_low(q, q, 2 * FP_DIGS, b0); } dv_copy(_r, _q, first); if (b0 > 0) { _r[first - 1] &= MASK(b0); } fp_add(r, r, _r); } while (fp_cmpn_low(r, m) != CMP_LT) { fp_subn_low(r, r, m); } fp_copy(c, r); }
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); }
void fp2_norh_low(dv2_t c, dv2_t a) { dv2_t t; bn_t b; dv2_null(t); bn_null(b); TRY { dv2_new(t); bn_new(b); #ifdef FP_QNRES /* If p = 3 mod 8, (1 + i) is a QNR/CNR. */ /* (a_0 + a_1 * i) * (1 + i) = (a_0 - a_1) + (a_0 + a_1) * u. */ dv_copy(t[1], a[1], 2 * FP_DIGS); fp_addd_low(c[1], a[0], a[1]); /* c_0 = c_0 + 2^N * p/2. */ dv_copy(t[0], a[0], 2 * FP_DIGS); bn_lshb_low(t[0] + FP_DIGS - 1, t[0] + FP_DIGS - 1, FP_DIGS + 1, 1); fp_addn_low(t[0] + FP_DIGS, t[0] + FP_DIGS, fp_prime_get()); bn_rshb_low(t[0] + FP_DIGS - 1, t[0] + FP_DIGS - 1, FP_DIGS + 1, 1); fp_subd_low(c[0], t[0], t[1]); #else switch (fp_prime_get_mod8()) { case 3: /* If p = 3 mod 8, (1 + u) is a QNR, u^2 = -1. */ /* (a_0 + a_1 * u) * (1 + u) = (a_0 - a_1) + (a_0 + a_1) * u. */ dv_copy(t[0], a[1], 2 * FP_DIGS); fp_addc_low(c[1], a[0], a[1]); fp_subc_low(c[0], a[0], t[0]); break; case 1: case 5: /* If p = 1,5 mod 8, (u) is a QNR. */ dv_copy(t[0], a[0], 2 * FP_DIGS); dv_zero(t[1], FP_DIGS); dv_copy(t[1] + FP_DIGS, fp_prime_get(), FP_DIGS); fp_subc_low(c[0], t[1], a[1]); for (int i = -1; i > fp_prime_get_qnr(); i--) { fp_subc_low(c[0], c[0], a[1]); } dv_copy(c[1], t[0], 2 * FP_DIGS); break; case 7: /* If p = 7 mod 8, (2 + u) is a QNR/CNR. */ fp2_addc_low(t, a, a); fp_subc_low(c[0], t[0], a[1]); fp_addc_low(c[1], t[1], a[0]); break; default: THROW(ERR_NO_VALID); break; } #endif } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { dv2_free(t); bn_free(b); } }