void field_isr ( field_a_t a, const field_a_t x ) { field_a_t L0, L1, L2, L3; field_sqr ( L2, x ); field_mul ( L1, x, L2 ); field_sqrn ( L0, L1, 2 ); field_mul ( L2, L1, L0 ); field_sqrn ( L0, L2, 4 ); field_mul ( L1, L2, L0 ); field_sqr ( L0, L1 ); field_mul ( L2, x, L0 ); field_sqrn ( L0, L2, 8 ); field_mul ( L2, L1, L0 ); field_sqrn ( L0, L2, 17 ); field_mul ( L1, L2, L0 ); field_sqrn ( L0, L1, 17 ); field_mul ( L1, L2, L0 ); field_sqrn ( L3, L1, 17 ); field_mul ( L0, L2, L3 ); field_sqrn ( L2, L0, 51 ); field_mul ( L0, L1, L2 ); field_sqrn ( L1, L0, 119 ); field_mul ( L2, L0, L1 ); field_sqr ( L0, L2 ); field_mul ( L1, x, L0 ); field_sqrn ( L0, L1, 239 ); field_mul ( a, L2, L0 ); }
/*- * Determines whether the given EC_POINT is an actual point on the curve defined * in the EC_GROUP. A point is valid if it satisfies the Weierstrass equation: * y^2 + x*y = x^3 + a*x^2 + b. */ int ec_GF2m_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx) { int ret = -1; BN_CTX *new_ctx = NULL; BIGNUM *lh, *y2; int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); if (EC_POINT_is_at_infinity(group, point)) return 1; field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; /* only support affine coordinates */ if (!point->Z_is_one) return -1; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return -1; } BN_CTX_start(ctx); y2 = BN_CTX_get(ctx); lh = BN_CTX_get(ctx); if (lh == NULL) goto err; /*- * We have a curve defined by a Weierstrass equation * y^2 + x*y = x^3 + a*x^2 + b. * <=> x^3 + a*x^2 + x*y + b + y^2 = 0 * <=> ((x + a) * x + y ) * x + b + y^2 = 0 */ if (!BN_GF2m_add(lh, &point->X, &group->a)) goto err; if (!field_mul(group, lh, lh, &point->X, ctx)) goto err; if (!BN_GF2m_add(lh, lh, &point->Y)) goto err; if (!field_mul(group, lh, lh, &point->X, ctx)) goto err; if (!BN_GF2m_add(lh, lh, &group->b)) goto err; if (!field_sqr(group, y2, &point->Y, ctx)) goto err; if (!BN_GF2m_add(lh, lh, y2)) goto err; ret = BN_is_zero(lh); err: if (ctx) BN_CTX_end(ctx); if (new_ctx) BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx) { int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); const BIGNUM *p; BN_CTX *new_ctx = NULL; BIGNUM *rh, *tmp, *Z4, *Z6; int ret = -1; if (EC_POINT_is_at_infinity(group, point)) return 1; field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; p = group->field; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return -1; } BN_CTX_start(ctx); rh = BN_CTX_get(ctx); tmp = BN_CTX_get(ctx); Z4 = BN_CTX_get(ctx); Z6 = BN_CTX_get(ctx); if (Z6 == NULL) goto err; /*- * We have a curve defined by a Weierstrass equation * y^2 = x^3 + a*x + b. * The point to consider is given in Jacobian projective coordinates * where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3). * Substituting this and multiplying by Z^6 transforms the above equation into * Y^2 = X^3 + a*X*Z^4 + b*Z^6. * To test this, we add up the right-hand side in 'rh'. */ /* rh := X^2 */ if (!field_sqr(group, rh, point->X, ctx)) goto err; if (!point->Z_is_one) { if (!field_sqr(group, tmp, point->Z, ctx)) goto err; if (!field_sqr(group, Z4, tmp, ctx)) goto err; if (!field_mul(group, Z6, Z4, tmp, ctx)) goto err; /* rh := (rh + a*Z^4)*X */ if (group->a_is_minus3) { if (!BN_mod_lshift1_quick(tmp, Z4, p)) goto err; if (!BN_mod_add_quick(tmp, tmp, Z4, p)) goto err; if (!BN_mod_sub_quick(rh, rh, tmp, p)) goto err; if (!field_mul(group, rh, rh, point->X, ctx)) goto err; } else { if (!field_mul(group, tmp, Z4, group->a, ctx)) goto err; if (!BN_mod_add_quick(rh, rh, tmp, p)) goto err; if (!field_mul(group, rh, rh, point->X, ctx)) goto err; } /* rh := rh + b*Z^6 */ if (!field_mul(group, tmp, group->b, Z6, ctx)) goto err; if (!BN_mod_add_quick(rh, rh, tmp, p)) goto err; } else { /* point->Z_is_one */ /* rh := (rh + a)*X */ if (!BN_mod_add_quick(rh, rh, group->a, p)) goto err; if (!field_mul(group, rh, rh, point->X, ctx)) goto err; /* rh := rh + b */ if (!BN_mod_add_quick(rh, rh, group->b, p)) goto err; } /* 'lh' := Y^2 */ if (!field_sqr(group, tmp, point->Y, ctx)) goto err; ret = (0 == BN_ucmp(tmp, rh)); err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx) { int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); const BIGNUM *p; BN_CTX *new_ctx = NULL; BIGNUM *n0, *n1, *n2, *n3; int ret = 0; if (EC_POINT_is_at_infinity(group, a)) { BN_zero(r->Z); r->Z_is_one = 0; return 1; } field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; p = group->field; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } BN_CTX_start(ctx); n0 = BN_CTX_get(ctx); n1 = BN_CTX_get(ctx); n2 = BN_CTX_get(ctx); n3 = BN_CTX_get(ctx); if (n3 == NULL) goto err; /* * Note that in this function we must not read components of 'a' once we * have written the corresponding components of 'r'. ('r' might the same * as 'a'.) */ /* n1 */ if (a->Z_is_one) { if (!field_sqr(group, n0, a->X, ctx)) goto err; if (!BN_mod_lshift1_quick(n1, n0, p)) goto err; if (!BN_mod_add_quick(n0, n0, n1, p)) goto err; if (!BN_mod_add_quick(n1, n0, group->a, p)) goto err; /* n1 = 3 * X_a^2 + a_curve */ } else if (group->a_is_minus3) { if (!field_sqr(group, n1, a->Z, ctx)) goto err; if (!BN_mod_add_quick(n0, a->X, n1, p)) goto err; if (!BN_mod_sub_quick(n2, a->X, n1, p)) goto err; if (!field_mul(group, n1, n0, n2, ctx)) goto err; if (!BN_mod_lshift1_quick(n0, n1, p)) goto err; if (!BN_mod_add_quick(n1, n0, n1, p)) goto err; /*- * n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2) * = 3 * X_a^2 - 3 * Z_a^4 */ } else { if (!field_sqr(group, n0, a->X, ctx)) goto err; if (!BN_mod_lshift1_quick(n1, n0, p)) goto err; if (!BN_mod_add_quick(n0, n0, n1, p)) goto err; if (!field_sqr(group, n1, a->Z, ctx)) goto err; if (!field_sqr(group, n1, n1, ctx)) goto err; if (!field_mul(group, n1, n1, group->a, ctx)) goto err; if (!BN_mod_add_quick(n1, n1, n0, p)) goto err; /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */ } /* Z_r */ if (a->Z_is_one) { if (!BN_copy(n0, a->Y)) goto err; } else { if (!field_mul(group, n0, a->Y, a->Z, ctx)) goto err; } if (!BN_mod_lshift1_quick(r->Z, n0, p)) goto err; r->Z_is_one = 0; /* Z_r = 2 * Y_a * Z_a */ /* n2 */ if (!field_sqr(group, n3, a->Y, ctx)) goto err; if (!field_mul(group, n2, a->X, n3, ctx)) goto err; if (!BN_mod_lshift_quick(n2, n2, 2, p)) goto err; /* n2 = 4 * X_a * Y_a^2 */ /* X_r */ if (!BN_mod_lshift1_quick(n0, n2, p)) goto err; if (!field_sqr(group, r->X, n1, ctx)) goto err; if (!BN_mod_sub_quick(r->X, r->X, n0, p)) goto err; /* X_r = n1^2 - 2 * n2 */ /* n3 */ if (!field_sqr(group, n0, n3, ctx)) goto err; if (!BN_mod_lshift_quick(n3, n0, 3, p)) goto err; /* n3 = 8 * Y_a^4 */ /* Y_r */ if (!BN_mod_sub_quick(n0, n2, r->X, p)) goto err; if (!field_mul(group, n0, n1, n0, ctx)) goto err; if (!BN_mod_sub_quick(r->Y, n0, n3, p)) goto err; /* Y_r = n1 * (n2 - X_r) - n3 */ ret = 1; err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) { int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); const BIGNUM *p; BN_CTX *new_ctx = NULL; BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6; int ret = 0; if (a == b) return EC_POINT_dbl(group, r, a, ctx); if (EC_POINT_is_at_infinity(group, a)) return EC_POINT_copy(r, b); if (EC_POINT_is_at_infinity(group, b)) return EC_POINT_copy(r, a); field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; p = group->field; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } BN_CTX_start(ctx); n0 = BN_CTX_get(ctx); n1 = BN_CTX_get(ctx); n2 = BN_CTX_get(ctx); n3 = BN_CTX_get(ctx); n4 = BN_CTX_get(ctx); n5 = BN_CTX_get(ctx); n6 = BN_CTX_get(ctx); if (n6 == NULL) goto end; /* * Note that in this function we must not read components of 'a' or 'b' * once we have written the corresponding components of 'r'. ('r' might * be one of 'a' or 'b'.) */ /* n1, n2 */ if (b->Z_is_one) { if (!BN_copy(n1, a->X)) goto end; if (!BN_copy(n2, a->Y)) goto end; /* n1 = X_a */ /* n2 = Y_a */ } else { if (!field_sqr(group, n0, b->Z, ctx)) goto end; if (!field_mul(group, n1, a->X, n0, ctx)) goto end; /* n1 = X_a * Z_b^2 */ if (!field_mul(group, n0, n0, b->Z, ctx)) goto end; if (!field_mul(group, n2, a->Y, n0, ctx)) goto end; /* n2 = Y_a * Z_b^3 */ } /* n3, n4 */ if (a->Z_is_one) { if (!BN_copy(n3, b->X)) goto end; if (!BN_copy(n4, b->Y)) goto end; /* n3 = X_b */ /* n4 = Y_b */ } else { if (!field_sqr(group, n0, a->Z, ctx)) goto end; if (!field_mul(group, n3, b->X, n0, ctx)) goto end; /* n3 = X_b * Z_a^2 */ if (!field_mul(group, n0, n0, a->Z, ctx)) goto end; if (!field_mul(group, n4, b->Y, n0, ctx)) goto end; /* n4 = Y_b * Z_a^3 */ } /* n5, n6 */ if (!BN_mod_sub_quick(n5, n1, n3, p)) goto end; if (!BN_mod_sub_quick(n6, n2, n4, p)) goto end; /* n5 = n1 - n3 */ /* n6 = n2 - n4 */ if (BN_is_zero(n5)) { if (BN_is_zero(n6)) { /* a is the same point as b */ BN_CTX_end(ctx); ret = EC_POINT_dbl(group, r, a, ctx); ctx = NULL; goto end; } else { /* a is the inverse of b */ BN_zero(r->Z); r->Z_is_one = 0; ret = 1; goto end; } } /* 'n7', 'n8' */ if (!BN_mod_add_quick(n1, n1, n3, p)) goto end; if (!BN_mod_add_quick(n2, n2, n4, p)) goto end; /* 'n7' = n1 + n3 */ /* 'n8' = n2 + n4 */ /* Z_r */ if (a->Z_is_one && b->Z_is_one) { if (!BN_copy(r->Z, n5)) goto end; } else { if (a->Z_is_one) { if (!BN_copy(n0, b->Z)) goto end; } else if (b->Z_is_one) { if (!BN_copy(n0, a->Z)) goto end; } else { if (!field_mul(group, n0, a->Z, b->Z, ctx)) goto end; } if (!field_mul(group, r->Z, n0, n5, ctx)) goto end; } r->Z_is_one = 0; /* Z_r = Z_a * Z_b * n5 */ /* X_r */ if (!field_sqr(group, n0, n6, ctx)) goto end; if (!field_sqr(group, n4, n5, ctx)) goto end; if (!field_mul(group, n3, n1, n4, ctx)) goto end; if (!BN_mod_sub_quick(r->X, n0, n3, p)) goto end; /* X_r = n6^2 - n5^2 * 'n7' */ /* 'n9' */ if (!BN_mod_lshift1_quick(n0, r->X, p)) goto end; if (!BN_mod_sub_quick(n0, n3, n0, p)) goto end; /* n9 = n5^2 * 'n7' - 2 * X_r */ /* Y_r */ if (!field_mul(group, n0, n0, n6, ctx)) goto end; if (!field_mul(group, n5, n4, n5, ctx)) goto end; /* now n5 is n5^3 */ if (!field_mul(group, n1, n2, n5, ctx)) goto end; if (!BN_mod_sub_quick(n0, n0, n1, p)) goto end; if (BN_is_odd(n0)) if (!BN_add(n0, n0, p)) goto end; /* now 0 <= n0 < 2*p, and n0 is even */ if (!BN_rshift1(r->Y, n0)) goto end; /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */ ret = 1; end: if (ctx) /* otherwise we already called BN_CTX_end */ BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) { /*- * return values: * -1 error * 0 equal (in affine coordinates) * 1 not equal */ int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); BN_CTX *new_ctx = NULL; BIGNUM *tmp1, *tmp2, *Za23, *Zb23; const BIGNUM *tmp1_, *tmp2_; int ret = -1; if (EC_POINT_is_at_infinity(group, a)) { return EC_POINT_is_at_infinity(group, b) ? 0 : 1; } if (EC_POINT_is_at_infinity(group, b)) return 1; if (a->Z_is_one && b->Z_is_one) { return ((BN_cmp(a->X, b->X) == 0) && BN_cmp(a->Y, b->Y) == 0) ? 0 : 1; } field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return -1; } BN_CTX_start(ctx); tmp1 = BN_CTX_get(ctx); tmp2 = BN_CTX_get(ctx); Za23 = BN_CTX_get(ctx); Zb23 = BN_CTX_get(ctx); if (Zb23 == NULL) goto end; /*- * We have to decide whether * (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3), * or equivalently, whether * (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3). */ if (!b->Z_is_one) { if (!field_sqr(group, Zb23, b->Z, ctx)) goto end; if (!field_mul(group, tmp1, a->X, Zb23, ctx)) goto end; tmp1_ = tmp1; } else tmp1_ = a->X; if (!a->Z_is_one) { if (!field_sqr(group, Za23, a->Z, ctx)) goto end; if (!field_mul(group, tmp2, b->X, Za23, ctx)) goto end; tmp2_ = tmp2; } else tmp2_ = b->X; /* compare X_a*Z_b^2 with X_b*Z_a^2 */ if (BN_cmp(tmp1_, tmp2_) != 0) { ret = 1; /* points differ */ goto end; } if (!b->Z_is_one) { if (!field_mul(group, Zb23, Zb23, b->Z, ctx)) goto end; if (!field_mul(group, tmp1, a->Y, Zb23, ctx)) goto end; /* tmp1_ = tmp1 */ } else tmp1_ = a->Y; if (!a->Z_is_one) { if (!field_mul(group, Za23, Za23, a->Z, ctx)) goto end; if (!field_mul(group, tmp2, b->Y, Za23, ctx)) goto end; /* tmp2_ = tmp2 */ } else tmp2_ = b->Y; /* compare Y_a*Z_b^3 with Y_b*Z_a^3 */ if (BN_cmp(tmp1_, tmp2_) != 0) { ret = 1; /* points differ */ goto end; } /* points are equal */ ret = 0; end: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx) { int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); const BIGNUM *p; BN_CTX *new_ctx = NULL; BIGNUM *n0, *n1, *n2, *n3; int ret = 0; if (EC_POINT_is_at_infinity(group, a)) { BN_zero(&r->Z); return 1; } field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; p = &group->field; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { return 0; } } BN_CTX_start(ctx); n0 = BN_CTX_get(ctx); n1 = BN_CTX_get(ctx); n2 = BN_CTX_get(ctx); n3 = BN_CTX_get(ctx); if (n3 == NULL) { goto err; } /* Note that in this function we must not read components of 'a' * once we have written the corresponding components of 'r'. * ('r' might the same as 'a'.) */ /* n1 */ if (BN_cmp(&a->Z, &group->one) == 0) { if (!field_sqr(group, n0, &a->X, ctx) || !BN_mod_lshift1_quick(n1, n0, p) || !BN_mod_add_quick(n0, n0, n1, p) || !BN_mod_add_quick(n1, n0, &group->a, p)) { goto err; } /* n1 = 3 * X_a^2 + a_curve */ } else { /* ring: This assumes a == -3. */ if (!field_sqr(group, n1, &a->Z, ctx) || !BN_mod_add_quick(n0, &a->X, n1, p) || !BN_mod_sub_quick(n2, &a->X, n1, p) || !field_mul(group, n1, n0, n2, ctx) || !BN_mod_lshift1_quick(n0, n1, p) || !BN_mod_add_quick(n1, n0, n1, p)) { goto err; } /* n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2) * = 3 * X_a^2 - 3 * Z_a^4 */ } /* Z_r */ if (BN_cmp(&a->Z, &group->one) == 0) { if (!BN_copy(n0, &a->Y)) { goto err; } } else if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) { goto err; } if (!BN_mod_lshift1_quick(&r->Z, n0, p)) { goto err; } /* Z_r = 2 * Y_a * Z_a */ /* n2 */ if (!field_sqr(group, n3, &a->Y, ctx) || !field_mul(group, n2, &a->X, n3, ctx) || !BN_mod_lshift_quick(n2, n2, 2, p)) { goto err; } /* n2 = 4 * X_a * Y_a^2 */ /* X_r */ if (!BN_mod_lshift1_quick(n0, n2, p) || !field_sqr(group, &r->X, n1, ctx) || !BN_mod_sub_quick(&r->X, &r->X, n0, p)) { goto err; } /* X_r = n1^2 - 2 * n2 */ /* n3 */ if (!field_sqr(group, n0, n3, ctx) || !BN_mod_lshift_quick(n3, n0, 3, p)) { goto err; } /* n3 = 8 * Y_a^4 */ /* Y_r */ if (!BN_mod_sub_quick(n0, n2, &r->X, p) || !field_mul(group, n0, n1, n0, ctx) || !BN_mod_sub_quick(&r->Y, n0, n3, p)) { goto err; } /* Y_r = n1 * (n2 - X_r) - n3 */ ret = 1; err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int main(int argc, char **argv) { (void)argc; (void)argv; struct tw_extensible_t ext; struct extensible_t exta; struct tw_niels_t niels; struct tw_pniels_t pniels; struct affine_t affine; struct montgomery_t mb; field_a_t a,b,c,d; double when; int i; int nbase = N_TESTS_BASE; /* Bad randomness so we can debug. */ char initial_seed[32]; for (i=0; i<32; i++) initial_seed[i] = i; struct crandom_state_t crand; crandom_init_from_buffer(&crand, initial_seed); /* For testing the performance drop from the crandom debuffering change. ignore_result(crandom_init_from_file(&crand, "/dev/urandom", 10000, 1)); */ word_t sk[SCALAR_WORDS],tk[SCALAR_WORDS]; q448_randomize(&crand, sk); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); memset(d,0,sizeof(d)); when = now(); for (i=0; i<nbase*5000; i++) { field_mul(c, b, a); } when = now() - when; printf("mul: %5.1fns\n", when * 1e9 / i); when = now(); for (i=0; i<nbase*5000; i++) { field_sqr(c, a); } when = now() - when; printf("sqr: %5.1fns\n", when * 1e9 / i); when = now(); for (i=0; i<nbase*5000; i++) { field_mulw(c, b, 1234562); } when = now() - when; printf("mulw: %5.1fns\n", when * 1e9 / i); when = now(); for (i=0; i<nbase*500; i++) { field_mul(c, b, a); field_mul(a, b, c); } when = now() - when; printf("mul dep: %5.1fns\n", when * 1e9 / i / 2); when = now(); for (i=0; i<nbase*10; i++) { field_randomize(&crand, a); } when = now() - when; printf("rand448: %5.1fns\n", when * 1e9 / i); sha512_ctx_a_t sha; uint8_t hashout[128]; when = now(); for (i=0; i<nbase; i++) { sha512_init(sha); sha512_final(sha, hashout); } when = now() - when; printf("sha512 1blk: %5.1fns\n", when * 1e9 / i); when = now(); for (i=0; i<nbase; i++) { sha512_update(sha, hashout, 128); } when = now() - when; printf("sha512 blk: %5.1fns (%0.2f MB/s)\n", when * 1e9 / i, 128*i/when/1e6); when = now(); for (i=0; i<nbase; i++) { field_isr(c, a); } when = now() - when; printf("isr auto: %5.1fµs\n", when * 1e6 / i); for (i=0; i<100; i++) { field_randomize(&crand, a); field_isr(d,a); field_sqr(b,d); field_mul(c,b,a); field_sqr(b,c); field_subw(b,1); if (!field_is_zero(b)) { printf("ISR validation failure!\n"); field_print("a", a); field_print("s", d); } } when = now(); for (i=0; i<nbase; i++) { elligator_2s_inject(&affine, a); } when = now() - when; printf("elligator: %5.1fµs\n", when * 1e6 / i); for (i=0; i<100; i++) { field_randomize(&crand, a); elligator_2s_inject(&affine, a); if (!validate_affine(&affine)) { printf("Elligator validation failure!\n"); field_print("a", a); field_print("x", affine.x); field_print("y", affine.y); } } when = now(); for (i=0; i<nbase; i++) { deserialize_affine(&affine, a); } when = now() - when; printf("decompress: %5.1fµs\n", when * 1e6 / i); convert_affine_to_extensible(&exta, &affine); when = now(); for (i=0; i<nbase; i++) { serialize_extensible(a, &exta); } when = now() - when; printf("compress: %5.1fµs\n", when * 1e6 / i); int goods = 0; for (i=0; i<100; i++) { field_randomize(&crand, a); mask_t good = deserialize_affine(&affine, a); if (good & !validate_affine(&affine)) { printf("Deserialize validation failure!\n"); field_print("a", a); field_print("x", affine.x); field_print("y", affine.y); } else if (good) { goods++; convert_affine_to_extensible(&exta,&affine); serialize_extensible(b, &exta); field_sub(c,b,a); if (!field_is_zero(c)) { printf("Reserialize validation failure!\n"); field_print("a", a); field_print("x", affine.x); field_print("y", affine.y); deserialize_affine(&affine, b); field_print("b", b); field_print("x", affine.x); field_print("y", affine.y); printf("\n"); } } } if (goods<i/3) { printf("Deserialization validation failure! Deserialized %d/%d points\n", goods, i); } word_t lsk[768/WORD_BITS]; crandom_generate(&crand, (unsigned char *)lsk, sizeof(lsk)); when = now(); for (i=0; i<nbase*100; i++) { barrett_reduce(lsk,sizeof(lsk)/sizeof(word_t),0,&curve_prime_order); } when = now() - when; printf("barrett red: %5.1fns\n", when * 1e9 / i); when = now(); for (i=0; i<nbase*10; i++) { barrett_mac(lsk,SCALAR_WORDS,lsk,SCALAR_WORDS,lsk,SCALAR_WORDS,&curve_prime_order); } when = now() - when; printf("barrett mac: %5.1fns\n", when * 1e9 / i); memset(&ext,0,sizeof(ext)); memset(&niels,0,sizeof(niels)); /* avoid assertions in p521 even though this isn't a valid ext or niels */ when = now(); for (i=0; i<nbase*100; i++) { add_tw_niels_to_tw_extensible(&ext, &niels); } when = now() - when; printf("exti+niels: %5.1fns\n", when * 1e9 / i); convert_tw_extensible_to_tw_pniels(&pniels, &ext); when = now(); for (i=0; i<nbase*100; i++) { add_tw_pniels_to_tw_extensible(&ext, &pniels); } when = now() - when; printf("exti+pniels: %5.1fns\n", when * 1e9 / i); when = now(); for (i=0; i<nbase*100; i++) { double_tw_extensible(&ext); } when = now() - when; printf("exti dbl: %5.1fns\n", when * 1e9 / i); when = now(); for (i=0; i<nbase*100; i++) { untwist_and_double(&exta, &ext); } when = now() - when; printf("i->a isog: %5.1fns\n", when * 1e9 / i); when = now(); for (i=0; i<nbase*100; i++) { twist_and_double(&ext, &exta); } when = now() - when; printf("a->i isog: %5.1fns\n", when * 1e9 / i); memset(&mb,0,sizeof(mb)); when = now(); for (i=0; i<nbase*100; i++) { montgomery_step(&mb); } when = now() - when; printf("monty step: %5.1fns\n", when * 1e9 / i); when = now(); for (i=0; i<nbase/10; i++) { ignore_result(montgomery_ladder(a,b,sk,FIELD_BITS,0)); } when = now() - when; printf("full ladder: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { scalarmul(&ext,sk); } when = now() - when; printf("edwards smz: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { scalarmul_vlook(&ext,sk); } when = now() - when; printf("edwards svl: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { scalarmul(&ext,sk); untwist_and_double_and_serialize(a,&ext); } when = now() - when; printf("edwards smc: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { q448_randomize(&crand, sk); scalarmul_vt(&ext,sk,SCALAR_BITS); } when = now() - when; printf("edwards vtm: %5.1fµs\n", when * 1e6 / i); tw_niels_a_t wnaft[1<<6]; when = now(); for (i=0; i<nbase/10; i++) { ignore_result(precompute_fixed_base_wnaf(wnaft,&ext,6)); } when = now() - when; printf("wnaf6 pre: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { q448_randomize(&crand, sk); scalarmul_fixed_base_wnaf_vt(&ext,sk,SCALAR_BITS,(const tw_niels_a_t*)wnaft,6); } when = now() - when; printf("edwards vt6: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { ignore_result(precompute_fixed_base_wnaf(wnaft,&ext,4)); } when = now() - when; printf("wnaf4 pre: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { q448_randomize(&crand, sk); scalarmul_fixed_base_wnaf_vt(&ext,sk,SCALAR_BITS,(const tw_niels_a_t*)wnaft,4); } when = now() - when; printf("edwards vt4: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { ignore_result(precompute_fixed_base_wnaf(wnaft,&ext,5)); } when = now() - when; printf("wnaf5 pre: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { q448_randomize(&crand, sk); scalarmul_fixed_base_wnaf_vt(&ext,sk,SCALAR_BITS,(const tw_niels_a_t*)wnaft,5); } when = now() - when; printf("edwards vt5: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { q448_randomize(&crand, sk); q448_randomize(&crand, tk); linear_combo_var_fixed_vt(&ext,sk,FIELD_BITS,tk,FIELD_BITS,(const tw_niels_a_t*)wnaft,5); } when = now() - when; printf("vt vf combo: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { deserialize_affine(&affine, a); convert_affine_to_extensible(&exta,&affine); twist_and_double(&ext,&exta); scalarmul(&ext,sk); untwist_and_double(&exta,&ext); serialize_extensible(b, &exta); } when = now() - when; printf("edwards sm: %5.1fµs\n", when * 1e6 / i); struct fixed_base_table_t t_5_5_18, t_3_5_30, t_8_4_14, t_5_3_30, t_15_3_10; while (1) { field_randomize(&crand, a); if (deserialize_affine(&affine, a)) break; } convert_affine_to_extensible(&exta,&affine); twist_and_double(&ext,&exta); when = now(); for (i=0; i<nbase/10; i++) { if (i) destroy_fixed_base(&t_5_5_18); ignore_result(precompute_fixed_base(&t_5_5_18, &ext, 5, 5, 18, NULL)); } when = now() - when; printf("pre(5,5,18): %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { if (i) destroy_fixed_base(&t_3_5_30); ignore_result(precompute_fixed_base(&t_3_5_30, &ext, 3, 5, 30, NULL)); } when = now() - when; printf("pre(3,5,30): %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { if (i) destroy_fixed_base(&t_5_3_30); ignore_result(precompute_fixed_base(&t_5_3_30, &ext, 5, 3, 30, NULL)); } when = now() - when; printf("pre(5,3,30): %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { if (i) destroy_fixed_base(&t_15_3_10); ignore_result(precompute_fixed_base(&t_15_3_10, &ext, 15, 3, 10, NULL)); } when = now() - when; printf("pre(15,3,10):%5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase/10; i++) { if (i) destroy_fixed_base(&t_8_4_14); ignore_result(precompute_fixed_base(&t_8_4_14, &ext, 8, 4, 14, NULL)); } when = now() - when; printf("pre(8,4,14): %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase; i++) { scalarmul_fixed_base(&ext, sk, FIELD_BITS, &t_5_5_18); } when = now() - when; printf("com(5,5,18): %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase; i++) { scalarmul_fixed_base(&ext, sk, FIELD_BITS, &t_3_5_30); } when = now() - when; printf("com(3,5,30): %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase; i++) { scalarmul_fixed_base(&ext, sk, FIELD_BITS, &t_8_4_14); } when = now() - when; printf("com(8,4,14): %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase; i++) { scalarmul_fixed_base(&ext, sk, FIELD_BITS, &t_5_3_30); } when = now() - when; printf("com(5,3,30): %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase; i++) { scalarmul_fixed_base(&ext, sk, FIELD_BITS, &t_15_3_10); } when = now() - when; printf("com(15,3,10):%5.1fµs\n", when * 1e6 / i); printf("\nGoldilocks:\n"); int res = goldilocks_init(); assert(!res); struct goldilocks_public_key_t gpk,hpk; struct goldilocks_private_key_t gsk,hsk; when = now(); for (i=0; i<nbase; i++) { if (i&1) { res = goldilocks_keygen(&gsk,&gpk); } else { res = goldilocks_keygen(&hsk,&hpk); } assert(!res); } when = now() - when; printf("keygen: %5.1fµs\n", when * 1e6 / i); uint8_t ss1[64],ss2[64]; int gres1=0,gres2=0; when = now(); for (i=0; i<nbase; i++) { if (i&1) { gres1 = goldilocks_shared_secret(ss1,&gsk,&hpk); } else { gres2 = goldilocks_shared_secret(ss2,&hsk,&gpk); } } when = now() - when; printf("ecdh: %5.1fµs\n", when * 1e6 / i); if (gres1 || gres2 || memcmp(ss1,ss2,64)) { printf("[FAIL] %d %d\n",gres1,gres2); printf("sk1 = "); for (i=0; i<SCALAR_BYTES; i++) { printf("%02x", gsk.opaque[i]); } printf("\nsk2 = "); for (i=0; i<SCALAR_BYTES; i++) { printf("%02x", hsk.opaque[i]); } printf("\nss1 = "); for (i=0; i<64; i++) { printf("%02x", ss1[i]); } printf("\nss2 = "); for (i=0; i<64; i++) { printf("%02x", ss2[i]); } printf("\n"); } uint8_t sout[FIELD_BYTES*2]; const char *message = "hello world"; size_t message_len = strlen(message); when = now(); for (i=0; i<nbase; i++) { res = goldilocks_sign(sout,(const unsigned char *)message,message_len,&gsk); (void)res; assert(!res); } when = now() - when; printf("sign: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase; i++) { int ver = goldilocks_verify(sout,(const unsigned char *)message,message_len,&gpk); (void)ver; assert(!ver); } when = now() - when; printf("verify: %5.1fµs\n", when * 1e6 / i); struct goldilocks_precomputed_public_key_t *pre = NULL; when = now(); for (i=0; i<nbase; i++) { goldilocks_destroy_precomputed_public_key(pre); pre = goldilocks_precompute_public_key(&gpk); } when = now() - when; printf("precompute: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase; i++) { int ver = goldilocks_verify_precomputed(sout,(const unsigned char *)message,message_len,pre); (void)ver; assert(!ver); } when = now() - when; printf("verify pre: %5.1fµs\n", when * 1e6 / i); when = now(); for (i=0; i<nbase; i++) { int ret = goldilocks_shared_secret_precomputed(ss1,&gsk,pre); (void)ret; assert(!ret); } when = now() - when; printf("ecdh pre: %5.1fµs\n", when * 1e6 / i); printf("\nTesting...\n"); int failures=0, successes = 0; for (i=0; i<nbase/10; i++) { ignore_result(goldilocks_keygen(&gsk,&gpk)); goldilocks_sign(sout,(const unsigned char *)message,message_len,&gsk); res = goldilocks_verify(sout,(const unsigned char *)message,message_len,&gpk); if (res) failures++; } if (failures) { printf("FAIL %d/%d signature checks!\n", failures, i); } failures=0; successes = 0; for (i=0; i<nbase/10; i++) { field_randomize(&crand, a); word_t two = 2; mask_t good = montgomery_ladder(b,a,&two,2,0); if (!good) continue; word_t x,y; crandom_generate(&crand, (unsigned char *)&x, sizeof(x)); crandom_generate(&crand, (unsigned char *)&y, sizeof(y)); x = (hword_t)x; y = (hword_t)y; word_t z=x*y; ignore_result(montgomery_ladder(b,a,&x,WORD_BITS,0)); ignore_result(montgomery_ladder(c,b,&y,WORD_BITS,0)); ignore_result(montgomery_ladder(b,a,&z,WORD_BITS,0)); field_sub(d,b,c); if (!field_is_zero(d)) { printf("Odd ladder validation failure %d!\n", ++failures); field_print("a", a); printf("x=%"PRIxWORD", y=%"PRIxWORD", z=%"PRIxWORD"\n", x,y,z); field_print("c", c); field_print("b", b); printf("\n"); } } failures = 0; for (i=0; i<nbase/10; i++) { mask_t good; do { field_randomize(&crand, a); good = deserialize_affine(&affine, a); } while (!good); convert_affine_to_extensible(&exta,&affine); twist_and_double(&ext,&exta); untwist_and_double(&exta,&ext); serialize_extensible(b, &exta); untwist_and_double_and_serialize(c, &ext); field_sub(d,b,c); if (good && !field_is_zero(d)){ printf("Iso+serial validation failure %d!\n", ++failures); field_print("a", a); field_print("b", b); field_print("c", c); printf("\n"); } else if (good) { successes ++; } } if (successes < i/3) { printf("Iso+serial variation: only %d/%d successful.\n", successes, i); } successes = failures = 0; for (i=0; i<nbase/10; i++) { field_a_t aa; struct tw_extensible_t exu,exv,exw; mask_t good; do { field_randomize(&crand, a); good = deserialize_affine(&affine, a); convert_affine_to_extensible(&exta,&affine); twist_and_double(&ext,&exta); } while (!good); do { field_randomize(&crand, aa); good = deserialize_affine(&affine, aa); convert_affine_to_extensible(&exta,&affine); twist_and_double(&exu,&exta); } while (!good); field_randomize(&crand, aa); q448_randomize(&crand, sk); if (i==0 || i==2) memset(&sk, 0, sizeof(sk)); q448_randomize(&crand, tk); if (i==0 || i==1) memset(&tk, 0, sizeof(tk)); copy_tw_extensible(&exv, &ext); copy_tw_extensible(&exw, &exu); scalarmul(&exv,sk); scalarmul(&exw,tk); convert_tw_extensible_to_tw_pniels(&pniels, &exw); add_tw_pniels_to_tw_extensible(&exv,&pniels); untwist_and_double(&exta,&exv); serialize_extensible(b, &exta); ignore_result(precompute_fixed_base_wnaf(wnaft,&exu,5)); linear_combo_var_fixed_vt(&ext,sk,FIELD_BITS,tk,FIELD_BITS,(const tw_niels_a_t*)wnaft,5); untwist_and_double(&exta,&exv); serialize_extensible(c, &exta); field_sub(d,b,c); if (!field_is_zero(d)){ printf("PreWNAF combo validation failure %d!\n", ++failures); field_print("a", a); field_print("A", aa); q448_print("s", sk); q448_print("t", tk); field_print("c", c); field_print("b", b); printf("\n\n"); } else if (good) { successes ++; } } if (successes < i) { printf("PreWNAF combo variation: only %d/%d successful.\n", successes, i); } return 0; }
int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) { // return values: // -1 error // 0 equal (in affine coordinates) // 1 not equal int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); BN_CTX *new_ctx = NULL; BIGNUM *tmp1, *tmp2, *Za23, *Zb23; const BIGNUM *tmp1_, *tmp2_; int ret = -1; if (ec_GFp_simple_is_at_infinity(group, a)) { return ec_GFp_simple_is_at_infinity(group, b) ? 0 : 1; } if (ec_GFp_simple_is_at_infinity(group, b)) { return 1; } int a_Z_is_one = BN_cmp(&a->Z, &group->one) == 0; int b_Z_is_one = BN_cmp(&b->Z, &group->one) == 0; if (a_Z_is_one && b_Z_is_one) { return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1; } field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { return -1; } } BN_CTX_start(ctx); tmp1 = BN_CTX_get(ctx); tmp2 = BN_CTX_get(ctx); Za23 = BN_CTX_get(ctx); Zb23 = BN_CTX_get(ctx); if (Zb23 == NULL) { goto end; } // We have to decide whether // (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3), // or equivalently, whether // (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3). if (!b_Z_is_one) { if (!field_sqr(group, Zb23, &b->Z, ctx) || !field_mul(group, tmp1, &a->X, Zb23, ctx)) { goto end; } tmp1_ = tmp1; } else { tmp1_ = &a->X; } if (!a_Z_is_one) { if (!field_sqr(group, Za23, &a->Z, ctx) || !field_mul(group, tmp2, &b->X, Za23, ctx)) { goto end; } tmp2_ = tmp2; } else { tmp2_ = &b->X; } // compare X_a*Z_b^2 with X_b*Z_a^2 if (BN_cmp(tmp1_, tmp2_) != 0) { ret = 1; // points differ goto end; } if (!b_Z_is_one) { if (!field_mul(group, Zb23, Zb23, &b->Z, ctx) || !field_mul(group, tmp1, &a->Y, Zb23, ctx)) { goto end; } // tmp1_ = tmp1 } else { tmp1_ = &a->Y; } if (!a_Z_is_one) { if (!field_mul(group, Za23, Za23, &a->Z, ctx) || !field_mul(group, tmp2, &b->Y, Za23, ctx)) { goto end; } // tmp2_ = tmp2 } else { tmp2_ = &b->Y; } // compare Y_a*Z_b^3 with Y_b*Z_a^3 if (BN_cmp(tmp1_, tmp2_) != 0) { ret = 1; // points differ goto end; } // points are equal ret = 0; end: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx) { int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); const BIGNUM *p; BN_CTX *new_ctx = NULL; BIGNUM *rh, *tmp, *Z4, *Z6; int ret = 0; if (EC_POINT_is_at_infinity(group, point)) { return 1; } field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; p = &group->field; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { return 0; } } BN_CTX_start(ctx); rh = BN_CTX_get(ctx); tmp = BN_CTX_get(ctx); Z4 = BN_CTX_get(ctx); Z6 = BN_CTX_get(ctx); if (Z6 == NULL) { goto err; } // We have a curve defined by a Weierstrass equation // y^2 = x^3 + a*x + b. // The point to consider is given in Jacobian projective coordinates // where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3). // Substituting this and multiplying by Z^6 transforms the above equation // into // Y^2 = X^3 + a*X*Z^4 + b*Z^6. // To test this, we add up the right-hand side in 'rh'. // rh := X^2 if (!field_sqr(group, rh, &point->X, ctx)) { goto err; } if (BN_cmp(&point->Z, &group->one) != 0) { if (!field_sqr(group, tmp, &point->Z, ctx) || !field_sqr(group, Z4, tmp, ctx) || !field_mul(group, Z6, Z4, tmp, ctx)) { goto err; } // rh := (rh + a*Z^4)*X if (group->a_is_minus3) { if (!bn_mod_lshift1_consttime(tmp, Z4, p, ctx) || !bn_mod_add_consttime(tmp, tmp, Z4, p, ctx) || !bn_mod_sub_consttime(rh, rh, tmp, p, ctx) || !field_mul(group, rh, rh, &point->X, ctx)) { goto err; } } else { if (!field_mul(group, tmp, Z4, &group->a, ctx) || !bn_mod_add_consttime(rh, rh, tmp, p, ctx) || !field_mul(group, rh, rh, &point->X, ctx)) { goto err; } } // rh := rh + b*Z^6 if (!field_mul(group, tmp, &group->b, Z6, ctx) || !bn_mod_add_consttime(rh, rh, tmp, p, ctx)) { goto err; } } else { // rh := (rh + a)*X if (!bn_mod_add_consttime(rh, rh, &group->a, p, ctx) || !field_mul(group, rh, rh, &point->X, ctx)) { goto err; } // rh := rh + b if (!bn_mod_add_consttime(rh, rh, &group->b, p, ctx)) { goto err; } } // 'lh' := Y^2 if (!field_sqr(group, tmp, &point->Y, ctx)) { goto err; } ret = (0 == BN_ucmp(tmp, rh)); err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx) { int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); const BIGNUM *p; BN_CTX *new_ctx = NULL; BIGNUM *n0, *n1, *n2, *n3; int ret = 0; if (EC_POINT_is_at_infinity(group, a)) { BN_zero(&r->Z); return 1; } field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; p = &group->field; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { return 0; } } BN_CTX_start(ctx); n0 = BN_CTX_get(ctx); n1 = BN_CTX_get(ctx); n2 = BN_CTX_get(ctx); n3 = BN_CTX_get(ctx); if (n3 == NULL) { goto err; } // Note that in this function we must not read components of 'a' // once we have written the corresponding components of 'r'. // ('r' might the same as 'a'.) // n1 if (BN_cmp(&a->Z, &group->one) == 0) { if (!field_sqr(group, n0, &a->X, ctx) || !bn_mod_lshift1_consttime(n1, n0, p, ctx) || !bn_mod_add_consttime(n0, n0, n1, p, ctx) || !bn_mod_add_consttime(n1, n0, &group->a, p, ctx)) { goto err; } // n1 = 3 * X_a^2 + a_curve } else if (group->a_is_minus3) { if (!field_sqr(group, n1, &a->Z, ctx) || !bn_mod_add_consttime(n0, &a->X, n1, p, ctx) || !bn_mod_sub_consttime(n2, &a->X, n1, p, ctx) || !field_mul(group, n1, n0, n2, ctx) || !bn_mod_lshift1_consttime(n0, n1, p, ctx) || !bn_mod_add_consttime(n1, n0, n1, p, ctx)) { goto err; } // n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2) // = 3 * X_a^2 - 3 * Z_a^4 } else { if (!field_sqr(group, n0, &a->X, ctx) || !bn_mod_lshift1_consttime(n1, n0, p, ctx) || !bn_mod_add_consttime(n0, n0, n1, p, ctx) || !field_sqr(group, n1, &a->Z, ctx) || !field_sqr(group, n1, n1, ctx) || !field_mul(group, n1, n1, &group->a, ctx) || !bn_mod_add_consttime(n1, n1, n0, p, ctx)) { goto err; } // n1 = 3 * X_a^2 + a_curve * Z_a^4 } // Z_r if (BN_cmp(&a->Z, &group->one) == 0) { if (!BN_copy(n0, &a->Y)) { goto err; } } else if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) { goto err; } if (!bn_mod_lshift1_consttime(&r->Z, n0, p, ctx)) { goto err; } // Z_r = 2 * Y_a * Z_a // n2 if (!field_sqr(group, n3, &a->Y, ctx) || !field_mul(group, n2, &a->X, n3, ctx) || !bn_mod_lshift_consttime(n2, n2, 2, p, ctx)) { goto err; } // n2 = 4 * X_a * Y_a^2 // X_r if (!bn_mod_lshift1_consttime(n0, n2, p, ctx) || !field_sqr(group, &r->X, n1, ctx) || !bn_mod_sub_consttime(&r->X, &r->X, n0, p, ctx)) { goto err; } // X_r = n1^2 - 2 * n2 // n3 if (!field_sqr(group, n0, n3, ctx) || !bn_mod_lshift_consttime(n3, n0, 3, p, ctx)) { goto err; } // n3 = 8 * Y_a^4 // Y_r if (!bn_mod_sub_consttime(n0, n2, &r->X, p, ctx) || !field_mul(group, n0, n1, n0, ctx) || !bn_mod_sub_consttime(&r->Y, n0, n3, p, ctx)) { goto err; } // Y_r = n1 * (n2 - X_r) - n3 ret = 1; err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) { int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); const BIGNUM *p; BN_CTX *new_ctx = NULL; BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6; int ret = 0; if (a == b) { return EC_POINT_dbl(group, r, a, ctx); } if (EC_POINT_is_at_infinity(group, a)) { return EC_POINT_copy(r, b); } if (EC_POINT_is_at_infinity(group, b)) { return EC_POINT_copy(r, a); } field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; p = &group->field; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { return 0; } } BN_CTX_start(ctx); n0 = BN_CTX_get(ctx); n1 = BN_CTX_get(ctx); n2 = BN_CTX_get(ctx); n3 = BN_CTX_get(ctx); n4 = BN_CTX_get(ctx); n5 = BN_CTX_get(ctx); n6 = BN_CTX_get(ctx); if (n6 == NULL) { goto end; } // Note that in this function we must not read components of 'a' or 'b' // once we have written the corresponding components of 'r'. // ('r' might be one of 'a' or 'b'.) // n1, n2 int b_Z_is_one = BN_cmp(&b->Z, &group->one) == 0; if (b_Z_is_one) { if (!BN_copy(n1, &a->X) || !BN_copy(n2, &a->Y)) { goto end; } // n1 = X_a // n2 = Y_a } else { if (!field_sqr(group, n0, &b->Z, ctx) || !field_mul(group, n1, &a->X, n0, ctx)) { goto end; } // n1 = X_a * Z_b^2 if (!field_mul(group, n0, n0, &b->Z, ctx) || !field_mul(group, n2, &a->Y, n0, ctx)) { goto end; } // n2 = Y_a * Z_b^3 } // n3, n4 int a_Z_is_one = BN_cmp(&a->Z, &group->one) == 0; if (a_Z_is_one) { if (!BN_copy(n3, &b->X) || !BN_copy(n4, &b->Y)) { goto end; } // n3 = X_b // n4 = Y_b } else { if (!field_sqr(group, n0, &a->Z, ctx) || !field_mul(group, n3, &b->X, n0, ctx)) { goto end; } // n3 = X_b * Z_a^2 if (!field_mul(group, n0, n0, &a->Z, ctx) || !field_mul(group, n4, &b->Y, n0, ctx)) { goto end; } // n4 = Y_b * Z_a^3 } // n5, n6 if (!bn_mod_sub_consttime(n5, n1, n3, p, ctx) || !bn_mod_sub_consttime(n6, n2, n4, p, ctx)) { goto end; } // n5 = n1 - n3 // n6 = n2 - n4 if (BN_is_zero(n5)) { if (BN_is_zero(n6)) { // a is the same point as b BN_CTX_end(ctx); ret = EC_POINT_dbl(group, r, a, ctx); ctx = NULL; goto end; } else { // a is the inverse of b BN_zero(&r->Z); ret = 1; goto end; } } // 'n7', 'n8' if (!bn_mod_add_consttime(n1, n1, n3, p, ctx) || !bn_mod_add_consttime(n2, n2, n4, p, ctx)) { goto end; } // 'n7' = n1 + n3 // 'n8' = n2 + n4 // Z_r if (a_Z_is_one && b_Z_is_one) { if (!BN_copy(&r->Z, n5)) { goto end; } } else { if (a_Z_is_one) { if (!BN_copy(n0, &b->Z)) { goto end; } } else if (b_Z_is_one) { if (!BN_copy(n0, &a->Z)) { goto end; } } else if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) { goto end; } if (!field_mul(group, &r->Z, n0, n5, ctx)) { goto end; } } // Z_r = Z_a * Z_b * n5 // X_r if (!field_sqr(group, n0, n6, ctx) || !field_sqr(group, n4, n5, ctx) || !field_mul(group, n3, n1, n4, ctx) || !bn_mod_sub_consttime(&r->X, n0, n3, p, ctx)) { goto end; } // X_r = n6^2 - n5^2 * 'n7' // 'n9' if (!bn_mod_lshift1_consttime(n0, &r->X, p, ctx) || !bn_mod_sub_consttime(n0, n3, n0, p, ctx)) { goto end; } // n9 = n5^2 * 'n7' - 2 * X_r // Y_r if (!field_mul(group, n0, n0, n6, ctx) || !field_mul(group, n5, n4, n5, ctx)) { goto end; // now n5 is n5^3 } if (!field_mul(group, n1, n2, n5, ctx) || !bn_mod_sub_consttime(n0, n0, n1, p, ctx)) { goto end; } if (BN_is_odd(n0) && !BN_add(n0, n0, p)) { goto end; } // now 0 <= n0 < 2*p, and n0 is even if (!BN_rshift1(&r->Y, n0)) { goto end; } // Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 ret = 1; end: if (ctx) { // otherwise we already called BN_CTX_end BN_CTX_end(ctx); } BN_CTX_free(new_ctx); return ret; }