int fp2_srt(fp2_t c, fp2_t a) { int r = 0; fp_t t1; fp_t t2; fp_t t3; fp_null(t1); fp_null(t2); fp_null(t3); TRY { fp_new(t1); fp_new(t2); fp_new(t3); /* t1 = a[0]^2 - u^2 * a[1]^2 */ fp_sqr(t1, a[0]); fp_sqr(t2, a[1]); for (int i = -1; i > fp_prime_get_qnr(); i--) { fp_add(t1, t1, t2); } for (int i = 0; i <= fp_prime_get_qnr(); i++) { fp_sub(t1, t1, t2); } fp_add(t1, t1, t2); if (fp_srt(t2, t1)) { /* t1 = (a_0 + sqrt(t1)) / 2 */ fp_add(t1, a[0], t2); fp_set_dig(t3, 2); fp_inv(t3, t3); fp_mul(t1, t1, t3); if (!fp_srt(t3, t1)) { /* t1 = (a_0 - sqrt(t1)) / 2 */ fp_sub(t1, a[0], t2); fp_set_dig(t3, 2); fp_inv(t3, t3); fp_mul(t1, t1, t3); fp_srt(t3, t1); } /* c_0 = sqrt(t1) */ fp_copy(c[0], t3); /* c_1 = a_1 / (2 * sqrt(t1)) */ fp_dbl(t3, t3); fp_inv(t3, t3); fp_mul(c[1], a[1], t3); r = 1; } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fp_free(t1); fp_free(t2); fp_free(t3); } return r; }
void fp2_mul_art(fp2_t c, fp2_t a) { fp_t t; fp_null(t); TRY { fp_new(t); #ifdef FP_QNRES /* (a_0 + a_1 * i) * i = -a_1 + a_0 * i. */ fp_copy(t, a[0]); fp_neg(c[0], a[1]); fp_copy(c[1], t); #else /* (a_0 + a_1 * u) * u = (a_1 * u^2) + a_0 * u. */ fp_copy(t, a[0]); fp_neg(c[0], a[1]); for (int i = -1; i > fp_prime_get_qnr(); i--) { fp_sub(c[0], c[0], a[1]); } for (int i = 1; i <= fp_prime_get_qnr() + 1; i++) { fp_add(c[0], c[0], a[1]); } fp_copy(c[1], t); #endif } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fp_free(t); } }
void fp2_sqr_basic(fp2_t c, fp2_t a) { fp_t t0, t1, t2; fp_null(t0); fp_null(t1); fp_null(t2); TRY { fp_new(t0); fp_new(t1); fp_new(t2); /* t0 = (a_0 + a_1). */ fp_add(t0, a[0], a[1]); /* t1 = (a_0 - a_1). */ fp_sub(t1, a[0], a[1]); /* t1 = a_0 + u^2 * a_1. */ for (int i = -1; i > fp_prime_get_qnr(); i--) { fp_sub(t1, t1, a[1]); } for (int i = 0; i <= fp_prime_get_qnr(); i++) { fp_add(t1, t1, a[1]); } if (fp_prime_get_qnr() == -1) { /* t2 = 2 * a_0. */ fp_dbl(t2, a[0]); /* c_1 = 2 * a_0 * a_1. */ fp_mul(c[1], t2, a[1]); /* c_0 = a_0^2 + a_1^2 * u^2. */ fp_mul(c[0], t0, t1); } else { /* c_1 = a_0 * a_1. */ fp_mul(c[1], a[0], a[1]); /* c_0 = a_0^2 + a_1^2 * u^2. */ fp_mul(c[0], t0, t1); for (int i = -1; i > fp_prime_get_qnr(); i--) { fp_add(c[0], c[0], c[1]); } for (int i = 0; i <= fp_prime_get_qnr(); i++) { fp_sub(c[0], c[0], c[1]); } /* c_1 = 2 * a_0 * a_1. */ fp_dbl(c[1], c[1]); } /* c = c_0 + c_1 * u. */ } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fp_free(t0); fp_free(t1); fp_free(t2); } }
void fp2_inv(fp2_t c, fp2_t a) { fp_t t0, t1; fp_null(t0); fp_null(t1); TRY { fp_new(t0); fp_new(t1); /* t0 = a_0^2, t1 = a_1^2. */ fp_sqr(t0, a[0]); fp_sqr(t1, a[1]); /* t1 = 1/(a_0^2 + a_1^2). */ #ifndef FP_QNRES if (fp_prime_get_qnr() != -1) { if (fp_prime_get_qnr() == -2) { fp_dbl(t1, t1); fp_add(t0, t0, t1); } else { if (fp_prime_get_qnr() < 0) { fp_mul_dig(t1, t1, -fp_prime_get_qnr()); fp_add(t0, t0, t1); } else { fp_mul_dig(t1, t1, fp_prime_get_qnr()); fp_sub(t0, t0, t1); } } } else { fp_add(t0, t0, t1); } #else fp_add(t0, t0, t1); #endif fp_inv(t1, t0); /* c_0 = a_0/(a_0^2 + a_1^2). */ fp_mul(c[0], a[0], t1); /* c_1 = - a_1/(a_0^2 + a_1^2). */ fp_mul(c[1], a[1], t1); fp_neg(c[1], c[1]); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fp_free(t0); fp_free(t1); } }
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 fp2_mul_basic(fp2_t c, fp2_t a, fp2_t b) { dv_t t0, t1, t2, t3, t4; dv_null(t0); dv_null(t1); dv_null(t2); dv_null(t3); dv_null(t4); TRY { dv_new(t0); dv_new(t1); dv_new(t2); dv_new(t3); dv_new(t4); /* Karatsuba algorithm. */ /* t2 = a_0 + a_1, t1 = b0 + b1. */ fp_add(t2, a[0], a[1]); fp_add(t1, b[0], b[1]); /* t3 = (a_0 + a_1) * (b0 + b1). */ fp_muln_low(t3, t2, t1); /* t0 = a_0 * b0, t4 = a_1 * b1. */ fp_muln_low(t0, a[0], b[0]); fp_muln_low(t4, a[1], b[1]); /* t2 = (a_0 * b0) + (a_1 * b1). */ fp_addc_low(t2, t0, t4); /* t1 = (a_0 * b0) + u^2 * (a_1 * b1). */ fp_subc_low(t1, t0, t4); /* t1 = u^2 * (a_1 * b1). */ for (int i = -1; i > fp_prime_get_qnr(); i--) { fp_subc_low(t1, t1, t4); } /* c_0 = t1 mod p. */ fp_rdc(c[0], t1); /* t4 = t3 - t2. */ fp_subc_low(t4, t3, t2); /* c_1 = t4 mod p. */ fp_rdc(c[1], t4); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { dv_free(t0); dv_free(t1); dv_free(t2); dv_free(t3); dv_free(t4); } }
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_nord_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[0], a[1], 2 * FP_DIGS); fp_addc_low(c[1], a[0], a[1]); fp_subc_low(c[0], a[0], t[0]); #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); } }
void fp_prime_calc() { #ifdef WITH_FPX if (fp_prime_get_qnr() != 0) { fp2_calc(); } if (fp_prime_get_cnr() != 0) { fp3_calc(); } #endif }
void fp2_nord_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); #if FP_PRIME == 158 fp_addc_low(t[0], a[0], a[0]); fp_addc_low(t[0], t[0], t[0]); fp_subc_low(t[0], t[0], a[1]); fp_addc_low(t[1], a[1], a[1]); fp_addc_low(t[1], t[1], t[1]); fp_addc_low(c[1], a[0], t[1]); dv_copy(c[0], t[0], 2 * FP_DIGS); #elif defined(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[0], a[1], 2 * FP_DIGS); fp_addc_low(c[1], a[0], a[1]); fp_subc_low(c[0], a[0], t[0]); #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 5: /* If p = 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^lg_4(b-1) + u) is a QNR/CNR. */ /* (a_0 + a_1 * u)(2^lg_4(b-1) + u) = * (2^lg_4(b-1)a_0 - a_1) + (a_0 + 2^lg_4(b-1)a_1 * u. */ fp2_addc_low(t, a, a); fp_prime_back(b, ep_curve_get_b()); for (int i = 1; i < bn_bits(b) / 2; i++) { fp2_addc_low(t, t, t); } 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); } }
void fp2_sqrn_low(dv2_t c, fp2_t a) { align dig_t t0[2 * FP_DIGS], t1[2 * FP_DIGS], t2[2 * FP_DIGS]; /* t0 = (a0 + a1). */ #ifdef FP_SPACE /* if we have room for carries, we can avoid reductions here. */ fp_addn_low(t0, a[0], a[1]); #else fp_addm_low(t0, a[0], a[1]); #endif /* t1 = (a0 - a1). */ fp_subm_low(t1, a[0], a[1]); #ifdef FP_QNRES #ifdef FP_SPACE fp_dbln_low(t2, a[0]); #else fp_dblm_low(t2, a[0]); #endif /* c1 = 2 * a0 * a1. */ fp_muln_low(c[1], t2, a[1]); /* c_0 = a_0^2 + a_1^2 * u^2. */ fp_muln_low(c[0], t0, t1); #else /* !FP_QNRES */ /* t1 = u^2 * (a1 * b1). */ for (int i = -1; i > fp_prime_get_qnr(); i--) { fp_subm_low(t1, t1, a[1]); } if (fp_prime_get_qnr() == -1) { /* t2 = 2 * a0. */ fp_dbl(t2, a[0]); /* c1 = 2 * a0 * a1. */ fp_muln_low(c[1], t2, a[1]); /* c0 = a0^2 + b_0^2 * u^2. */ fp_muln_low(c[0], t0, t1); } else { /* c1 = a0 * a1. */ fp_muln_low(c[1], a[0], a[1]); /* c0 = a0^2 + b_0^2 * u^2. */ fp_muln_low(c[0], t0, t1); #ifdef FP_SPACE for (int i = -1; i > fp_prime_get_qnr(); i--) { fp_addd_low(c[0], c[0], c[1]); } /* c1 = 2 * a0 * a1. */ fp_addd_low(c[1], c[1], c[1]); #else for (int i = -1; i > fp_prime_get_qnr(); i--) { fp_addc_low(c[0], c[0], c[1]); } /* c1 = 2 * a0 * a1. */ fp_addc_low(c[1], c[1], c[1]); #endif } #endif /* c = c0 + c1 * u. */ }