diff options
Diffstat (limited to 'crypto/ec/ec_montgomery.c')
-rw-r--r-- | crypto/ec/ec_montgomery.c | 128 |
1 files changed, 90 insertions, 38 deletions
diff --git a/crypto/ec/ec_montgomery.c b/crypto/ec/ec_montgomery.c index 62b0d7f6..35df3651 100644 --- a/crypto/ec/ec_montgomery.c +++ b/crypto/ec/ec_montgomery.c @@ -79,23 +79,18 @@ int ec_GFp_mont_group_init(EC_GROUP *group) { ok = ec_GFp_simple_group_init(group); group->mont = NULL; - group->one = NULL; return ok; } void ec_GFp_mont_group_finish(EC_GROUP *group) { BN_MONT_CTX_free(group->mont); group->mont = NULL; - BN_free(group->one); - group->one = NULL; ec_GFp_simple_group_finish(group); } int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) { BN_MONT_CTX_free(dest->mont); dest->mont = NULL; - BN_clear_free(dest->one); - dest->one = NULL; if (!ec_GFp_simple_group_copy(dest, src)) { return 0; @@ -110,12 +105,6 @@ int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) { goto err; } } - if (src->one != NULL) { - dest->one = BN_dup(src->one); - if (dest->one == NULL) { - goto err; - } - } return 1; @@ -129,13 +118,10 @@ int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { BN_CTX *new_ctx = NULL; BN_MONT_CTX *mont = NULL; - BIGNUM *one = NULL; int ret = 0; BN_MONT_CTX_free(group->mont); group->mont = NULL; - BN_free(group->one); - group->one = NULL; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); @@ -152,29 +138,20 @@ int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p, OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); goto err; } - one = BN_new(); - if (one == NULL || !BN_to_montgomery(one, BN_value_one(), mont, ctx)) { - goto err; - } group->mont = mont; mont = NULL; - group->one = one; - one = NULL; ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx); if (!ret) { BN_MONT_CTX_free(group->mont); group->mont = NULL; - BN_free(group->one); - group->one = NULL; } err: BN_CTX_free(new_ctx); BN_MONT_CTX_free(mont); - BN_free(one); return ret; } @@ -218,19 +195,6 @@ int ec_GFp_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, return BN_from_montgomery(r, a, group->mont, ctx); } -int ec_GFp_mont_field_set_to_one(const EC_GROUP *group, BIGNUM *r, - BN_CTX *ctx) { - if (group->one == NULL) { - OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED); - return 0; - } - - if (!BN_copy(r, group->one)) { - return 0; - } - return 1; -} - static int ec_GFp_mont_check_pub_key_order(const EC_GROUP *group, const EC_POINT* pub_key, BN_CTX *ctx) { @@ -251,20 +215,108 @@ err: return ret; } +static int ec_GFp_mont_point_get_affine_coordinates(const EC_GROUP *group, + const EC_POINT *point, + BIGNUM *x, BIGNUM *y, + BN_CTX *ctx) { + if (EC_POINT_is_at_infinity(group, point)) { + OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY); + return 0; + } + + BN_CTX *new_ctx = NULL; + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + int ret = 0; + + BN_CTX_start(ctx); + + if (BN_cmp(&point->Z, &group->one) == 0) { + /* |point| is already affine. */ + if (x != NULL && !BN_from_montgomery(x, &point->X, group->mont, ctx)) { + goto err; + } + if (y != NULL && !BN_from_montgomery(y, &point->Y, group->mont, ctx)) { + goto err; + } + } else { + /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */ + + BIGNUM *Z_1 = BN_CTX_get(ctx); + BIGNUM *Z_2 = BN_CTX_get(ctx); + BIGNUM *Z_3 = BN_CTX_get(ctx); + if (Z_1 == NULL || + Z_2 == NULL || + Z_3 == NULL) { + goto err; + } + + /* The straightforward way to calculate the inverse of a Montgomery-encoded + * value where the result is Montgomery-encoded is: + * + * |BN_from_montgomery| + |BN_mod_inverse| + |BN_to_montgomery|. + * + * This is equivalent, but more efficient, because |BN_from_montgomery| + * is more efficient (at least in theory) than |BN_to_montgomery|, since it + * doesn't have to do the multiplication before the reduction. */ + if (!BN_from_montgomery(Z_1, &point->Z, group->mont, ctx) || + !BN_from_montgomery(Z_1, Z_1, group->mont, ctx) || + !BN_mod_inverse(Z_1, Z_1, &group->field, ctx)) { + goto err; + } + + if (!BN_mod_mul_montgomery(Z_2, Z_1, Z_1, group->mont, ctx)) { + goto err; + } + + /* Instead of using |BN_from_montgomery| to convert the |x| coordinate + * and then calling |BN_from_montgomery| again to convert the |y| + * coordinate below, convert the common factor |Z_2| once now, saving one + * reduction. */ + if (!BN_from_montgomery(Z_2, Z_2, group->mont, ctx)) { + goto err; + } + + if (x != NULL) { + if (!BN_mod_mul_montgomery(x, &point->X, Z_2, group->mont, ctx)) { + goto err; + } + } + + if (y != NULL) { + if (!BN_mod_mul_montgomery(Z_3, Z_2, Z_1, group->mont, ctx) || + !BN_mod_mul_montgomery(y, &point->Y, Z_3, group->mont, ctx)) { + goto err; + } + } + } + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + const EC_METHOD *EC_GFp_mont_method(void) { static const EC_METHOD ret = { ec_GFp_mont_group_init, ec_GFp_mont_group_finish, ec_GFp_mont_group_copy, ec_GFp_mont_group_set_curve, - ec_GFp_simple_point_get_affine_coordinates, + ec_GFp_mont_point_get_affine_coordinates, ec_wNAF_mul /* XXX: Not constant time. */, ec_GFp_mont_check_pub_key_order, ec_GFp_mont_field_mul, ec_GFp_mont_field_sqr, ec_GFp_mont_field_encode, ec_GFp_mont_field_decode, - ec_GFp_mont_field_set_to_one, }; return &ret; |