int cp_ecss_ver(bn_t e, bn_t s, unsigned char *msg, int len, ec_t q) { bn_t n, ev, rv; ec_t p; unsigned char hash[MD_LEN]; unsigned char m[len + EC_BYTES]; int result = 0; bn_null(n); bn_null(ev); bn_null(rv); ec_null(p); TRY { bn_new(n); bn_new(ev); bn_new(rv); ec_new(p); ec_curve_get_ord(n); if (bn_sign(e) == BN_POS && bn_sign(s) == BN_POS && !bn_is_zero(s)) { if (bn_cmp(e, n) == CMP_LT && bn_cmp(s, n) == CMP_LT) { ec_mul_sim_gen(p, s, q, e); ec_get_x(rv, p); bn_mod(rv, rv, n); memcpy(m, msg, len); bn_write_bin(m + len, EC_BYTES, rv); md_map(hash, m, len + EC_BYTES); if (8 * MD_LEN > bn_bits(n)) { len = CEIL(bn_bits(n), 8); bn_read_bin(ev, hash, len); bn_rsh(ev, ev, 8 * MD_LEN - bn_bits(n)); } else { bn_read_bin(ev, hash, MD_LEN); } bn_mod(ev, ev, n); result = dv_cmp_const(ev->dp, e->dp, MIN(ev->used, e->used)); result = (result == CMP_NE ? 0 : 1); if (ev->used != e->used) { result = 0; } } } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(n); bn_free(ev); bn_free(rv); ec_free(p); } return result; }
/** * Multiplies and adds two prime elliptic curve points simultaneously, * optionally choosing the first point as the generator depending on an optional * table of precomputed points. * * @param[out] r - the result. * @param[in] p - the first point to multiply. * @param[in] k - the first integer. * @param[in] q - the second point to multiply. * @param[in] m - the second integer. * @param[in] t - the pointer to the precomputed table. */ void ep_mul_sim_endom(ep_t r, const ep_t p, const bn_t k, const ep_t q, const bn_t m, const ep_t *t) { int len, len0, len1, len2, len3, i, n, sk0, sk1, sl0, sl1, w, g = 0; int8_t naf0[FP_BITS + 1], naf1[FP_BITS + 1], *t0, *t1; int8_t naf2[FP_BITS + 1], naf3[FP_BITS + 1], *t2, *t3; bn_t k0, k1, l0, l1; bn_t ord, v1[3], v2[3]; ep_t u; ep_t tab0[1 << (EP_WIDTH - 2)]; ep_t tab1[1 << (EP_WIDTH - 2)]; bn_null(ord); bn_null(k0); bn_null(k1); bn_null(l0); bn_null(l1); ep_null(u); for (i = 0; i < (1 << (EP_WIDTH - 2)); i++) { ep_null(tab0[i]); ep_null(tab1[i]); } bn_new(ord); bn_new(k0); bn_new(k1); bn_new(l0); bn_new(l1); ep_new(u); TRY { for (i = 0; i < 3; i++) { bn_null(v1[i]); bn_null(v2[i]); bn_new(v1[i]); bn_new(v2[i]); } ep_curve_get_ord(ord); ep_curve_get_v1(v1); ep_curve_get_v2(v2); bn_rec_glv(k0, k1, k, ord, (const bn_t *)v1, (const bn_t *)v2); sk0 = bn_sign(k0); sk1 = bn_sign(k1); bn_abs(k0, k0); bn_abs(k1, k1); bn_rec_glv(l0, l1, m, ord, (const bn_t *)v1, (const bn_t *)v2); sl0 = bn_sign(l0); sl1 = bn_sign(l1); bn_abs(l0, l0); bn_abs(l1, l1); g = (t == NULL ? 0 : 1); if (!g) { for (i = 0; i < (1 << (EP_WIDTH - 2)); i++) { ep_new(tab0[i]); } ep_tab(tab0, p, EP_WIDTH); t = (const ep_t *)tab0; } /* Prepare the precomputation table. */ for (i = 0; i < (1 << (EP_WIDTH - 2)); i++) { ep_new(tab1[i]); } /* Compute the precomputation table. */ ep_tab(tab1, q, EP_WIDTH); /* Compute the w-TNAF representation of k and l */ if (g) { w = EP_DEPTH; } else { w = EP_WIDTH; } len0 = len1 = len2 = len3 = FP_BITS + 1; bn_rec_naf(naf0, &len0, k0, w); bn_rec_naf(naf1, &len1, k1, w); bn_rec_naf(naf2, &len2, l0, EP_WIDTH); bn_rec_naf(naf3, &len3, l1, EP_WIDTH); len = MAX(MAX(len0, len1), MAX(len2, len3)); t0 = naf0 + len - 1; t1 = naf1 + len - 1; t2 = naf2 + len - 1; t3 = naf3 + len - 1; for (i = len0; i < len; i++) { naf0[i] = 0; } for (i = len1; i < len; i++) { naf1[i] = 0; } for (i = len2; i < len; i++) { naf2[i] = 0; } for (i = len3; i < len; i++) { naf3[i] = 0; } ep_set_infty(r); for (i = len - 1; i >= 0; i--, t0--, t1--, t2--, t3--) { ep_dbl(r, r); n = *t0; if (n > 0) { if (sk0 == BN_POS) { ep_add(r, r, t[n / 2]); } else { ep_sub(r, r, t[n / 2]); } } if (n < 0) { if (sk0 == BN_POS) { ep_sub(r, r, t[-n / 2]); } else { ep_add(r, r, t[-n / 2]); } } n = *t1; if (n > 0) { ep_copy(u, t[n / 2]); fp_mul(u->x, u->x, ep_curve_get_beta()); if (sk1 == BN_NEG) { ep_neg(u, u); } ep_add(r, r, u); } if (n < 0) { ep_copy(u, t[-n / 2]); fp_mul(u->x, u->x, ep_curve_get_beta()); if (sk1 == BN_NEG) { ep_neg(u, u); } ep_sub(r, r, u); } n = *t2; if (n > 0) { if (sl0 == BN_POS) { ep_add(r, r, tab1[n / 2]); } else { ep_sub(r, r, tab1[n / 2]); } } if (n < 0) { if (sl0 == BN_POS) { ep_sub(r, r, tab1[-n / 2]); } else { ep_add(r, r, tab1[-n / 2]); } } n = *t3; if (n > 0) { ep_copy(u, tab1[n / 2]); fp_mul(u->x, u->x, ep_curve_get_beta()); if (sl1 == BN_NEG) { ep_neg(u, u); } ep_add(r, r, u); } if (n < 0) { ep_copy(u, tab1[-n / 2]); fp_mul(u->x, u->x, ep_curve_get_beta()); if (sl1 == BN_NEG) { ep_neg(u, u); } ep_sub(r, r, u); } } /* Convert r to affine coordinates. */ ep_norm(r, r); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(ord); bn_free(k0); bn_free(k1); bn_free(l0); bn_free(l1); ep_free(u); if (!g) { for (i = 0; i < 1 << (EP_WIDTH - 2); i++) { ep_free(tab0[i]); } } /* Free the precomputation tables. */ for (i = 0; i < 1 << (EP_WIDTH - 2); i++) { ep_free(tab1[i]); } for (i = 0; i < 3; i++) { bn_free(v1[i]); bn_free(v2[i]); } } }
/** * Multiplies a prime elliptic curve point by an integer using the COMBS * method. * * @param[out] r - the result. * @param[in] t - the precomputed table. * @param[in] k - the integer. */ static void ed_mul_combs_endom(ed_t r, const ed_t *t, const bn_t k) { int i, j, l, w0, w1, n0, n1, p0, p1, s0, s1; bn_t n, k0, k1, v1[3], v2[3]; ed_t u; bn_null(n); bn_null(k0); bn_null(k1); ed_null(u); TRY { bn_new(n); bn_new(k0); bn_new(k1); ed_new(u); for (i = 0; i < 3; i++) { bn_null(v1[i]); bn_null(v2[i]); bn_new(v1[i]); bn_new(v2[i]); } ed_curve_get_ord(n); ed_curve_get_v1(v1); ed_curve_get_v2(v2); l = bn_bits(n); l = ((l % (2 * ED_DEPTH)) == 0 ? (l / (2 * ED_DEPTH)) : (l / (2 * ED_DEPTH)) + 1); bn_rec_glv(k0, k1, k, n, (const bn_t *)v1, (const bn_t *)v2); s0 = bn_sign(k0); s1 = bn_sign(k1); bn_abs(k0, k0); bn_abs(k1, k1); n0 = bn_bits(k0); n1 = bn_bits(k1); p0 = (ED_DEPTH) * l - 1; ed_set_infty(r); for (i = l - 1; i >= 0; i--) { ed_dbl(r, r); w0 = 0; w1 = 0; p1 = p0--; for (j = ED_DEPTH - 1; j >= 0; j--, p1 -= l) { w0 = w0 << 1; w1 = w1 << 1; if (p1 < n0 && bn_get_bit(k0, p1)) { w0 = w0 | 1; } if (p1 < n1 && bn_get_bit(k1, p1)) { w1 = w1 | 1; } } if (w0 > 0) { if (s0 == BN_POS) { ed_add(r, r, t[w0]); } else { ed_sub(r, r, t[w0]); } } if (w1 > 0) { ed_copy(u, t[w1]); fp_mul(u->x, u->x, ed_curve_get_beta()); if (s1 == BN_NEG) { ed_neg(u, u); } ed_add(r, r, u); } } ed_norm(r, r); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(n); bn_free(k0); bn_free(k1); ed_free(u); for (i = 0; i < 3; i++) { bn_free(v1[i]); bn_free(v2[i]); } } }
static Boolean kcl_int_sign(cint_t *ai) { return(bn_sign(ai->cint_data)); }
void bn_rand_mod(bn_t a, bn_t b) { do { bn_rand(a, bn_sign(b), bn_bits(b)); } while (bn_is_zero(a) || bn_cmp_abs(a, b) != CMP_LT); }
int cp_rsa_enc(uint8_t *out, int *out_len, uint8_t *in, int in_len, rsa_t pub) { bn_t m, eb; int size, pad_len, result = STS_OK; bn_null(m); bn_null(eb); bn_size_bin(&size, pub->n); if (pub == NULL || in_len <= 0 || in_len > (size - RSA_PAD_LEN)) { return STS_ERR; } TRY { bn_new(m); bn_new(eb); bn_zero(m); bn_zero(eb); #if CP_RSAPD == BASIC if (pad_basic(eb, &pad_len, in_len, size, RSA_ENC) == STS_OK) { #elif CP_RSAPD == PKCS1 if (pad_pkcs1(eb, &pad_len, in_len, size, RSA_ENC) == STS_OK) { #elif CP_RSAPD == PKCS2 if (pad_pkcs2(eb, &pad_len, in_len, size, RSA_ENC) == STS_OK) { #endif bn_read_bin(m, in, in_len); bn_add(eb, eb, m); #if CP_RSAPD == PKCS2 pad_pkcs2(eb, &pad_len, in_len, size, RSA_ENC_FIN); #endif bn_mxp(eb, eb, pub->e, pub->n); if (size <= *out_len) { *out_len = size; memset(out, 0, *out_len); bn_write_bin(out, size, eb); } else { result = STS_ERR; } } else { result = STS_ERR; } } CATCH_ANY { result = STS_ERR; } FINALLY { bn_free(m); bn_free(eb); } return result; } #if CP_RSA == BASIC || !defined(STRIP) int cp_rsa_dec_basic(uint8_t *out, int *out_len, uint8_t *in, int in_len, rsa_t prv) { bn_t m, eb; int size, pad_len, result = STS_OK; bn_size_bin(&size, prv->n); if (prv == NULL || in_len != size || in_len < RSA_PAD_LEN) { return STS_ERR; } bn_null(m); bn_null(eb); TRY { bn_new(m); bn_new(eb); bn_read_bin(eb, in, in_len); bn_mxp(eb, eb, prv->d, prv->n); if (bn_cmp(eb, prv->n) != CMP_LT) { result = STS_ERR; } #if CP_RSAPD == BASIC if (pad_basic(eb, &pad_len, in_len, size, RSA_DEC) == STS_OK) { #elif CP_RSAPD == PKCS1 if (pad_pkcs1(eb, &pad_len, in_len, size, RSA_DEC) == STS_OK) { #elif CP_RSAPD == PKCS2 if (pad_pkcs2(eb, &pad_len, in_len, size, RSA_DEC) == STS_OK) { #endif size = size - pad_len; if (size <= *out_len) { memset(out, 0, size); bn_write_bin(out, size, eb); *out_len = size; } else { result = STS_ERR; } } else { result = STS_ERR; } } CATCH_ANY { result = STS_ERR; } FINALLY { bn_free(m); bn_free(eb); } return result; } #endif #if CP_RSA == QUICK || !defined(STRIP) int cp_rsa_dec_quick(uint8_t *out, int *out_len, uint8_t *in, int in_len, rsa_t prv) { bn_t m, eb; int size, pad_len, result = STS_OK; bn_null(m); bn_null(eb); bn_size_bin(&size, prv->n); if (prv == NULL || in_len != size || in_len < RSA_PAD_LEN) { return STS_ERR; } TRY { bn_new(m); bn_new(eb); bn_read_bin(eb, in, in_len); bn_copy(m, eb); /* m1 = c^dP mod p. */ bn_mxp(eb, eb, prv->dp, prv->p); /* m2 = c^dQ mod q. */ bn_mxp(m, m, prv->dq, prv->q); /* m1 = m1 - m2 mod p. */ bn_sub(eb, eb, m); while (bn_sign(eb) == BN_NEG) { bn_add(eb, eb, prv->p); } bn_mod(eb, eb, prv->p); /* m1 = qInv(m1 - m2) mod p. */ bn_mul(eb, eb, prv->qi); bn_mod(eb, eb, prv->p); /* m = m2 + m1 * q. */ bn_mul(eb, eb, prv->q); bn_add(eb, eb, m); if (bn_cmp(eb, prv->n) != CMP_LT) { result = STS_ERR; } #if CP_RSAPD == BASIC if (pad_basic(eb, &pad_len, in_len, size, RSA_DEC) == STS_OK) { #elif CP_RSAPD == PKCS1 if (pad_pkcs1(eb, &pad_len, in_len, size, RSA_DEC) == STS_OK) { #elif CP_RSAPD == PKCS2 if (pad_pkcs2(eb, &pad_len, in_len, size, RSA_DEC) == STS_OK) { #endif size = size - pad_len; if (size <= *out_len) { memset(out, 0, size); bn_write_bin(out, size, eb); *out_len = size; } else { result = STS_ERR; } } else { result = STS_ERR; } } CATCH_ANY { result = STS_ERR; } FINALLY { bn_free(m); bn_free(eb); } return result; } #endif #if CP_RSA == BASIC || !defined(STRIP) int cp_rsa_sig_basic(uint8_t *sig, int *sig_len, uint8_t *msg, int msg_len, int hash, rsa_t prv) { bn_t m, eb; int size, pad_len, result = STS_OK; uint8_t h[MD_LEN]; if (prv == NULL || msg_len < 0) { return STS_ERR; } pad_len = (!hash ? MD_LEN : msg_len); #if CP_RSAPD == PKCS2 size = bn_bits(prv->n) - 1; size = (size / 8) + (size % 8 > 0); if (pad_len > (size - 2)) { return STS_ERR; } #else bn_size_bin(&size, prv->n); if (pad_len > (size - RSA_PAD_LEN)) { return STS_ERR; } #endif bn_null(m); bn_null(eb); TRY { bn_new(m); bn_new(eb); bn_zero(m); bn_zero(eb); int operation = (!hash ? RSA_SIG : RSA_SIG_HASH); #if CP_RSAPD == BASIC if (pad_basic(eb, &pad_len, pad_len, size, operation) == STS_OK) { #elif CP_RSAPD == PKCS1 if (pad_pkcs1(eb, &pad_len, pad_len, size, operation) == STS_OK) { #elif CP_RSAPD == PKCS2 if (pad_pkcs2(eb, &pad_len, pad_len, size, operation) == STS_OK) { #endif if (!hash) { md_map(h, msg, msg_len); bn_read_bin(m, h, MD_LEN); bn_add(eb, eb, m); } else { bn_read_bin(m, msg, msg_len); bn_add(eb, eb, m); } #if CP_RSAPD == PKCS2 pad_pkcs2(eb, &pad_len, bn_bits(prv->n), size, RSA_SIG_FIN); #endif bn_mxp(eb, eb, prv->d, prv->n); bn_size_bin(&size, prv->n); if (size <= *sig_len) { memset(sig, 0, size); bn_write_bin(sig, size, eb); *sig_len = size; } else { result = STS_ERR; } } else { result = STS_ERR; } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(m); bn_free(eb); } return result; } #endif #if CP_RSA == QUICK || !defined(STRIP) int cp_rsa_sig_quick(uint8_t *sig, int *sig_len, uint8_t *msg, int msg_len, int hash, rsa_t prv) { bn_t m, eb; int pad_len, size, result = STS_OK; uint8_t h[MD_LEN]; if (prv == NULL || msg_len < 0) { return STS_ERR; } pad_len = (!hash ? MD_LEN : msg_len); #if CP_RSAPD == PKCS2 size = bn_bits(prv->n) - 1; size = (size / 8) + (size % 8 > 0); if (pad_len > (size - 2)) { return STS_ERR; } #else bn_size_bin(&size, prv->n); if (pad_len > (size - RSA_PAD_LEN)) { return STS_ERR; } #endif bn_null(m); bn_null(eb); TRY { bn_new(m); bn_new(eb); bn_zero(m); bn_zero(eb); int operation = (!hash ? RSA_SIG : RSA_SIG_HASH); #if CP_RSAPD == BASIC if (pad_basic(eb, &pad_len, pad_len, size, operation) == STS_OK) { #elif CP_RSAPD == PKCS1 if (pad_pkcs1(eb, &pad_len, pad_len, size, operation) == STS_OK) { #elif CP_RSAPD == PKCS2 if (pad_pkcs2(eb, &pad_len, pad_len, size, operation) == STS_OK) { #endif if (!hash) { md_map(h, msg, msg_len); bn_read_bin(m, h, MD_LEN); bn_add(eb, eb, m); } else { bn_read_bin(m, msg, msg_len); bn_add(eb, eb, m); } #if CP_RSAPD == PKCS2 pad_pkcs2(eb, &pad_len, bn_bits(prv->n), size, RSA_SIG_FIN); #endif bn_copy(m, eb); /* m1 = c^dP mod p. */ bn_mxp(eb, eb, prv->dp, prv->p); /* m2 = c^dQ mod q. */ bn_mxp(m, m, prv->dq, prv->q); /* m1 = m1 - m2 mod p. */ bn_sub(eb, eb, m); while (bn_sign(eb) == BN_NEG) { bn_add(eb, eb, prv->p); } bn_mod(eb, eb, prv->p); /* m1 = qInv(m1 - m2) mod p. */ bn_mul(eb, eb, prv->qi); bn_mod(eb, eb, prv->p); /* m = m2 + m1 * q. */ bn_mul(eb, eb, prv->q); bn_add(eb, eb, m); bn_mod(eb, eb, prv->n); bn_size_bin(&size, prv->n); if (size <= *sig_len) { memset(sig, 0, size); bn_write_bin(sig, size, eb); *sig_len = size; } else { result = STS_ERR; } } else { result = STS_ERR; } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(m); bn_free(eb); } return result; } #endif int cp_rsa_ver(uint8_t *sig, int sig_len, uint8_t *msg, int msg_len, int hash, rsa_t pub) { bn_t m, eb; int size, pad_len, result; uint8_t h1[MAX(msg_len, MD_LEN) + 8], h2[MAX(msg_len, MD_LEN)]; /* We suppose that the signature is invalid. */ result = 0; if (pub == NULL || msg_len < 0) { return 0; } pad_len = (!hash ? MD_LEN : msg_len); #if CP_RSAPD == PKCS2 size = bn_bits(pub->n) - 1; if (size % 8 == 0) { size = size / 8 - 1; } else { bn_size_bin(&size, pub->n); } if (pad_len > (size - 2)) { return 0; } #else bn_size_bin(&size, pub->n); if (pad_len > (size - RSA_PAD_LEN)) { return 0; } #endif bn_null(m); bn_null(eb); TRY { bn_new(m); bn_new(eb); bn_read_bin(eb, sig, sig_len); bn_mxp(eb, eb, pub->e, pub->n); int operation = (!hash ? RSA_VER : RSA_VER_HASH); #if CP_RSAPD == BASIC if (pad_basic(eb, &pad_len, MD_LEN, size, operation) == STS_OK) { #elif CP_RSAPD == PKCS1 if (pad_pkcs1(eb, &pad_len, MD_LEN, size, operation) == STS_OK) { #elif CP_RSAPD == PKCS2 if (pad_pkcs2(eb, &pad_len, bn_bits(pub->n), size, operation) == STS_OK) { #endif #if CP_RSAPD == PKCS2 memset(h1, 0, 8); if (!hash) { md_map(h1 + 8, msg, msg_len); md_map(h2, h1, MD_LEN + 8); memset(h1, 0, MD_LEN); bn_write_bin(h1, size - pad_len, eb); /* Everything went ok, so signature status is changed. */ result = util_cmp_const(h1, h2, MD_LEN); } else { memcpy(h1 + 8, msg, msg_len); md_map(h2, h1, MD_LEN + 8); memset(h1, 0, msg_len); bn_write_bin(h1, size - pad_len, eb); /* Everything went ok, so signature status is changed. */ result = util_cmp_const(h1, h2, msg_len); } #else memset(h1, 0, MAX(msg_len, MD_LEN)); bn_write_bin(h1, size - pad_len, eb); if (!hash) { md_map(h2, msg, msg_len); /* Everything went ok, so signature status is changed. */ result = util_cmp_const(h1, h2, MD_LEN); } else { /* Everything went ok, so signature status is changed. */ result = util_cmp_const(h1, msg, msg_len); } #endif result = (result == CMP_EQ ? 1 : 0); } else { result = 0; } } CATCH_ANY { result = 0; } FINALLY { bn_free(m); bn_free(eb); } return result; }
/** * Computes the final exponentiation of a pairing defined over a Barreto-Naehrig * curve. * * @param[out] c - the result. * @param[in] a - the extension field element to exponentiate. */ static void pp_exp_bn(fp12_t c, fp12_t a) { fp12_t t0, t1, t2, t3; int l = MAX_TERMS + 1, b[MAX_TERMS + 1]; bn_t x; fp12_null(t0); fp12_null(t1); fp12_null(t2); fp12_null(t3); bn_null(x); TRY { fp12_new(t0); fp12_new(t1); fp12_new(t2); fp12_new(t3); bn_new(x); /* * New final exponentiation following Fuentes-Castañeda, Knapp and * Rodríguez-Henríquez: Fast Hashing to G_2. */ fp_param_get_var(x); fp_param_get_sps(b, &l); /* First, compute m = f^(p^6 - 1)(p^2 + 1). */ fp12_conv_cyc(c, a); /* Now compute m^((p^4 - p^2 + 1) / r). */ /* t0 = m^2x. */ fp12_exp_cyc_sps(t0, c, b, l); fp12_sqr_cyc(t0, t0); /* t1 = m^6x. */ fp12_sqr_cyc(t1, t0); fp12_mul(t1, t1, t0); /* t2 = m^6x^2. */ fp12_exp_cyc_sps(t2, t1, b, l); /* t3 = m^12x^3. */ fp12_sqr_cyc(t3, t2); fp12_exp_cyc_sps(t3, t3, b, l); if (bn_sign(x) == BN_NEG) { fp12_inv_uni(t0, t0); fp12_inv_uni(t1, t1); fp12_inv_uni(t3, t3); } /* t3 = a = m^12x^3 * m^6x^2 * m^6x. */ fp12_mul(t3, t3, t2); fp12_mul(t3, t3, t1); /* t0 = b = 1/(m^2x) * t3. */ fp12_inv_uni(t0, t0); fp12_mul(t0, t0, t3); /* Compute t2 * t3 * m * b^p * a^p^2 * [b * 1/m]^p^3. */ fp12_mul(t2, t2, t3); fp12_mul(t2, t2, c); fp12_inv_uni(c, c); fp12_mul(c, c, t0); fp12_frb(c, c, 3); fp12_mul(c, c, t2); fp12_frb(t0, t0, 1); fp12_mul(c, c, t0); fp12_frb(t3, t3, 2); fp12_mul(c, c, t3); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fp12_free(t0); fp12_free(t1); fp12_free(t2); fp12_free(t3); bn_free(x); } }
void pp_map_sim_oatep_k12(fp12_t r, ep_t *p, ep2_t *q, int m) { ep_t _p[m]; ep2_t t[m], _q[m]; bn_t a; int i, j, len = FP_BITS, s[FP_BITS]; TRY { bn_null(a); bn_new(a); for (i = 0; i < m; i++) { ep_null(_p[i]); ep2_null(_q[i]); ep2_null(t[i]); ep_new(_p[i]); ep2_new(_q[i]); ep2_new(t[i]); } j = 0; for (i = 0; i < m; i++) { if (!ep_is_infty(p[i]) && !ep2_is_infty(q[i])) { ep_norm(_p[j], p[i]); ep2_norm(_q[j++], q[i]); } } fp12_set_dig(r, 1); fp_param_get_var(a); bn_mul_dig(a, a, 6); bn_add_dig(a, a, 2); fp_param_get_map(s, &len); if (j > 0) { switch (ep_param_get()) { case BN_P158: case BN_P254: case BN_P256: case BN_P638: /* r = f_{|a|,Q}(P). */ pp_mil_sps_k12(r, t, _q, _p, j, s, len); if (bn_sign(a) == BN_NEG) { /* f_{-a,Q}(P) = 1/f_{a,Q}(P). */ fp12_inv_uni(r, r); } for (i = 0; i < j; i++) { if (bn_sign(a) == BN_NEG) { ep2_neg(t[i], t[i]); } pp_fin_k12_oatep(r, t[i], _q[i], _p[i]); } pp_exp_k12(r, r); break; case B12_P638: /* r = f_{|a|,Q}(P). */ pp_mil_sps_k12(r, t, _q, _p, j, s, len); if (bn_sign(a) == BN_NEG) { fp12_inv_uni(r, r); } pp_exp_k12(r, r); break; } } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(a); for (i = 0; i < m; i++) { ep_free(_p[i]); ep2_free(_q[i]); ep2_free(t[i]); } } }
/** * Multiplies and adds two prime elliptic curve points simultaneously, * optionally choosing the first point as the generator depending on an optional * table of precomputed points. * * @param[out] r - the result. * @param[in] p - the first point to multiply. * @param[in] k - the first integer. * @param[in] q - the second point to multiply. * @param[in] m - the second integer. * @param[in] t - the pointer to the precomputed table. */ static void ep_mul_sim_plain(ep_t r, const ep_t p, const bn_t k, const ep_t q, const bn_t m, const ep_t *t) { int i, l, l0, l1, n0, n1, w, gen; int8_t naf0[FP_BITS + 1], naf1[FP_BITS + 1], *_k, *_m; ep_t t0[1 << (EP_WIDTH - 2)]; ep_t t1[1 << (EP_WIDTH - 2)]; for (i = 0; i < (1 << (EP_WIDTH - 2)); i++) { ep_null(t0[i]); ep_null(t1[i]); } TRY { gen = (t == NULL ? 0 : 1); if (!gen) { for (i = 0; i < (1 << (EP_WIDTH - 2)); i++) { ep_new(t0[i]); } ep_tab(t0, p, EP_WIDTH); t = (const ep_t *)t0; } /* Prepare the precomputation table. */ for (i = 0; i < (1 << (EP_WIDTH - 2)); i++) { ep_new(t1[i]); } /* Compute the precomputation table. */ ep_tab(t1, q, EP_WIDTH); /* Compute the w-TNAF representation of k. */ if (gen) { w = EP_DEPTH; } else { w = EP_WIDTH; } l0 = l1 = FP_BITS + 1; bn_rec_naf(naf0, &l0, k, w); bn_rec_naf(naf1, &l1, m, EP_WIDTH); l = MAX(l0, l1); for (i = l0; i < l; i++) { naf0[i] = 0; } for (i = l1; i < l; i++) { naf1[i] = 0; } if (bn_sign(k) == BN_NEG) { for (i = 0; i < l0; i++) { naf0[i] = -naf0[i]; } } if (bn_sign(m) == BN_NEG) { for (i = 0; i < l1; i++) { naf1[i] = -naf1[i]; } } _k = naf0 + l - 1; _m = naf1 + l - 1; ep_set_infty(r); for (i = l - 1; i >= 0; i--, _k--, _m--) { ep_dbl(r, r); n0 = *_k; n1 = *_m; if (n0 > 0) { ep_add(r, r, t[n0 / 2]); } if (n0 < 0) { ep_sub(r, r, t[-n0 / 2]); } if (n1 > 0) { ep_add(r, r, t1[n1 / 2]); } if (n1 < 0) { ep_sub(r, r, t1[-n1 / 2]); } } /* Convert r to affine coordinates. */ ep_norm(r, r); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { /* Free the precomputation tables. */ if (!gen) { for (i = 0; i < 1 << (EP_WIDTH - 2); i++) { ep_free(t0[i]); } } for (i = 0; i < 1 << (EP_WIDTH - 2); i++) { ep_free(t1[i]); } } }
static void ed_mul_naf_imp(ed_t r, const ed_t p, const bn_t k) { int l, i, n; int8_t naf[RLC_FP_BITS + 1]; ed_t t[1 << (ED_WIDTH - 2)]; if (bn_is_zero(k)) { ed_set_infty(r); return; } TRY { /* Prepare the precomputation table. */ for (i = 0; i < (1 << (ED_WIDTH - 2)); i++) { ed_null(t[i]); ed_new(t[i]); } /* Compute the precomputation table. */ ed_tab(t, p, ED_WIDTH); /* Compute the w-NAF representation of k. */ l = sizeof(naf); bn_rec_naf(naf, &l, k, EP_WIDTH); ed_set_infty(r); for (i = l - 1; i > 0; i--) { n = naf[i]; if (n == 0) { /* This point will be doubled in the previous iteration. */ r->norm = 2; ed_dbl(r, r); } else { ed_dbl(r, r); if (n > 0) { ed_add(r, r, t[n / 2]); } else if (n < 0) { ed_sub(r, r, t[-n / 2]); } } } /* Last iteration. */ n = naf[0]; ed_dbl(r, r); if (n > 0) { ed_add(r, r, t[n / 2]); } else if (n < 0) { ed_sub(r, r, t[-n / 2]); } /* Convert r to affine coordinates. */ ed_norm(r, r); if (bn_sign(k) == RLC_NEG) { ed_neg(r, r); } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { /* Free the precomputation table. */ for (i = 0; i < (1 << (ED_WIDTH - 2)); i++) { ed_free(t[i]); } } }
void pp_map_oatep_k12(fp12_t r, ep_t p, ep2_t q) { ep_t _p[1]; ep2_t t[1], _q[1]; bn_t a; int len = FP_BITS, s[FP_BITS]; ep_null(_p[0]); ep2_null(_q[0]); ep2_null(t[0]); bn_null(a); TRY { ep_new(_p[0]); ep2_new(_q[0]); ep2_new(t[0]); bn_new(a); fp_param_get_var(a); bn_mul_dig(a, a, 6); bn_add_dig(a, a, 2); fp_param_get_map(s, &len); fp12_set_dig(r, 1); ep_norm(_p[0], p); ep2_norm(_q[0], q); if (!ep_is_infty(_p[0]) && !ep2_is_infty(_q[0])) { switch (ep_param_get()) { case BN_P158: case BN_P254: case BN_P256: case BN_P638: /* r = f_{|a|,Q}(P). */ pp_mil_sps_k12(r, t, _q, _p, 1, s, len); if (bn_sign(a) == BN_NEG) { /* f_{-a,Q}(P) = 1/f_{a,Q}(P). */ fp12_inv_uni(r, r); ep2_neg(t[0], t[0]); } pp_fin_k12_oatep(r, t[0], _q[0], _p[0]); pp_exp_k12(r, r); break; case B12_P638: /* r = f_{|a|,Q}(P). */ pp_mil_sps_k12(r, t, _q, _p, 1, s, len); if (bn_sign(a) == BN_NEG) { fp12_inv_uni(r, r); ep2_neg(t[0], t[0]); } pp_exp_k12(r, r); break; } } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { ep_free(_p[0]); ep2_free(_q[0]); ep2_free(t[0]); bn_free(a); } }
void ed_mul_slide(ed_t r, const ed_t p, const bn_t k) { ed_t t[1 << (EP_WIDTH - 1)], q; int i, j, l; uint8_t win[RLC_FP_BITS + 1]; ed_null(q); if (bn_is_zero(k) || ed_is_infty(p)) { ed_set_infty(r); return; } TRY { for (i = 0; i < (1 << (EP_WIDTH - 1)); i ++) { ed_null(t[i]); ed_new(t[i]); } ed_new(q); ed_copy(t[0], p); ed_dbl(q, p); #if defined(EP_MIXED) ed_norm(q, q); #endif /* Create table. */ for (i = 1; i < (1 << (EP_WIDTH - 1)); i++) { ed_add(t[i], t[i - 1], q); } #if defined(EP_MIXED) ed_norm_sim(t + 1, (const ed_t *)t + 1, (1 << (EP_WIDTH - 1)) - 1); #endif ed_set_infty(q); l = RLC_FP_BITS + 1; bn_rec_slw(win, &l, k, EP_WIDTH); for (i = 0; i < l; i++) { if (win[i] == 0) { ed_dbl(q, q); } else { for (j = 0; j < util_bits_dig(win[i]); j++) { ed_dbl(q, q); } ed_add(q, q, t[win[i] >> 1]); } } ed_norm(r, q); if (bn_sign(k) == RLC_NEG) { ed_neg(r, r); } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { for (i = 0; i < (1 << (EP_WIDTH - 1)); i++) { ed_free(t[i]); } ed_free(q); } }
void fp_exp_slide(fp_t c, const fp_t a, const bn_t b) { fp_t t[1 << (FP_WIDTH - 1)], r; int i, j, l; uint8_t win[FP_BITS + 1]; fp_null(r); if (bn_is_zero(b)) { fp_set_dig(c, 1); return; } /* Initialize table. */ for (i = 0; i < (1 << (FP_WIDTH - 1)); i++) { fp_null(t[i]); } TRY { for (i = 0; i < (1 << (FP_WIDTH - 1)); i ++) { fp_new(t[i]); } fp_new(r); fp_copy(t[0], a); fp_sqr(r, a); /* Create table. */ for (i = 1; i < 1 << (FP_WIDTH - 1); i++) { fp_mul(t[i], t[i - 1], r); } fp_set_dig(r, 1); l = FP_BITS + 1; bn_rec_slw(win, &l, b, FP_WIDTH); for (i = 0; i < l; i++) { if (win[i] == 0) { fp_sqr(r, r); } else { for (j = 0; j < util_bits_dig(win[i]); j++) { fp_sqr(r, r); } fp_mul(r, r, t[win[i] >> 1]); } } if (bn_sign(b) == BN_NEG) { fp_inv(c, r); } else { fp_copy(c, r); } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { for (i = 0; i < (1 << (FP_WIDTH - 1)); i++) { fp_free(t[i]); } fp_free(r); } }
void fp_param_get_sps(int *s, int *len) { bn_t a; bn_null(a); if (*len < MAX_TERMS) { THROW(ERR_NO_BUFFER); } TRY { bn_new(a); *len = 0; switch (fp_param_get()) { case BN_158: case BN_254: case BN_256: fp_param_get_var(a); if (bn_sign(a) == BN_NEG) { bn_neg(a, a); } *len = bn_ham(a); for (int i = 0, j = 0; j < bn_bits(a); j++) { if (bn_test_bit(a, j)) { s[i++] = j; } } break; case B24_477: s[0] = 7; s[1] = -31; s[2] = -45; s[3] = 48; *len = 4; break; case KSS_508: s[0] = -12; s[1] = -46; s[2] = 51; s[3] = 64; *len = 4; break; case BN_638: s[0] = 0; s[1] = -68; s[2] = -128; s[3] = 158; *len = 4; break; case B12_638: s[0] = -5; s[1] = -93; s[2] = -105; s[3] = 107; *len = 4; break; case SS_1536: s[0] = 0; s[1] = 41; s[2] = 255; *len = 3; break; default: THROW(ERR_NO_VALID); break; } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(a); } }
int bn_is_prime_solov(const bn_t a) { bn_t t0, t1, t2; int i, result; bn_null(t0); bn_null(t1); bn_null(t2); result = 1; TRY { bn_new(t0); bn_new(t1); bn_new(t2); for (i = 0; i < 100; i++) { /* Generate t0, 2 <= t0, <= a - 2. */ do { bn_rand(t0, BN_POS, bn_bits(a)); bn_mod(t0, t0, a); } while (bn_cmp_dig(t0, 2) == CMP_LT); /* t2 = a - 1. */ bn_copy(t2, a); bn_sub_dig(t2, t2, 1); /* t1 = (a - 1)/2. */ bn_rsh(t1, t2, 1); /* t1 = t0^(a - 1)/2 mod a. */ #if BN_MOD != PMERS bn_mxp(t1, t0, t1, a); #else bn_exp(t1, t0, t1, a); #endif /* If t1 != 1 and t1 != n - 1 return 0 */ if (bn_cmp_dig(t1, 1) != CMP_EQ && bn_cmp(t1, t2) != CMP_EQ) { result = 0; break; } /* t2 = (t0|a). */ bn_smb_jac(t2, t0, a); if (bn_sign(t2) == BN_NEG) { bn_add(t2, t2, a); } /* If t1 != t2 (mod a) return 0. */ bn_mod(t1, t1, a); bn_mod(t2, t2, a); if (bn_cmp(t1, t2) != CMP_EQ) { result = 0; break; } } } CATCH_ANY { result = 0; THROW(ERR_CAUGHT); } FINALLY { bn_free(t0); bn_free(t1); bn_free(t2); } return result; }
void ep_mul_sim_trick(ep_t r, const ep_t p, const bn_t k, const ep_t q, const bn_t m) { ep_t t0[1 << (EP_WIDTH / 2)], t1[1 << (EP_WIDTH / 2)], t[1 << EP_WIDTH]; bn_t n; int l0, l1, w = EP_WIDTH / 2; uint8_t w0[CEIL(FP_BITS + 1, w)], w1[CEIL(FP_BITS + 1, w)]; bn_null(n); if (bn_is_zero(k) || ep_is_infty(p)) { ep_mul(r, q, m); return; } if (bn_is_zero(m) || ep_is_infty(q)) { ep_mul(r, p, k); return; } TRY { bn_new(n); ep_curve_get_ord(n); for (int i = 0; i < (1 << w); i++) { ep_null(t0[i]); ep_null(t1[i]); ep_new(t0[i]); ep_new(t1[i]); } for (int i = 0; i < (1 << EP_WIDTH); i++) { ep_null(t[i]); ep_new(t[i]); } ep_set_infty(t0[0]); ep_copy(t0[1], p); if (bn_sign(k) == BN_NEG) { ep_neg(t0[1], t0[1]); } for (int i = 2; i < (1 << w); i++) { ep_add(t0[i], t0[i - 1], t0[1]); } ep_set_infty(t1[0]); ep_copy(t1[1], q); if (bn_sign(m) == BN_NEG) { ep_neg(t1[1], t1[1]); } for (int i = 1; i < (1 << w); i++) { ep_add(t1[i], t1[i - 1], t1[1]); } for (int i = 0; i < (1 << w); i++) { for (int j = 0; j < (1 << w); j++) { ep_add(t[(i << w) + j], t0[i], t1[j]); } } #if defined(EP_MIXED) ep_norm_sim(t + 1, (const ep_t *)t + 1, (1 << (EP_WIDTH)) - 1); #endif l0 = l1 = CEIL(FP_BITS, w); bn_rec_win(w0, &l0, k, w); bn_rec_win(w1, &l1, m, w); for (int i = l0; i < l1; i++) { w0[i] = 0; } for (int i = l1; i < l0; i++) { w1[i] = 0; } ep_set_infty(r); for (int i = MAX(l0, l1) - 1; i >= 0; i--) { for (int j = 0; j < w; j++) { ep_dbl(r, r); } ep_add(r, r, t[(w0[i] << w) + w1[i]]); } ep_norm(r, r); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(n); for (int i = 0; i < (1 << w); i++) { ep_free(t0[i]); ep_free(t1[i]); } for (int i = 0; i < (1 << EP_WIDTH); i++) { ep_free(t[i]); } } }
int cp_rsa_gen_quick(rsa_t pub, rsa_t prv, int bits) { bn_t t, r; int result = STS_OK; if (pub == NULL || prv == NULL || bits == 0) { return STS_ERR; } bn_null(t); bn_null(r); TRY { bn_new(t); bn_new(r); /* Generate different primes p and q. */ do { bn_gen_prime(prv->p, bits / 2); bn_gen_prime(prv->q, bits / 2); } while (bn_cmp(prv->p, prv->q) == CMP_EQ); /* Swap p and q so that p is smaller. */ if (bn_cmp(prv->p, prv->q) == CMP_LT) { bn_copy(t, prv->p); bn_copy(prv->p, prv->q); bn_copy(prv->q, t); } /* n = pq. */ bn_mul(pub->n, prv->p, prv->q); bn_copy(prv->n, pub->n); bn_sub_dig(prv->p, prv->p, 1); bn_sub_dig(prv->q, prv->q, 1); /* phi(n) = (p - 1)(q - 1). */ bn_mul(t, prv->p, prv->q); bn_set_2b(pub->e, 16); bn_add_dig(pub->e, pub->e, 1); /* d = e^(-1) mod phi(n). */ bn_gcd_ext(r, prv->d, NULL, pub->e, t); if (bn_sign(prv->d) == BN_NEG) { bn_add(prv->d, prv->d, t); } if (bn_cmp_dig(r, 1) == CMP_EQ) { /* dP = d mod (p - 1). */ bn_mod(prv->dp, prv->d, prv->p); /* dQ = d mod (q - 1). */ bn_mod(prv->dq, prv->d, prv->q); bn_add_dig(prv->p, prv->p, 1); bn_add_dig(prv->q, prv->q, 1); /* qInv = q^(-1) mod p. */ bn_gcd_ext(r, prv->qi, NULL, prv->q, prv->p); if (bn_sign(prv->qi) == BN_NEG) { bn_add(prv->qi, prv->qi, prv->p); } result = STS_OK; } } CATCH_ANY { result = STS_ERR; } FINALLY { bn_free(t); bn_free(r); } return result; }
void ep_mul_sim_joint(ep_t r, const ep_t p, const bn_t k, const ep_t q, const bn_t m) { ep_t t[5]; int i, u_i, len, offset; int8_t jsf[2 * (FP_BITS + 1)]; if (bn_is_zero(k) || ep_is_infty(p)) { ep_mul(r, q, m); return; } if (bn_is_zero(m) || ep_is_infty(q)) { ep_mul(r, p, k); return; } TRY { for (i = 0; i < 5; i++) { ep_null(t[i]); ep_new(t[i]); } ep_set_infty(t[0]); ep_copy(t[1], q); if (bn_sign(m) == BN_NEG) { ep_neg(t[1], t[1]); } ep_copy(t[2], p); if (bn_sign(k) == BN_NEG) { ep_neg(t[2], t[2]); } ep_add(t[3], t[2], t[1]); ep_sub(t[4], t[2], t[1]); #if defined(EP_MIXED) ep_norm_sim(t + 3, (const ep_t *)t + 3, 2); #endif len = 2 * (FP_BITS + 1); bn_rec_jsf(jsf, &len, k, m); ep_set_infty(r); offset = MAX(bn_bits(k), bn_bits(m)) + 1; for (i = len - 1; i >= 0; i--) { ep_dbl(r, r); if (jsf[i] != 0 && jsf[i] == -jsf[i + offset]) { u_i = jsf[i] * 2 + jsf[i + offset]; if (u_i < 0) { ep_sub(r, r, t[4]); } else { ep_add(r, r, t[4]); } } else { u_i = jsf[i] * 2 + jsf[i + offset]; if (u_i < 0) { ep_sub(r, r, t[-u_i]); } else { ep_add(r, r, t[u_i]); } } } ep_norm(r, r); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { for (i = 0; i < 5; i++) { ep_free(t[i]); } } }
/** * Divides two multiple precision integers, computing the quotient and the * remainder. * * @param[out] c - the quotient. * @param[out] d - the remainder. * @param[in] a - the dividend. * @param[in] b - the the divisor. */ static void bn_div_imp(bn_t c, bn_t d, const bn_t a, const bn_t b) { bn_t q, x, y, r; int sign; bn_null(q); bn_null(x); bn_null(y); bn_null(r); /* If a < b, we're done. */ if (bn_cmp_abs(a, b) == CMP_LT) { if (bn_sign(a) == BN_POS) { if (c != NULL) { bn_zero(c); } if (d != NULL) { bn_copy(d, a); } } else { if (c != NULL) { bn_set_dig(c, 1); if (bn_sign(b) == BN_POS) { bn_neg(c, c); } } if (d != NULL) { if (bn_sign(b) == BN_POS) { bn_add(d, a, b); } else { bn_sub(d, a, b); } } } return; } TRY { bn_new(x); bn_new(y); bn_new_size(q, a->used + 1); bn_new(r); bn_zero(q); bn_zero(r); bn_abs(x, a); bn_abs(y, b); /* Find the sign. */ sign = (a->sign == b->sign ? BN_POS : BN_NEG); bn_divn_low(q->dp, r->dp, x->dp, a->used, y->dp, b->used); /* We have the quotient in q and the remainder in r. */ if (c != NULL) { q->used = a->used - b->used + 1; q->sign = sign; bn_trim(q); if (bn_sign(a) == BN_NEG) { bn_sub_dig(c, q, 1); } else { bn_copy(c, q); } } if (d != NULL) { r->used = b->used; r->sign = a->sign; bn_trim(r); if (bn_sign(a) == BN_NEG) { bn_add(d, r, b); } else { bn_copy(d, r); } } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(r); bn_free(q); bn_free(x); bn_free(y); } }
/** * Computes the final exponentiation of a pairing defined over a * Barreto-Lynn-Scott curve. * * @param[out] c - the result. * @param[in] a - the extension field element to exponentiate. */ static void pp_exp_b12(fp12_t c, fp12_t a) { fp12_t t[10]; bn_t x; int l = MAX_TERMS + 1, b[MAX_TERMS + 1]; bn_null(x); TRY { for (int i = 0; i < 10; i++) { fp12_null(t[i]); fp12_new(t[i]); } bn_new(x); fp_param_get_var(x); fp_param_get_sps(b, &l); /* First, compute m^(p^6 - 1)(p^2 + 1). */ fp12_conv_cyc(c, a); /* v0 = f^-1. */ fp12_inv_uni(t[0], c); /* v1 = f^-2. */ fp12_sqr_cyc(t[1], t[0]); /* v2 = f^x. */ fp12_exp_cyc_sps(t[2], c, b, l); if (bn_sign(x) == BN_NEG) { fp12_inv_uni(t[2], t[2]); } /* v3 = f^2x. */ fp12_sqr_cyc(t[3], t[2]); /* v4 = f^(x - 2). */ fp12_mul(t[4], t[2], t[1]); /* v5 = f^(x^2 - 2x). */ fp12_exp_cyc_sps(t[5], t[4], b, l); if (bn_sign(x) == BN_NEG) { fp12_inv_uni(t[5], t[5]); } /* v6 = f^(x^3 - 2x^2). */ fp12_exp_cyc_sps(t[6], t[5], b, l); if (bn_sign(x) == BN_NEG) { fp12_inv_uni(t[6], t[6]); } /* v7 = f^(x^4 - 2x^3 + 2x). */ fp12_exp_cyc_sps(t[7], t[6], b, l); if (bn_sign(x) == BN_NEG) { fp12_inv_uni(t[7], t[7]); } fp12_mul(t[7], t[7], t[3]); /* v8 = f^(x^5 - 2x^4 + 2x^2). */ fp12_exp_cyc_sps(t[8], t[7], b, l); if (bn_sign(x) == BN_NEG) { fp12_inv_uni(t[8], t[8]); } /* v7 = f^(x^4 - 2x^3 + 2x - 1)^p. */ fp12_mul(t[7], t[7], t[0]); fp12_frb(t[7], t[7], 1); /* v6 = f^(x^3 - 2x^2 + x)^p^2. */ fp12_mul(t[6], t[6], t[2]); fp12_frb(t[6], t[6], 2); /* v5 = f^(x^2 - 2x + 1)^p^3. */ fp12_mul(t[5], t[5], c); fp12_frb(t[5], t[5], 1); fp12_frb(t[5], t[5], 2); /* v4 = f^(2 - x). */ fp12_inv_uni(t[4], t[4]); /* Now compute f * v4 * v5 * v6 * v7 * v8. */ fp12_mul(c, c, t[4]); fp12_mul(c, c, t[5]); fp12_mul(c, c, t[6]); fp12_mul(c, c, t[7]); fp12_mul(c, c, t[8]); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { for (int i = 0; i < 9; i++) { fp12_free(t[i]); } bn_free(x); } }