void eb_sub_basic(eb_t r, const eb_t p, const eb_t q) { eb_t t; eb_null(t); if (p == q) { eb_set_infty(r); return; } TRY { eb_new(t); eb_neg_basic(t, q); eb_add_basic(r, p, t); r->norm = 1; } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { eb_free(t); } }
void eb_norm(eb_t r, const eb_t p) { if (eb_is_infty(p)) { eb_set_infty(r); return; } if (p->norm == 1) { /* If the point is represented in affine coordinates, we just copy it. */ eb_copy(r, p); return; } if (p->norm == 2) { eb_norm_halve(r, p); return; } #if EB_ADD == PROJC || !defined(STRIP) #if defined(EB_SUPER) if (eb_curve_is_super()) { eb_norm_super(r, p, 0); return; } #endif /* EB_SUPER */ #if defined(EB_ORDIN) || defined(EB_KBLTZ) eb_norm_ordin(r, p, 0); #endif /* EB_ORDIN || EB_KBLTZ */ #endif /* EB_ADD == PROJC */ }
void eb_mul_pre_combs(eb_t *t, eb_t p) { int i, j, l; bn_t ord; bn_null(ord); TRY { bn_new(ord); eb_curve_get_ord(ord); l = bn_bits(ord); l = ((l % EB_DEPTH) == 0 ? (l / EB_DEPTH) : (l / EB_DEPTH) + 1); eb_set_infty(t[0]); eb_copy(t[1], p); for (j = 1; j < EB_DEPTH; j++) { eb_dbl(t[1 << j], t[1 << (j - 1)]); for (i = 1; i < l; i++) { eb_dbl(t[1 << j], t[1 << j]); } for (i = 1; i < (1 << j); i++) { eb_add(t[(1 << j) + i], t[1 << j], t[i]); } } eb_norm_sim(t + 2, t + 2, EB_TABLE_COMBS - 2); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(ord); } }
void eb_dbl_basic(eb_t r, const eb_t p) { if (eb_is_infty(p)) { eb_set_infty(r); return; } eb_dbl_basic_imp(r, p); }
void eb_mul_pre_combd(eb_t *t, eb_t p) { bn_t n; bn_null(n); TRY { int i, j, d, e; bn_new(n); eb_curve_get_ord(n); d = bn_bits(n); d = ((d % EB_DEPTH) == 0 ? (d / EB_DEPTH) : (d / EB_DEPTH) + 1); e = (d % 2 == 0 ? (d / 2) : (d / 2) + 1); eb_set_infty(t[0]); eb_copy(t[1], p); for (j = 1; j < EB_DEPTH; j++) { eb_dbl(t[1 << j], t[1 << (j - 1)]); for (i = 1; i < d; i++) { eb_dbl(t[1 << j], t[1 << j]); } for (i = 1; i < (1 << j); i++) { eb_add(t[(1 << j) + i], t[1 << j], t[i]); } } eb_set_infty(t[1 << EB_DEPTH]); for (j = 1; j < (1 << EB_DEPTH); j++) { eb_dbl(t[(1 << EB_DEPTH) + j], t[j]); for (i = 1; i < e; i++) { eb_dbl(t[(1 << EB_DEPTH) + j], t[(1 << EB_DEPTH) + j]); } } eb_norm_sim(t + 2, t + 2, (1 << EB_DEPTH) - 2); eb_norm_sim(t + (1 << EB_DEPTH) + 1, t + (1 << EB_DEPTH) + 1, (1 << EB_DEPTH) - 1); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(n); } }
void eb_mul_fix_combd(eb_t r, eb_t *t, bn_t k) { int i, j, d, e, w0, w1, n0, p0, p1; bn_t n; bn_null(n); TRY { bn_new(n); eb_curve_get_ord(n); d = bn_bits(n); d = ((d % EB_DEPTH) == 0 ? (d / EB_DEPTH) : (d / EB_DEPTH) + 1); e = (d % 2 == 0 ? (d / 2) : (d / 2) + 1); eb_set_infty(r); n0 = bn_bits(k); p1 = (e - 1) + (EB_DEPTH - 1) * d; for (i = e - 1; i >= 0; i--) { eb_dbl(r, r); w0 = 0; p0 = p1; for (j = EB_DEPTH - 1; j >= 0; j--, p0 -= d) { w0 = w0 << 1; if (p0 < n0 && bn_test_bit(k, p0)) { w0 = w0 | 1; } } w1 = 0; p0 = p1-- + e; for (j = EB_DEPTH - 1; j >= 0; j--, p0 -= d) { w1 = w1 << 1; if (i + e < d && p0 < n0 && bn_test_bit(k, p0)) { w1 = w1 | 1; } } eb_add(r, r, t[w0]); eb_add(r, r, t[(1 << EB_DEPTH) + w1]); } eb_norm(r, r); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(n); } }
void eb_neg_basic(eb_t r, const eb_t p) { if (eb_is_infty(p)) { eb_set_infty(r); return; } if (r != p) { fb_copy(r->x, p->x); fb_copy(r->z, p->z); } fb_add(r->y, p->x, p->y); r->norm = 1; }
void eb_read_bin(eb_t a, const uint8_t *bin, int len) { if (len == 1) { if (bin[0] == 0) { eb_set_infty(a); return; } else { THROW(ERR_NO_BUFFER); return; } } if (len != (FB_BYTES + 1) && len != (2 * FB_BYTES + 1)) { THROW(ERR_NO_BUFFER); return; } a->norm = 1; fb_set_dig(a->z, 1); fb_read_bin(a->x, bin + 1, FB_BYTES); if (len == FB_BYTES + 1) { switch(bin[0]) { case 2: fb_zero(a->y); break; case 3: fb_zero(a->y); fb_set_bit(a->y, 0, 1); break; default: THROW(ERR_NO_VALID); break; } eb_upk(a, a); } if (len == 2 * FB_BYTES + 1) { if (bin[0] == 4) { fb_read_bin(a->y, bin + FB_BYTES + 1, FB_BYTES); } else { THROW(ERR_NO_VALID); } } }
void eb_neg_projc(eb_t r, const eb_t p) { fb_t t; fb_null(t); if (eb_is_infty(p)) { eb_set_infty(r); return; } if (p->norm) { if (r != p) { fb_copy(r->x, p->x); fb_copy(r->z, p->z); } fb_add(r->y, p->x, p->y); r->norm = 1; return; } TRY { fb_new(t); fb_mul(t, p->x, p->z); fb_add(r->y, p->y, t); if (r != p) { fb_copy(r->z, p->z); fb_copy(r->x, p->x); } r->norm = 0; } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fb_free(t); } }
void eb_neg_basic(eb_t r, const eb_t p) { if (eb_is_infty(p)) { eb_set_infty(r); return; } if (r != p) { fb_copy(r->x, p->x); fb_copy(r->z, p->z); } #if defined(EB_SUPER) if (eb_curve_is_super()) { switch (eb_curve_opt_c()) { case OPT_ZERO: fb_copy(r->y, p->y); break; case OPT_ONE: fb_add_dig(r->y, p->y, (dig_t)1); break; case OPT_DIGIT: fb_add_dig(r->y, p->y, eb_curve_get_c()[0]); break; default: fb_add(r->y, p->y, eb_curve_get_c()); break; } r->norm = 1; return; } #endif fb_add(r->y, p->x, p->y); r->norm = 1; }
void eb_mul_sim_trick(eb_t r, const eb_t p, const bn_t k, const eb_t q, const bn_t m) { eb_t t0[1 << (EB_WIDTH / 2)], t1[1 << (EB_WIDTH / 2)], t[1 << EB_WIDTH]; bn_t n; int l0, l1, w = EB_WIDTH / 2; uint8_t w0[CEIL(FB_BITS, 2)], w1[CEIL(FB_BITS, w)]; bn_null(n); for (int i = 0; i < 1 << EB_WIDTH; i++) { eb_null(t[i]); } for (int i = 0; i < 1 << (EB_WIDTH / 2); i++) { eb_null(t0[i]); eb_null(t1[i]); } TRY { bn_new(n); eb_curve_get_ord(n); for (int i = 0; i < (1 << w); i++) { eb_new(t0[i]); eb_new(t1[i]); } for (int i = 0; i < (1 << EB_WIDTH); i++) { eb_new(t[i]); } eb_set_infty(t0[0]); for (int i = 1; i < (1 << w); i++) { eb_add(t0[i], t0[i - 1], p); } eb_set_infty(t1[0]); for (int i = 1; i < (1 << w); i++) { eb_add(t1[i], t1[i - 1], q); } for (int i = 0; i < (1 << w); i++) { for (int j = 0; j < (1 << w); j++) { eb_add(t[(i << w) + j], t0[i], t1[j]); } } #if EB_WIDTH > 2 && defined(EB_MIXED) eb_norm_sim(t + 1, (const eb_t *)(t + 1), (1 << EB_WIDTH) - 1); #endif l0 = l1 = CEIL(FB_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; } eb_set_infty(r); for (int i = MAX(l0, l1) - 1; i >= 0; i--) { for (int j = 0; j < w; j++) { eb_dbl(r, r); } eb_add(r, r, t[(w0[i] << w) + w1[i]]); } eb_norm(r, r); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(n); for (int i = 0; i < (1 << w); i++) { eb_free(t0[i]); eb_free(t1[i]); } for (int i = 0; i < (1 << EB_WIDTH); i++) { eb_free(t[i]); } } }
/** * Multiplies and adds two binary 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 a precomputed table. */ static void eb_mul_sim_plain(eb_t r, const eb_t p, const bn_t k, const eb_t q, const bn_t m, const eb_t *t) { int l, l0, l1, i, n0, n1, w, g; int8_t naf0[FB_BITS + 1], naf1[FB_BITS + 1], *_k, *_m; eb_t t0[1 << (EB_WIDTH - 2)]; eb_t t1[1 << (EB_WIDTH - 2)]; for (i = 0; i < (1 << (EB_WIDTH - 2)); i++) { eb_null(t0[i]); eb_null(t1[i]); } TRY { g = (t == NULL ? 0 : 1); if (!g) { for (i = 0; i < (1 << (EB_WIDTH - 2)); i++) { eb_new(t0[i]); } eb_tab(t0, p, EB_WIDTH); t = (const eb_t *)t0; } /* Prepare the precomputation table. */ for (i = 0; i < (1 << (EB_WIDTH - 2)); i++) { eb_new(t1[i]); } /* Compute the precomputation table. */ eb_tab(t1, q, EB_WIDTH); /* Compute the w-NAF representation of k. */ if (g) { w = EB_DEPTH; } else { w = EB_WIDTH; } l0 = l1 = FB_BITS + 1; bn_rec_naf(naf0, &l0, k, w); bn_rec_naf(naf1, &l1, m, EB_WIDTH); l = MAX(l0, l1); _k = naf0 + l - 1; _m = naf1 + l - 1; for (i = l0; i < l; i++) { naf0[i] = 0; } for (i = l1; i < l; i++) { naf1[i] = 0; } eb_set_infty(r); for (i = l - 1; i >= 0; i--, _k--, _m--) { eb_dbl(r, r); n0 = *_k; n1 = *_m; if (n0 > 0) { eb_add(r, r, t[n0 / 2]); } if (n0 < 0) { eb_sub(r, r, t[-n0 / 2]); } if (n1 > 0) { eb_add(r, r, t1[n1 / 2]); } if (n1 < 0) { eb_sub(r, r, t1[-n1 / 2]); } } /* Convert r to affine coordinates. */ eb_norm(r, r); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { /* Free the precomputation tables. */ if (!g) { for (i = 0; i < 1 << (EB_WIDTH - 2); i++) { eb_free(t0[i]); } } for (i = 0; i < 1 << (EB_WIDTH - 2); i++) { eb_free(t1[i]); } } }
void eb_mul_sim_trick(eb_t r, const eb_t p, const bn_t k, const eb_t q, const bn_t m) { eb_t t0[1 << (EB_WIDTH / 2)], t1[1 << (EB_WIDTH / 2)], t[1 << EB_WIDTH]; int l0, l1, w = EB_WIDTH / 2; uint8_t *w0 = RLC_ALLOCA(uint8_t, RLC_CEIL(RLC_FB_BITS, w)); uint8_t *w1 = RLC_ALLOCA(uint8_t, RLC_CEIL(RLC_FB_BITS, w)); bn_t n; bn_null(n); if (bn_is_zero(k) || eb_is_infty(p)) { eb_mul(r, q, m); return; } if (bn_is_zero(m) || eb_is_infty(q)) { eb_mul(r, p, k); return; } TRY { bn_new(n); eb_curve_get_ord(n); for (int i = 0; i < (1 << w); i++) { eb_null(t0[i]); eb_null(t1[i]); eb_new(t0[i]); eb_new(t1[i]); } for (int i = 0; i < (1 << EB_WIDTH); i++) { eb_null(t[i]); eb_new(t[i]); } eb_set_infty(t0[0]); eb_copy(t0[1], p); if (bn_sign(k) == RLC_NEG) { eb_neg(t0[1], t0[1]); } for (int i = 2; i < (1 << w); i++) { eb_add(t0[i], t0[i - 1], t0[1]); } eb_set_infty(t1[0]); eb_copy(t1[1], q); if (bn_sign(m) == RLC_NEG) { eb_neg(t1[1], t1[1]); } for (int i = 2; i < (1 << w); i++) { eb_add(t1[i], t1[i - 1], t1[1]); } for (int i = 0; i < (1 << w); i++) { for (int j = 0; j < (1 << w); j++) { eb_add(t[(i << w) + j], t0[i], t1[j]); } } #if EB_WIDTH > 2 && defined(EB_MIXED) eb_norm_sim(t + 1, (const eb_t *)(t + 1), (1 << EB_WIDTH) - 1); #endif l0 = l1 = RLC_CEIL(RLC_FB_BITS + 1, 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; } eb_set_infty(r); for (int i = RLC_MAX(l0, l1) - 1; i >= 0; i--) { for (int j = 0; j < w; j++) { eb_dbl(r, r); } eb_add(r, r, t[(w0[i] << w) + w1[i]]); } eb_norm(r, r); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(n); for (int i = 0; i < (1 << w); i++) { eb_free(t0[i]); eb_free(t1[i]); } for (int i = 0; i < (1 << EB_WIDTH); i++) { eb_free(t[i]); } } }
void eb_tab(eb_t *t, const eb_t p, int w) { int u; #if defined(EB_PLAIN) if (!eb_curve_is_kbltz()) { if (w > 2) { eb_dbl(t[0], p); #if defined(EB_MIXED) eb_norm(t[0], t[0]); #endif eb_add(t[1], t[0], p); for (int i = 2; i < (1 << (w - 2)); i++) { eb_add(t[i], t[i - 1], t[0]); } #if defined(EB_MIXED) eb_norm_sim(t + 1, (const eb_t *)t + 1, (1 << (w - 2)) - 1); #endif } eb_copy(t[0], p); } #endif /* EB_PLAIN */ #if defined(EB_KBLTZ) if (eb_curve_is_kbltz()) { u = (eb_curve_opt_a() == OPT_ZERO ? -1 : 1); /* Prepare the precomputation table. */ for (int i = 0; i < 1 << (w - 2); i++) { eb_set_infty(t[i]); fb_set_dig(t[i]->z, 1); t[i]->norm = 1; } #if defined(EB_MIXED) eb_norm(t[0], p); #else eb_copy(t[0], p); #endif switch (w) { #if EB_DEPTH == 3 || EB_WIDTH == 3 case 3: eb_frb(t[1], t[0]); if (u == 1) { eb_sub(t[1], t[0], t[1]); } else { eb_add(t[1], t[0], t[1]); } break; #endif #if EB_DEPTH == 4 || EB_WIDTH == 4 case 4: eb_frb(t[3], t[0]); eb_frb(t[3], t[3]); eb_sub(t[1], t[3], p); eb_add(t[2], t[3], p); eb_frb(t[3], t[3]); if (u == 1) { eb_neg(t[3], t[3]); } eb_sub(t[3], t[3], p); break; #endif #if EB_DEPTH == 5 || EB_WIDTH == 5 case 5: eb_frb(t[3], t[0]); eb_frb(t[3], t[3]); eb_sub(t[1], t[3], p); eb_add(t[2], t[3], p); eb_frb(t[3], t[3]); eb_frb(t[7], t[3]); eb_sub(t[7], t[7], p); if (u == 1) { eb_neg(t[3], t[3]); } eb_sub(t[3], t[3], p); eb_frb(t[4], t[2]); eb_frb(t[4], t[4]); eb_neg(t[4], t[4]); eb_sub(t[5], t[4], p); eb_add(t[6], t[4], p); eb_frb(t[4], t[4]); if (u == -1) { eb_neg(t[4], t[4]); } eb_add(t[4], t[4], p); break; #endif #if EB_DEPTH == 6 || EB_WIDTH == 6 case 6: eb_frb(t[0], t[0]); eb_frb(t[0], t[0]); eb_neg(t[14], t[0]); eb_sub(t[13], t[14], p); eb_add(t[14], t[14], p); eb_frb(t[0], t[0]); eb_frb(t[8], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_sub(t[11], t[0], p); eb_add(t[12], t[0], p); eb_frb(t[0], t[12]); eb_frb(t[0], t[0]); eb_sub(t[1], t[0], p); eb_add(t[2], t[0], p); eb_frb(t[15], t[8]); if (u == -1) { eb_neg(t[15], t[15]); } eb_sub(t[15], t[15], p); eb_frb(t[0], t[13]); eb_frb(t[0], t[0]); eb_sub(t[5], t[0], p); eb_add(t[6], t[0], p); eb_sub(t[7], t[8], p); eb_add(t[8], t[8], p); eb_frb(t[0], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_sub(t[3], t[0], p); eb_add(t[4], t[0], p); eb_frb(t[0], t[1]); eb_frb(t[0], t[0]); eb_neg(t[9], t[0]); eb_sub(t[9], t[9], p); eb_frb(t[0], t[14]); eb_frb(t[0], t[0]); eb_add(t[10], t[0], p); eb_copy(t[0], p); break; #endif #if EB_DEPTH == 7 || EB_WIDTH == 7 /** * Formulas from http://eprint.iacr.org/2012/519 */ case 7: eb_frb(t[0], t[0]); eb_frb(t[0], t[0]); eb_sub(t[17], t[0], p); eb_add(t[18], t[0], p); eb_frb(t[0], t[0]); if (u == 1) { eb_neg(t[0], t[0]); } eb_sub(t[19], t[0], p); eb_add(t[20], t[0], p); eb_frb(t[0], t[19]); eb_frb(t[0], t[0]); eb_frb(t[11], t[0]); if (u == 1) { eb_neg(t[11], t[11]); } eb_add(t[12], t[11], p); eb_sub(t[11], t[11], p); eb_neg(t[0], t[0]); eb_sub(t[1], t[0], p); eb_add(t[2], t[0], p); eb_frb(t[0], t[17]); eb_frb(t[0], t[0]); eb_frb(t[0], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_sub(t[3], t[0], p); eb_frb(t[0], t[1]); eb_frb(t[0], t[0]); eb_add(t[9], t[0], p); eb_neg(t[9], t[9]); eb_frb(t[0], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_add(t[4], t[0], p); eb_frb(t[0], t[18]); eb_frb(t[0], t[0]); eb_sub(t[7], t[0], t[18]); eb_sub(t[25], t[0], p); eb_add(t[26], t[0], p); eb_frb(t[0], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_sub(t[27], t[0], p); eb_add(t[28], t[0], p); eb_frb(t[0], t[17]); eb_frb(t[0], t[0]); eb_add(t[8], t[0], t[18]); eb_neg(t[0], t[0]); eb_add(t[10], t[0], p); eb_frb(t[0], t[7]); eb_frb(t[0], t[0]); eb_sub(t[13], t[0], p); eb_frb(t[0], t[8]); eb_frb(t[0], t[0]); eb_neg(t[0], t[0]); eb_add(t[14], t[0], p); eb_frb(t[0], t[19]); eb_frb(t[0], t[0]); eb_add(t[15], t[0], t[17]); eb_add(t[16], t[0], t[18]); eb_frb(t[0], t[26]); eb_frb(t[0], t[0]); eb_neg(t[0], t[0]); eb_sub(t[5], t[0], p); eb_add(t[6], t[0], p); eb_add(t[23], t[0], t[17]); eb_add(t[24], t[0], t[18]); eb_frb(t[0], t[25]); eb_frb(t[0], t[0]); eb_sub(t[21], t[0], p); eb_add(t[22], t[0], p); eb_frb(t[0], t[20]); eb_frb(t[0], t[0]); eb_add(t[29], t[0], p); eb_neg(t[29], t[29]); eb_frb(t[0], t[27]); eb_frb(t[0], t[0]); eb_add(t[30], t[0], p); eb_frb(t[0], t[7]); eb_frb(t[0], t[0]); eb_add(t[31], t[0], t[17]) eb_copy(t[0], p); break; #endif #if EB_DEPTH == 8 || EB_WIDTH == 8 /** * Formulas from http://eprint.iacr.org/2012/519 */ case 8: eb_frb(t[0], t[0]); eb_frb(t[0], t[0]); eb_neg(t[0], t[0]); eb_sub(t[45], t[0], p); eb_add(t[46], t[0], p); eb_frb(t[0], t[0]); if (u == 1) { eb_neg(t[0], t[0]); } eb_sub(t[43], t[0], p); eb_add(t[44], t[0], p); eb_frb(t[0], t[44]); eb_frb(t[0], t[0]); eb_sub(t[1], t[0], p); eb_add(t[2], t[0], p); eb_add(t[47], t[0], t[45]); eb_add(t[48], t[0], t[46]); eb_frb(t[0], t[46]); eb_frb(t[0], t[0]); eb_neg(t[0], t[0]); eb_sub(t[7], t[0], t[46]); eb_sub(t[8], t[0], t[45]); eb_frb(t[0], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_sub(t[3], t[0], p); eb_frb(t[0], t[1]); eb_frb(t[0], t[0]); eb_neg(t[0], t[0]); eb_add(t[55], t[0], t[45]); eb_add(t[56], t[0], t[46]); eb_sub(t[9], t[0], p); eb_add(t[10], t[0], p); eb_frb(t[0], t[0]); if (u == 1) { eb_neg(t[0], t[0]); } eb_add(t[4], t[0], p); eb_frb(t[0], t[47]); eb_frb(t[0], t[0]); eb_neg(t[0], t[0]); eb_sub(t[17], t[0], p); eb_add(t[18], t[0], p); eb_frb(t[0], t[8]); eb_frb(t[0], t[0]); eb_add(t[31], t[0], t[45]); eb_add(t[32], t[0], t[46]); eb_neg(t[0], t[0]); eb_sub(t[13], t[0], p); eb_add(t[14], t[0], p); eb_frb(t[0], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_sub(t[19], t[0], p); eb_frb(t[0], t[7]); eb_frb(t[0], t[0]); eb_frb(t[0], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_add(t[20], t[0], p); eb_frb(t[0], t[9]); eb_frb(t[0], t[0]); eb_sub(t[21], t[0], p); eb_add(t[22], t[0], p); eb_frb(t[0], t[2]); eb_frb(t[0], t[0]); eb_sub(t[25], t[0], p); eb_add(t[26], t[0], p); eb_frb(t[0], t[43]); eb_frb(t[0], t[0]); eb_neg(t[0], t[0]); eb_sub(t[33], t[0], p); eb_add(t[34], t[0], p); eb_frb(t[0], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_add(t[12], t[0], p); eb_frb(t[0], t[45]); eb_frb(t[0], t[0]); eb_sub(t[37], t[0], p); eb_add(t[38], t[0], p); eb_frb(t[0], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_sub(t[35], t[0], p); eb_add(t[36], t[0], p); eb_frb(t[0], t[38]); eb_frb(t[0], t[0]); eb_sub(t[41], t[0], p); eb_add(t[42], t[0], p); eb_neg(t[0], t[0]); eb_sub(t[39], t[0], t[46]); eb_sub(t[40], t[0], t[45]); eb_frb(t[0], t[37]); eb_frb(t[0], t[0]); eb_sub(t[5], t[0], p); eb_add(t[6], t[0], p); eb_frb(t[0], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_add(t[15], t[0], t[43]); eb_add(t[16], t[0], t[44]); eb_neg(t[0], t[0]); eb_sub(t[27], t[0], p); eb_add(t[28], t[0], p); eb_frb(t[0], t[36]); eb_frb(t[0], t[0]); eb_frb(t[0], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_sub(t[11], t[0], p); eb_frb(t[0], t[39]); eb_frb(t[0], t[0]); eb_add(t[0], t[0], p); eb_neg(t[49], t[0]); eb_frb(t[0], t[7]); eb_frb(t[0], t[0]); eb_neg(t[0], t[0]); eb_add(t[50], t[0], p); eb_frb(t[0], t[44]); eb_frb(t[0], t[0]); eb_frb(t[0], t[0]); if (u == 1) { eb_neg(t[0], t[0]); } eb_sub(t[51], t[0], p); eb_add(t[52], t[0], p); eb_frb(t[0], t[46]); eb_frb(t[0], t[0]); eb_neg(t[0], t[0]); eb_sub(t[53], t[0], p); eb_add(t[54], t[0], p); eb_frb(t[0], t[54]); eb_frb(t[0], t[0]); eb_add(t[23], t[0], t[45]); eb_add(t[24], t[0], t[46]); eb_frb(t[0], t[42]); eb_frb(t[0], t[0]); eb_sub(t[57], t[0], p); eb_frb(t[0], t[53]); eb_frb(t[0], t[0]); eb_neg(t[0], t[0]); eb_add(t[58], t[0], p); eb_frb(t[0], t[38]); eb_frb(t[0], t[0]); eb_frb(t[0], t[0]); if (u == -1) { eb_neg(t[0], t[0]); } eb_sub(t[59], t[0], p); eb_add(t[60], t[0], p); eb_frb(t[0], t[35]); eb_frb(t[0], t[0]); eb_sub(t[61], t[0], p); eb_add(t[62], t[0], p); eb_frb(t[0], t[47]); eb_frb(t[0], t[0]); eb_neg(t[0], t[0]); eb_add(t[63], t[0], t[45]); eb_frb(t[0], t[36]); eb_frb(t[0], t[0]); eb_neg(t[0], t[0]); eb_sub(t[29], t[0], p); eb_add(t[30], t[0], p); eb_copy(t[0], p); break; #endif } #if defined(EB_MIXED) if (w > 2) { eb_norm_sim(t + 1, (const eb_t *)t + 1, (1 << (w - 2)) - 1); } #endif } #endif /* EB_KBLTZ */ }
/** * Adds a point represented in affine coordinates to a point represented in * projective coordinates. * * @param r - the result. * @param p - the affine point. * @param q - the projective point. */ static void eb_add_projc_ordin_mix(eb_t r, eb_t p, eb_t q) { fb_t t0, t1, t2, t3, t4, t5; fb_null(t0); fb_null(t1); fb_null(t2); fb_null(t3); fb_null(t4); fb_null(t5); TRY { fb_new(t0); fb_new(t1); fb_new(t2); fb_new(t3); fb_new(t4); fb_new(t5); if (!p->norm) { /* A = y1 + y2 * z1^2. */ fb_sqr(t0, p->z); fb_mul(t0, t0, q->y); fb_add(t0, t0, p->y); /* B = x1 + x2 * z1. */ fb_mul(t1, p->z, q->x); fb_add(t1, t1, p->x); } else { /* t0 = A = y1 + y2. */ fb_add(t0, p->y, q->y); /* t1 = B = x1 + x2. */ fb_add(t1, p->x, q->x); } if (fb_is_zero(t1)) { if (fb_is_zero(t0)) { /* If t0 = 0 and t1 = 0, p = q, should have doubled! */ eb_dbl_projc(r, p); } else { /* If t0 = 0, r is infinity. */ eb_set_infty(r); } } else { if (!p->norm) { /* t2 = C = B * z1. */ fb_mul(t2, p->z, t1); /* z3 = C^2. */ fb_sqr(r->z, t2); /* t1 = B^2. */ fb_sqr(t1, t1); /* t1 = A + B^2. */ fb_add(t1, t0, t1); } else { /* If z1 = 0, t2 = C = B. */ fb_copy(t2, t1); /* z3 = B^2. */ fb_sqr(r->z, t1); /* t1 = A + z3. */ fb_add(t1, t0, r->z); } /* t3 = D = x2 * z3. */ fb_mul(t3, r->z, q->x); /* t4 = (y2 + x2). */ fb_add(t4, q->x, q->y); /* z3 = A^2. */ fb_sqr(r->x, t0); /* t1 = A + B^2 + a2 * C. */ switch (eb_curve_opt_a()) { case OPT_ZERO: break; case OPT_ONE: fb_add(t1, t1, t2); break; case OPT_DIGIT: /* t5 = a2 * C. */ fb_mul_dig(t5, t2, eb_curve_get_a()[0]); fb_add(t1, t1, t5); break; default: /* t5 = a2 * C. */ fb_mul(t5, eb_curve_get_a(), t2); fb_add(t1, t1, t5); break; } /* t1 = C * (A + B^2 + a2 * C). */ fb_mul(t1, t1, t2); /* x3 = A^2 + C * (A + B^2 + a2 * C). */ fb_add(r->x, r->x, t1); /* t3 = D + x3. */ fb_add(t3, t3, r->x); /* t2 = A * B. */ fb_mul(t2, t0, t2); /* y3 = (D + x3) * (A * B + z3). */ fb_add(r->y, t2, r->z); fb_mul(r->y, r->y, t3); /* t0 = z3^2. */ fb_sqr(t0, r->z); /* t0 = (y2 + x2) * z3^2. */ fb_mul(t0, t0, t4); /* y3 = (D + x3) * (A * B + z3) + (y2 + x2) * z3^2. */ fb_add(r->y, r->y, t0); } r->norm = 0; } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fb_free(t0); fb_free(t1); fb_free(t2); fb_free(t3); fb_free(t4); fb_free(t5); } }
/** * Adds two points represented in projective coordinates on an ordinary binary * elliptic curve. * * @param r - the result. * @param p - the first point to add. * @param q - the second point to add. */ static void eb_add_projc_ordin(eb_t r, eb_t p, eb_t q) { #if defined(EB_MIXED) && defined(STRIP) eb_add_projc_ordin_mix(r, p, q); #else /* General addition. */ fb_t t0, t1, t2, t3, t4, t5, t6, t7; fb_null(t0); fb_null(t1); fb_null(t2); fb_null(t3); fb_null(t4); fb_null(t5); fb_null(t6); fb_null(t7); TRY { fb_new(t0); fb_new(t1); fb_new(t2); fb_new(t3); fb_new(t4); fb_new(t5); fb_new(t6); fb_new(t7); if (q->norm) { eb_add_projc_ordin_mix(r, p, q); } else { /* t0 = B = x2 * z1. */ fb_mul(t0, q->x, p->z); /* A = x1 * z2 */ fb_mul(t1, p->x, q->z); /* t2 = E = A + B. */ fb_add(t2, t1, t0); /* t3 = D = B^2. */ fb_sqr(t3, t0); /* t4 = C = A^2. */ fb_sqr(t4, t1); /* t5 = F = C + D. */ fb_add(t5, t3, t4); /* t6 = H = y2 * z1^2. */ fb_sqr(t6, p->z); fb_mul(t6, t6, q->y); /* t7 = G = y1 * z2^2. */ fb_sqr(t7, q->z); fb_mul(t7, t7, p->y); /* t3 = D + H. */ fb_add(t3, t3, t6); /* t4 = C + G. */ fb_add(t4, t4, t7); /* t6 = I = G + H. */ fb_add(t6, t7, t6); /* If E is zero. */ if (fb_is_zero(t2)) { if (fb_is_zero(t6)) { /* If I is zero, p = q, should have doubled. */ eb_dbl_projc(r, p); } else { /* If I is not zero, q = -p, r = infinity. */ eb_set_infty(r); } } else { /* t6 = J = I * E. */ fb_mul(t6, t6, t2); /* z3 = F * z1 * z2. */ fb_mul(r->z, p->z, q->z); fb_mul(r->z, t5, r->z); /* t4 = B * (C + G). */ fb_mul(t4, t0, t4); /* t2 = A * J. */ fb_mul(t2, t1, t6); /* x3 = A * (D + H) + B * (C + G). */ fb_mul(r->x, t1, t3); fb_add(r->x, r->x, t4); /* t7 = F * G. */ fb_mul(t7, t7, t5); /* Y3 = (A * J + F * G) * F + (J + z3) * x3. */ fb_add(r->y, t2, t7); fb_mul(r->y, r->y, t5); /* t7 = (J + z3) * x3. */ fb_add(t7, t6, r->z); fb_mul(t7, t7, r->x); fb_add(r->y, r->y, t7); } } r->norm = 0; } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fb_free(t0); fb_free(t1); fb_free(t2); fb_free(t3); fb_free(t4); fb_free(t5); fb_free(t6); fb_free(t7); } #endif }
/** * Adds two points represented in affine coordinates on an ordinary binary * 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 eb_add_basic_imp(eb_t r, const eb_t p, const eb_t q) { fb_t t0, t1, t2; fb_null(t0); fb_null(t1); fb_null(t2); TRY { fb_new(t0); fb_new(t1); fb_new(t2); /* t0 = (y1 + y2). */ fb_add(t0, p->y, q->y); /* t1 = (x1 + x2). */ fb_add(t1, p->x, q->x); if (fb_is_zero(t1)) { if (fb_is_zero(t0)) { /* If t1 is zero and t0 is zero, p = q, should have doubled. */ eb_dbl_basic(r, p); } else { /* If t0 is not zero and t1 is zero, q = -p and r = infinity. */ eb_set_infty(r); } } else { /* t2 = 1/(x1 + x2). */ fb_inv(t2, t1); /* t0 = lambda = (y1 + y2)/(x1 + x2). */ fb_mul(t0, t0, t2); /* t2 = lambda^2. */ fb_sqr(t2, t0); /* t2 = lambda^2 + lambda + x1 + x2 + a. */ fb_add(t2, t2, t0); fb_add(t2, t2, t1); switch (eb_curve_opt_a()) { case OPT_ZERO: break; case OPT_ONE: fb_add_dig(t2, t2, (dig_t)1); break; case OPT_DIGIT: fb_add_dig(t2, t2, eb_curve_get_a()[0]); break; default: fb_add(t2, t2, eb_curve_get_a()); break; } /* y3 = lambda*(x3 + x1) + x3 + y1. */ fb_add(t1, t2, p->x); fb_mul(t1, t1, t0); fb_add(t1, t1, t2); fb_add(r->y, p->y, t1); /* x3 = lambda^2 + lambda + x1 + x2 + a. */ fb_copy(r->x, t2); fb_copy(r->z, p->z); r->norm = 1; } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fb_free(t0); fb_free(t1); fb_free(t2); } }
void eb_mul_sim_joint(eb_t r, const eb_t p, const bn_t k, const eb_t q, const bn_t m) { eb_t t[5]; int u_i, len, offset; int8_t jsf[2 * (FB_BITS + 1)]; int i; eb_null(t[0]); eb_null(t[1]); eb_null(t[2]); eb_null(t[3]); eb_null(t[4]); TRY { for (i = 0; i < 5; i++) { eb_new(t[i]); } eb_set_infty(t[0]); eb_copy(t[1], q); eb_copy(t[2], p); eb_add(t[3], p, q); eb_sub(t[4], p, q); #if defined(EB_MIXED) eb_norm_sim(t + 3, (const eb_t*)(t + 3), 2); #endif len = 2 * (FB_BITS + 1); bn_rec_jsf(jsf, &len, k, m); eb_set_infty(r); offset = MAX(bn_bits(k), bn_bits(m)) + 1; for (i = len - 1; i >= 0; i--) { eb_dbl(r, r); if (jsf[i] != 0 && jsf[i] == -jsf[i + offset]) { u_i = jsf[i] * 2 + jsf[i + offset]; if (u_i < 0) { eb_sub(r, r, t[4]); } else { eb_add(r, r, t[4]); } } else { u_i = jsf[i] * 2 + jsf[i + offset]; if (u_i < 0) { eb_sub(r, r, t[-u_i]); } else { eb_add(r, r, t[u_i]); } } } eb_norm(r, r); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { for (i = 0; i < 5; i++) { eb_free(t[i]); } } }
void eb_neg_projc(eb_t r, const eb_t p) { fb_t t; fb_null(t); if (eb_is_infty(p)) { eb_set_infty(r); return; } if (p->norm) { if (r != p) { fb_copy(r->x, p->x); fb_copy(r->z, p->z); } #if defined(EB_SUPER) if (eb_curve_is_super()) { switch (eb_curve_opt_c()) { case OPT_ZERO: fb_copy(r->y, p->y); break; case OPT_ONE: fb_add_dig(r->y, p->y, (dig_t)1); break; case OPT_DIGIT: fb_add_dig(r->y, p->y, eb_curve_get_c()[0]); break; default: fb_add(r->y, p->y, eb_curve_get_c()); break; } r->norm = 1; return; } #endif fb_add(r->y, p->x, p->y); r->norm = 1; return; } #if defined(EB_SUPER) if (eb_curve_is_super()) { fb_add(r->y, p->y, p->z); fb_copy(r->z, p->z); fb_copy(r->x, p->x); r->norm = 0; return; } #endif TRY { fb_new(t); fb_mul(t, p->x, p->z); fb_add(r->y, p->y, t); if (r != p) { fb_copy(r->z, p->z); fb_copy(r->x, p->x); } r->norm = 0; } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fb_free(t); } }
/** * Multiplies and adds two binary 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 a precomputed table. */ static void eb_mul_sim_kbltz(eb_t r, const eb_t p, const bn_t k, const eb_t q, const bn_t m, const eb_t *t) { int l0, l1, l, i, n0, n1, w, g; int8_t u, tnaf0[FB_BITS + 8], tnaf1[FB_BITS + 8], *_k, *_m; eb_t t0[1 << (EB_WIDTH - 2)]; eb_t t1[1 << (EB_WIDTH - 2)]; bn_t vm, s0, s1; bn_null(vm); bn_null(s0); bn_null(s1); for (i = 0; i < (1 << (EB_WIDTH - 2)); i++) { eb_null(t0[i]); eb_null(t1[i]); } TRY { bn_new(vm); bn_new(s0); bn_new(s1); /* Compute the w-TNAF representation of k. */ if (eb_curve_opt_a() == OPT_ZERO) { u = -1; } else { u = 1; } g = (t == NULL ? 0 : 1); if (!g) { for (i = 0; i < (1 << (EB_WIDTH - 2)); i++) { eb_new(t0[i]); eb_set_infty(t0[i]); fb_set_bit(t0[i]->z, 0, 1); t0[i]->norm = 1; } eb_tab(t0, p, EB_WIDTH); t = (const eb_t *)t0; } /* Prepare the precomputation table. */ for (i = 0; i < (1 << (EB_WIDTH - 2)); i++) { eb_new(t1[i]); eb_set_infty(t1[i]); fb_set_bit(t1[i]->z, 0, 1); t1[i]->norm = 1; } /* Compute the precomputation table. */ eb_tab(t1, q, EB_WIDTH); /* Compute the w-TNAF representation of k. */ if (g) { w = EB_DEPTH; } else { w = EB_WIDTH; } eb_curve_get_vm(vm); eb_curve_get_s0(s0); eb_curve_get_s1(s1); l0 = l1 = FB_BITS + 8; bn_rec_tnaf(tnaf0, &l0, k, vm, s0, s1, u, FB_BITS, w); bn_rec_tnaf(tnaf1, &l1, m, vm, s0, s1, u, FB_BITS, EB_WIDTH); l = MAX(l0, l1); _k = tnaf0 + l - 1; _m = tnaf1 + l - 1; for (i = l0; i < l; i++) tnaf0[i] = 0; for (i = l1; i < l; i++) tnaf1[i] = 0; _k = tnaf0 + l - 1; _m = tnaf1 + l - 1; eb_set_infty(r); for (i = l - 1; i >= 0; i--, _k--, _m--) { eb_frb(r, r); n0 = *_k; n1 = *_m; if (n0 > 0) { eb_add(r, r, t[n0 / 2]); } if (n0 < 0) { eb_sub(r, r, t[-n0 / 2]); } if (n1 > 0) { eb_add(r, r, t1[n1 / 2]); } if (n1 < 0) { eb_sub(r, r, t1[-n1 / 2]); } } /* Convert r to affine coordinates. */ eb_norm(r, r); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { if (!g) { for (i = 0; i < (1 << (EB_WIDTH - 2)); i++) { eb_free(t0[i]); } } for (i = 0; i < (1 << (EB_WIDTH - 2)); i++) { eb_free(t1[i]); } bn_free(vm); bn_free(s0); bn_free(s1); } }
/** * Adds a point represented in affine coordinates to a point represented in * projective coordinates. * * @param[out] r - the result. * @param[in] p - the affine point. * @param[in] q - the projective point. */ static void eb_add_projc_mix(eb_t r, const eb_t p, const eb_t q) { fb_t t0, t1, t2, t3, t4, t5; fb_null(t0); fb_null(t1); fb_null(t2); fb_null(t3); fb_null(t4); fb_null(t5); TRY { fb_new(t0); fb_new(t1); fb_new(t2); fb_new(t3); fb_new(t4); fb_new(t5); /* madd-2005-dl formulas: 7M + 4S + 9add + 1*4 + 3*2. */ /* http://www.hyperelliptic.org/EFD/g12o/auto-shortw-lopezdahab-1.html#addition-madd-2005-dl */ if (!p->norm) { /* A = y1 + y2 * z1^2. */ fb_sqr(t0, p->z); fb_mul(t0, t0, q->y); fb_add(t0, t0, p->y); /* B = x1 + x2 * z1. */ fb_mul(t1, p->z, q->x); fb_add(t1, t1, p->x); } else { /* t0 = A = y1 + y2. */ fb_add(t0, p->y, q->y); /* t1 = B = x1 + x2. */ fb_add(t1, p->x, q->x); } if (fb_is_zero(t1)) { if (fb_is_zero(t0)) { /* If t0 = 0 and t1 = 0, p = q, should have doubled! */ eb_dbl_projc(r, p); } else { /* If t0 = 0, r is infinity. */ eb_set_infty(r); } } else { if (!p->norm) { /* t2 = C = B * z1. */ fb_mul(t2, p->z, t1); /* z3 = C^2. */ fb_sqr(r->z, t2); /* t1 = B^2. */ fb_sqr(t1, t1); /* t1 = A + B^2. */ fb_add(t1, t0, t1); } else { /* If z1 = 0, t2 = C = B. */ fb_copy(t2, t1); /* z3 = B^2. */ fb_sqr(r->z, t1); /* t1 = A + z3. */ fb_add(t1, t0, r->z); } /* t3 = D = x2 * z3. */ fb_mul(t3, r->z, q->x); /* t4 = (y2 + x2). */ fb_add(t4, q->x, q->y); /* z3 = A^2. */ fb_sqr(r->x, t0); /* t1 = A + B^2 + a2 * C. */ switch (eb_curve_opt_a()) { case OPT_ZERO: break; case OPT_ONE: fb_add(t1, t1, t2); break; case OPT_DIGIT: /* t5 = a2 * C. */ fb_mul_dig(t5, t2, eb_curve_get_a()[0]); fb_add(t1, t1, t5); break; default: /* t5 = a2 * C. */ fb_mul(t5, eb_curve_get_a(), t2); fb_add(t1, t1, t5); break; } /* t1 = C * (A + B^2 + a2 * C). */ fb_mul(t1, t1, t2); /* x3 = A^2 + C * (A + B^2 + a2 * C). */ fb_add(r->x, r->x, t1); /* t3 = D + x3. */ fb_add(t3, t3, r->x); /* t2 = A * B. */ fb_mul(t2, t0, t2); /* y3 = (D + x3) * (A * B + z3). */ fb_add(r->y, t2, r->z); fb_mul(r->y, r->y, t3); /* t0 = z3^2. */ fb_sqr(t0, r->z); /* t0 = (y2 + x2) * z3^2. */ fb_mul(t0, t0, t4); /* y3 = (D + x3) * (A * B + z3) + (y2 + x2) * z3^2. */ fb_add(r->y, r->y, t0); } r->norm = 0; } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fb_free(t0); fb_free(t1); fb_free(t2); fb_free(t3); fb_free(t4); fb_free(t5); } }