void ep_dbl_projc(ep_t r, const ep_t p) { if (ep_is_infty(p)) { ep_set_infty(r); return; } if (fp_is_zero(p->x)) { ep_set_infty(r); return; } ep_dbl_projc_imp(r, p); }
void ep_sub_basic(ep_t r, const ep_t p, const ep_t q) { ep_t t; ep_null(t); if (p == q) { ep_set_infty(r); return; } TRY { ep_new(t); ep_neg_basic(t, q); ep_add_basic(r, p, t); r->norm = 1; } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { ep_free(t); } }
void ep_dbl_basic(ep_t r, const ep_t p) { if (ep_is_infty(p)) { ep_set_infty(r); return; } ep_dbl_basic_imp(r, NULL, p); }
void ep_curve_init(void) { ctx_t *ctx = core_get(); #ifdef EP_PRECO for (int i = 0; i < RELIC_EP_TABLE; i++) { ctx->ep_ptr[i] = &(ctx->ep_pre[i]); } #endif #if ALLOC == STATIC fp_new(ctx->ep_g.x); fp_new(ctx->ep_g.y); fp_new(ctx->ep_g.z); #ifdef EP_PRECO for (int i = 0; i < RELIC_EP_TABLE; i++) { fp_new(ctx->ep_pre[i].x); fp_new(ctx->ep_pre[i].y); fp_new(ctx->ep_pre[i].z); } #endif #endif ep_set_infty(&ctx->ep_g); bn_init(&ctx->ep_r, FP_DIGS); bn_init(&ctx->ep_h, FP_DIGS); #if defined(EP_ENDOM) && (EP_MUL == LWNAF || EP_FIX == COMBS || EP_FIX == LWNAF || !defined(STRIP)) for (int i = 0; i < 3; i++) { bn_init(&(ctx->ep_v1[i]), FP_DIGS); bn_init(&(ctx->ep_v2[i]), FP_DIGS); } #endif }
void ep_dbl_slp_basic(ep_t r, fp_t s, const ep_t p) { if (ep_is_infty(p)) { ep_set_infty(r); return; } ep_dbl_basic_imp(r, s, p); }
void ep_neg_projc(ep_t r, const ep_t p) { if (ep_is_infty(p)) { ep_set_infty(r); return; } if (r != p) { fp_copy(r->x, p->x); fp_copy(r->z, p->z); } fp_neg(r->y, p->y); r->norm = p->norm; }
void ep_read_bin(ep_t a, const uint8_t *bin, int len) { if (len == 1) { if (bin[0] == 0) { ep_set_infty(a); return; } else { THROW(ERR_NO_BUFFER); return; } } if (len != (FP_BYTES + 1) && len != (2 * FP_BYTES + 1)) { THROW(ERR_NO_BUFFER); return; } a->norm = 1; fp_set_dig(a->z, 1); fp_read_bin(a->x, bin + 1, FP_BYTES); if (len == FP_BYTES + 1) { switch(bin[0]) { case 2: fp_zero(a->y); break; case 3: fp_zero(a->y); fp_set_bit(a->y, 0, 1); break; default: THROW(ERR_NO_VALID); break; } ep_upk(a, a); } if (len == 2 * FP_BYTES + 1) { if (bin[0] == 4) { fp_read_bin(a->y, bin + FP_BYTES + 1, FP_BYTES); } else { THROW(ERR_NO_VALID); } } }
/** * 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]); } } }
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 u_i, len, offset; int8_t jsf[2 * (FP_BITS + 1)]; int i; ep_null(t[0]); ep_null(t[1]); ep_null(t[2]); ep_null(t[3]); ep_null(t[4]); TRY { for (i = 0; i < 5; i++) { ep_new(t[i]); } ep_set_infty(t[0]); ep_copy(t[1], q); ep_copy(t[2], p); ep_add(t[3], p, q); ep_sub(t[4], p, q); #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]); } } }
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); for (int i = 0; i < 1 << EP_WIDTH; i++) { ep_null(t[i]); } for (int i = 0; i < 1 << (EP_WIDTH / 2); i++) { ep_null(t0[i]); ep_null(t1[i]); } TRY { bn_new(n); ep_curve_get_ord(n); for (int i = 0; i < (1 << w); i++) { ep_new(t0[i]); ep_new(t1[i]); } for (int i = 0; i < (1 << EP_WIDTH); i++) { ep_new(t[i]); } ep_set_infty(t0[0]); for (int i = 1; i < (1 << w); i++) { ep_add(t0[i], t0[i - 1], p); } ep_set_infty(t1[0]); for (int i = 1; i < (1 << w); i++) { ep_add(t1[i], t1[i - 1], q); } 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]); } } }
/** * 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 len, l0, l1, i, 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); len = MAX(l0, l1); _k = naf0 + len - 1; _m = naf1 + len - 1; for (i = l0; i < len; i++) naf0[i] = 0; for (i = l1; i < len; i++) naf1[i] = 0; ep_set_infty(r); for (i = len - 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]); } } }
/** * Adds two points represented in affine coordinates on an ordinary prime * elliptic curve. * * @param[out] r - the result. * @param[out] s - the slope. * @param[in] p - the first point to add. * @param[in] q - the second point to add. */ static void ep_add_basic_imp(ep_t r, fp_t s, const ep_t p, const ep_t q) { 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 = x2 - x1. */ fp_sub(t0, q->x, p->x); /* t1 = y2 - y1. */ fp_sub(t1, q->y, p->y); /* If t0 is zero. */ if (fp_is_zero(t0)) { if (fp_is_zero(t1)) { /* If t1 is zero, q = p, should have doubled. */ ep_dbl_basic(r, p); } else { /* If t1 is not zero and t0 is zero, q = -p and r = infinity. */ ep_set_infty(r); } } else { /* t2 = 1/(x2 - x1). */ fp_inv(t2, t0); /* t2 = lambda = (y2 - y1)/(x2 - x1). */ fp_mul(t2, t1, t2); /* x3 = lambda^2 - x2 - x1. */ fp_sqr(t1, t2); fp_sub(t0, t1, p->x); fp_sub(t0, t0, q->x); /* y3 = lambda * (x1 - x3) - y1. */ fp_sub(t1, p->x, t0); fp_mul(t1, t2, t1); fp_sub(r->y, t1, p->y); fp_copy(r->x, t0); fp_copy(r->z, p->z); if (s != NULL) { fp_copy(s, t2); } r->norm = 1; } fp_free(t0); fp_free(t1); fp_free(t2); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fp_free(t0); fp_free(t1); fp_free(t2); } }
/** * Adds two points represented in projective coordinates on an ordinary prime * elliptic curve. * * @param[out] r - the result. * @param[in] p - the first point to add. * @param[in] q - the second point to add. */ static void ep_add_projc_imp(ep_t r, const ep_t p, const ep_t q) { #if defined(EP_MIXED) && defined(STRIP) /* If code size is a problem, leave only the mixed version. */ ep_add_projc_mix(r, p, q); #else /* General addition. */ #if defined(EP_MIXED) || !defined(STRIP) /* Test if z2 = 1 only if mixed coordinates are turned on. */ if (q->norm) { ep_add_projc_mix(r, p, q); return; } #endif fp_t t0, t1, t2, t3, t4, t5, t6; fp_null(t0); fp_null(t1); fp_null(t2); fp_null(t3); fp_null(t4); fp_null(t5); fp_null(t6); TRY { fp_new(t0); fp_new(t1); fp_new(t2); fp_new(t3); fp_new(t4); fp_new(t5); fp_new(t6); /* add-2007-bl formulas: 11M + 5S + 9add + 4*2 */ /* http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl */ /* t0 = z1^2. */ fp_sqr(t0, p->z); /* t1 = z2^2. */ fp_sqr(t1, q->z); /* t2 = U1 = x1 * z2^2. */ fp_mul(t2, p->x, t1); /* t3 = U2 = x2 * z1^2. */ fp_mul(t3, q->x, t0); /* t6 = z1^2 + z2^2. */ fp_add(t6, t0, t1); /* t0 = S2 = y2 * z1^3. */ fp_mul(t0, t0, p->z); fp_mul(t0, t0, q->y); /* t1 = S1 = y1 * z2^3. */ fp_mul(t1, t1, q->z); fp_mul(t1, t1, p->y); /* t3 = H = U2 - U1. */ fp_sub(t3, t3, t2); /* t0 = R = 2 * (S2 - S1). */ fp_sub(t0, t0, t1); fp_dbl(t0, t0); /* If E is zero. */ if (fp_is_zero(t3)) { if (fp_is_zero(t0)) { /* If I is zero, p = q, should have doubled. */ ep_dbl_projc(r, p); } else { /* If I is not zero, q = -p, r = infinity. */ ep_set_infty(r); } } else { /* t4 = I = (2*H)^2. */ fp_dbl(t4, t3); fp_sqr(t4, t4); /* t5 = J = H * I. */ fp_mul(t5, t3, t4); /* t4 = V = U1 * I. */ fp_mul(t4, t2, t4); /* x3 = R^2 - J - 2 * V. */ fp_sqr(r->x, t0); fp_sub(r->x, r->x, t5); fp_dbl(t2, t4); fp_sub(r->x, r->x, t2); /* y3 = R * (V - x3) - 2 * S1 * J. */ fp_sub(t4, t4, r->x); fp_mul(t4, t4, t0); fp_mul(t1, t1, t5); fp_dbl(t1, t1); fp_sub(r->y, t4, t1); /* z3 = ((z1 + z2)^2 - z1^2 - z2^2) * H. */ fp_add(r->z, p->z, q->z); fp_sqr(r->z, r->z); fp_sub(r->z, r->z, t6); fp_mul(r->z, r->z, t3); } r->norm = 0; } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fp_free(t0); fp_free(t1); fp_free(t2); fp_free(t3); fp_free(t4); fp_free(t5); fp_free(t6); } #endif }
/** * Adds a point represented in affine coordinates to a point represented in * projective coordinates. * * @param[out] r - the result. * @param[in] p - the projective point. * @param[in] q - the affine point. */ static void ep_add_projc_mix(ep_t r, const ep_t p, const ep_t q) { fp_t t0, t1, t2, t3, t4, t5, t6; fp_null(t0); fp_null(t1); fp_null(t2); fp_null(t3); fp_null(t4); fp_null(t5); fp_null(t6); TRY { fp_new(t0); fp_new(t1); fp_new(t2); fp_new(t3); fp_new(t4); fp_new(t5); fp_new(t6); /* madd-2007-bl formulas: 7M + 4S + 9add + 1*4 + 3*2. */ /* http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-madd-2007-bl */ if (!p->norm) { /* t0 = z1^2. */ fp_sqr(t0, p->z); /* t3 = U2 = x2 * z1^2. */ fp_mul(t3, q->x, t0); /* t1 = S2 = y2 * z1^3. */ fp_mul(t1, t0, p->z); fp_mul(t1, t1, q->y); /* t3 = H = U2 - x1. */ fp_sub(t3, t3, p->x); /* t1 = R = 2 * (S2 - y1). */ fp_sub(t1, t1, p->y); fp_dbl(t1, t1); } else { /* H = x2 - x1. */ fp_sub(t3, q->x, p->x); /* t1 = R = 2 * (y2 - y1). */ fp_sub(t1, q->y, p->y); fp_dbl(t1, t1); } /* t2 = HH = H^2. */ fp_sqr(t2, t3); /* If E is zero. */ if (fp_is_zero(t3)) { if (fp_is_zero(t1)) { /* If I is zero, p = q, should have doubled. */ ep_dbl_projc(r, p); } else { /* If I is not zero, q = -p, r = infinity. */ ep_set_infty(r); } } else { /* t4 = I = 4*HH. */ fp_dbl(t4, t2); fp_dbl(t4, t4); /* t5 = J = H * I. */ fp_mul(t5, t3, t4); /* t4 = V = x1 * I. */ fp_mul(t4, p->x, t4); /* x3 = R^2 - J - 2 * V. */ fp_sqr(r->x, t1); fp_sub(r->x, r->x, t5); fp_dbl(t6, t4); fp_sub(r->x, r->x, t6); /* y3 = R * (V - x3) - 2 * Y1 * J. */ fp_sub(t4, t4, r->x); fp_mul(t4, t4, t1); fp_mul(t1, p->y, t5); fp_dbl(t1, t1); fp_sub(r->y, t4, t1); if (!p->norm) { /* z3 = (z1 + H)^2 - z1^2 - HH. */ fp_add(r->z, p->z, t3); fp_sqr(r->z, r->z); fp_sub(r->z, r->z, t0); fp_sub(r->z, r->z, t2); } else { /* z3 = 2 * H. */ fp_dbl(r->z, t3); } } r->norm = 0; } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fp_free(t0); fp_free(t1); fp_free(t2); fp_free(t3); fp_free(t4); fp_free(t5); fp_free(t6); } }