/** * 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]); } } }
/** * 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); } }
/** * 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]); } } }