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 fp_subc_low(dig_t *c, const dig_t *a, const dig_t *b) { dig_t carry = fp_subd_low(c, a, b); if (carry) { fp_addn_low(c + FP_DIGS, c + FP_DIGS, fp_prime_get()); } }
void fp2_muln_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. */ #ifdef FP_SPACE fp_addn_low(t0, a[0], a[1]); fp_addn_low(t1, b[0], b[1]); #else fp_addm_low(t0, a[0], a[1]); fp_addm_low(t1, b[0], b[1]); #endif /* c_0 = a_0 * b_0, c_1 = a_1 * b_1. */ fp_muln_low(c[0], a[0], b[0]); fp_muln_low(c[1], a[1], b[1]); /* t2 = (a_0 + a_1) * (b_0 + b_1). */ fp_muln_low(t2, t0, t1); /* t0 = (a_0 * b_0) + (a_1 * b_1). */ #ifdef FP_SPACE fp_addd_low(t0, c[0], c[1]); #else fp_addc_low(t0, c[0], c[1]); #endif /* c_0 = (a_0 * b_0) + u^2 * (a_1 * b_1). */ fp_subc_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_subc_low(c[0], c[0], c[1]); } for (int i = 0; i <= fp_prime_get_qnr(); i++) { fp_addc_low(c[0], c[0], c[1]); } #endif /* c_1 = t2 - t0. */ #ifdef FP_SPACE fp_subd_low(c[1], t2, t0); #else fp_subc_low(c[1], t2, t0); #endif }
void fp2_subd_low(dv2_t c, dv2_t a, dv2_t b) { fp_subd_low(c[0], a[0], b[0]); fp_subd_low(c[1], a[1], b[1]); }
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); } }