2016-05-17 18:51:04 +00:00
|
|
|
/*
|
2018-05-29 12:07:08 +00:00
|
|
|
* Copyright 2002-2018 The OpenSSL Project Authors. All Rights Reserved.
|
2017-06-15 14:16:46 +00:00
|
|
|
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
|
2016-05-17 18:51:04 +00:00
|
|
|
*
|
|
|
|
* Licensed under the OpenSSL license (the "License"). You may not use
|
|
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
|
|
* in the file LICENSE in the source distribution or at
|
|
|
|
* https://www.openssl.org/source/license.html
|
|
|
|
*/
|
|
|
|
|
2002-08-02 13:42:24 +00:00
|
|
|
#include <openssl/err.h>
|
|
|
|
|
2014-10-28 22:58:56 +00:00
|
|
|
#include "internal/bn_int.h"
|
2002-08-02 13:42:24 +00:00
|
|
|
#include "ec_lcl.h"
|
|
|
|
|
2011-02-12 17:23:32 +00:00
|
|
|
#ifndef OPENSSL_NO_EC2M
|
|
|
|
|
2002-08-02 13:42:24 +00:00
|
|
|
const EC_METHOD *EC_GF2m_simple_method(void)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
static const EC_METHOD ret = {
|
|
|
|
EC_FLAGS_DEFAULT_OCT,
|
|
|
|
NID_X9_62_characteristic_two_field,
|
|
|
|
ec_GF2m_simple_group_init,
|
|
|
|
ec_GF2m_simple_group_finish,
|
|
|
|
ec_GF2m_simple_group_clear_finish,
|
|
|
|
ec_GF2m_simple_group_copy,
|
|
|
|
ec_GF2m_simple_group_set_curve,
|
|
|
|
ec_GF2m_simple_group_get_curve,
|
|
|
|
ec_GF2m_simple_group_get_degree,
|
2016-02-28 17:48:48 +00:00
|
|
|
ec_group_simple_order_bits,
|
2015-01-22 03:40:55 +00:00
|
|
|
ec_GF2m_simple_group_check_discriminant,
|
|
|
|
ec_GF2m_simple_point_init,
|
|
|
|
ec_GF2m_simple_point_finish,
|
|
|
|
ec_GF2m_simple_point_clear_finish,
|
|
|
|
ec_GF2m_simple_point_copy,
|
|
|
|
ec_GF2m_simple_point_set_to_infinity,
|
|
|
|
0 /* set_Jprojective_coordinates_GFp */ ,
|
|
|
|
0 /* get_Jprojective_coordinates_GFp */ ,
|
|
|
|
ec_GF2m_simple_point_set_affine_coordinates,
|
|
|
|
ec_GF2m_simple_point_get_affine_coordinates,
|
|
|
|
0, 0, 0,
|
|
|
|
ec_GF2m_simple_add,
|
|
|
|
ec_GF2m_simple_dbl,
|
|
|
|
ec_GF2m_simple_invert,
|
|
|
|
ec_GF2m_simple_is_at_infinity,
|
|
|
|
ec_GF2m_simple_is_on_curve,
|
|
|
|
ec_GF2m_simple_cmp,
|
|
|
|
ec_GF2m_simple_make_affine,
|
|
|
|
ec_GF2m_simple_points_make_affine,
|
2018-04-24 13:01:53 +00:00
|
|
|
0 /* mul */,
|
|
|
|
0 /* precompute_mul */,
|
|
|
|
0 /* have_precompute_mul */,
|
2015-01-22 03:40:55 +00:00
|
|
|
ec_GF2m_simple_field_mul,
|
|
|
|
ec_GF2m_simple_field_sqr,
|
|
|
|
ec_GF2m_simple_field_div,
|
|
|
|
0 /* field_encode */ ,
|
|
|
|
0 /* field_decode */ ,
|
2016-02-28 17:48:48 +00:00
|
|
|
0, /* field_set_to_one */
|
|
|
|
ec_key_simple_priv2oct,
|
|
|
|
ec_key_simple_oct2priv,
|
|
|
|
0, /* set private */
|
|
|
|
ec_key_simple_generate_key,
|
|
|
|
ec_key_simple_check_key,
|
|
|
|
ec_key_simple_generate_public_key,
|
|
|
|
0, /* keycopy */
|
|
|
|
0, /* keyfinish */
|
Implement coordinate blinding for EC_POINT
This commit implements coordinate blinding, i.e., it randomizes the
representative of an elliptic curve point in its equivalence class, for
prime curves implemented through EC_GFp_simple_method,
EC_GFp_mont_method, and EC_GFp_nist_method.
This commit is derived from the patch
https://marc.info/?l=openssl-dev&m=131194808413635 by Billy Brumley.
Coordinate blinding is a generally useful side-channel countermeasure
and is (mostly) free. The function itself takes a few field
multiplicationss, but is usually only necessary at the beginning of a
scalar multiplication (as implemented in the patch). When used this way,
it makes the values that variables take (i.e., field elements in an
algorithm state) unpredictable.
For instance, this mitigates chosen EC point side-channel attacks for
settings such as ECDH and EC private key decryption, for the
aforementioned curves.
For EC_METHODs using different coordinate representations this commit
does nothing, but the corresponding coordinate blinding function can be
easily added in the future to extend these changes to such curves.
Co-authored-by: Nicola Tuveri <nic.tuv@gmail.com>
Co-authored-by: Billy Brumley <bbrumley@gmail.com>
Reviewed-by: Andy Polyakov <appro@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6501)
2018-06-16 14:07:40 +00:00
|
|
|
ecdh_simple_compute_key,
|
|
|
|
0, /* field_inverse_mod_ord */
|
EC point multiplication: add `ladder` scaffold
for specialized Montgomery ladder implementations
PR #6009 and #6070 replaced the default EC point multiplication path for
prime and binary curves with a unified Montgomery ladder implementation
with various timing attack defenses (for the common paths when a secret
scalar is feed to the point multiplication).
The newly introduced default implementation directly used
EC_POINT_add/dbl in the main loop.
The scaffolding introduced by this commit allows EC_METHODs to define a
specialized `ladder_step` function to improve performances by taking
advantage of efficient formulas for differential addition-and-doubling
and different coordinate systems.
- `ladder_pre` is executed before the main loop of the ladder: by
default it copies the input point P into S, and doubles it into R.
Specialized implementations could, e.g., use this hook to transition
to different coordinate systems before copying and doubling;
- `ladder_step` is the core of the Montgomery ladder loop: by default it
computes `S := R+S; R := 2R;`, but specific implementations could,
e.g., implement a more efficient formula for differential
addition-and-doubling;
- `ladder_post` is executed after the Montgomery ladder loop: by default
it's a noop, but specialized implementations could, e.g., use this
hook to transition back from the coordinate system used for optimizing
the differential addition-and-doubling or recover the y coordinate of
the result point.
This commit also renames `ec_mul_consttime` to `ec_scalar_mul_ladder`,
as it better corresponds to what this function does: nothing can be
truly said about the constant-timeness of the overall execution of this
function, given that the underlying operations are not necessarily
constant-time themselves.
What this implementation ensures is that the same fixed sequence of
operations is executed for each scalar multiplication (for a given
EC_GROUP), with no dependency on the value of the input scalar.
Co-authored-by: Sohaib ul Hassan <soh.19.hassan@gmail.com>
Co-authored-by: Billy Brumley <bbrumley@gmail.com>
Reviewed-by: Andy Polyakov <appro@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6690)
2018-07-07 21:50:49 +00:00
|
|
|
0, /* blind_coordinates */
|
|
|
|
0, /* ladder_pre */
|
|
|
|
0, /* ladder_step */
|
|
|
|
0 /* ladder_post */
|
2015-01-22 03:40:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
return &ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize a GF(2^m)-based EC_GROUP structure. Note that all other members
|
|
|
|
* are handled by EC_GROUP_new.
|
2002-08-02 13:42:24 +00:00
|
|
|
*/
|
|
|
|
int ec_GF2m_simple_group_init(EC_GROUP *group)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
group->field = BN_new();
|
|
|
|
group->a = BN_new();
|
|
|
|
group->b = BN_new();
|
|
|
|
|
2015-10-30 11:12:26 +00:00
|
|
|
if (group->field == NULL || group->a == NULL || group->b == NULL) {
|
2015-05-01 01:37:06 +00:00
|
|
|
BN_free(group->field);
|
|
|
|
BN_free(group->a);
|
|
|
|
BN_free(group->b);
|
2015-01-22 03:40:55 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free a GF(2^m)-based EC_GROUP structure. Note that all other members are
|
|
|
|
* handled by EC_GROUP_free.
|
2002-08-02 13:42:24 +00:00
|
|
|
*/
|
|
|
|
void ec_GF2m_simple_group_finish(EC_GROUP *group)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
BN_free(group->field);
|
|
|
|
BN_free(group->a);
|
|
|
|
BN_free(group->b);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clear and free a GF(2^m)-based EC_GROUP structure. Note that all other
|
|
|
|
* members are handled by EC_GROUP_clear_free.
|
2002-08-02 13:42:24 +00:00
|
|
|
*/
|
|
|
|
void ec_GF2m_simple_group_clear_finish(EC_GROUP *group)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
BN_clear_free(group->field);
|
|
|
|
BN_clear_free(group->a);
|
|
|
|
BN_clear_free(group->b);
|
|
|
|
group->poly[0] = 0;
|
|
|
|
group->poly[1] = 0;
|
|
|
|
group->poly[2] = 0;
|
|
|
|
group->poly[3] = 0;
|
|
|
|
group->poly[4] = 0;
|
|
|
|
group->poly[5] = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy a GF(2^m)-based EC_GROUP structure. Note that all other members are
|
|
|
|
* handled by EC_GROUP_copy.
|
2002-08-02 13:42:24 +00:00
|
|
|
*/
|
|
|
|
int ec_GF2m_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
if (!BN_copy(dest->field, src->field))
|
|
|
|
return 0;
|
|
|
|
if (!BN_copy(dest->a, src->a))
|
|
|
|
return 0;
|
|
|
|
if (!BN_copy(dest->b, src->b))
|
|
|
|
return 0;
|
|
|
|
dest->poly[0] = src->poly[0];
|
|
|
|
dest->poly[1] = src->poly[1];
|
|
|
|
dest->poly[2] = src->poly[2];
|
|
|
|
dest->poly[3] = src->poly[3];
|
|
|
|
dest->poly[4] = src->poly[4];
|
|
|
|
dest->poly[5] = src->poly[5];
|
|
|
|
if (bn_wexpand(dest->a, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) ==
|
|
|
|
NULL)
|
|
|
|
return 0;
|
|
|
|
if (bn_wexpand(dest->b, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) ==
|
|
|
|
NULL)
|
|
|
|
return 0;
|
|
|
|
bn_set_all_zero(dest->a);
|
|
|
|
bn_set_all_zero(dest->b);
|
|
|
|
return 1;
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
|
|
|
/* Set the curve parameters of an EC_GROUP structure. */
|
2002-08-02 14:28:37 +00:00
|
|
|
int ec_GF2m_simple_group_set_curve(EC_GROUP *group,
|
2015-01-22 03:40:55 +00:00
|
|
|
const BIGNUM *p, const BIGNUM *a,
|
|
|
|
const BIGNUM *b, BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
int ret = 0, i;
|
|
|
|
|
|
|
|
/* group->field */
|
|
|
|
if (!BN_copy(group->field, p))
|
|
|
|
goto err;
|
|
|
|
i = BN_GF2m_poly2arr(group->field, group->poly, 6) - 1;
|
|
|
|
if ((i != 5) && (i != 3)) {
|
|
|
|
ECerr(EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE, EC_R_UNSUPPORTED_FIELD);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* group->a */
|
|
|
|
if (!BN_GF2m_mod_arr(group->a, a, group->poly))
|
|
|
|
goto err;
|
|
|
|
if (bn_wexpand(group->a, (int)(group->poly[0] + BN_BITS2 - 1) / BN_BITS2)
|
|
|
|
== NULL)
|
|
|
|
goto err;
|
|
|
|
bn_set_all_zero(group->a);
|
|
|
|
|
|
|
|
/* group->b */
|
|
|
|
if (!BN_GF2m_mod_arr(group->b, b, group->poly))
|
|
|
|
goto err;
|
|
|
|
if (bn_wexpand(group->b, (int)(group->poly[0] + BN_BITS2 - 1) / BN_BITS2)
|
|
|
|
== NULL)
|
|
|
|
goto err;
|
|
|
|
bn_set_all_zero(group->b);
|
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the curve parameters of an EC_GROUP structure. If p, a, or b are NULL
|
|
|
|
* then there values will not be set but the method will return with success.
|
2002-08-02 13:42:24 +00:00
|
|
|
*/
|
2015-01-22 03:40:55 +00:00
|
|
|
int ec_GF2m_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p,
|
|
|
|
BIGNUM *a, BIGNUM *b, BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (p != NULL) {
|
|
|
|
if (!BN_copy(p, group->field))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a != NULL) {
|
|
|
|
if (!BN_copy(a, group->a))
|
|
|
|
goto err;
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
if (b != NULL) {
|
|
|
|
if (!BN_copy(b, group->b))
|
|
|
|
goto err;
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Gets the degree of the field. For a curve over GF(2^m) this is the value
|
|
|
|
* m.
|
|
|
|
*/
|
|
|
|
int ec_GF2m_simple_group_get_degree(const EC_GROUP *group)
|
|
|
|
{
|
|
|
|
return BN_num_bits(group->field) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Checks the discriminant of the curve. y^2 + x*y = x^3 + a*x^2 + b is an
|
|
|
|
* elliptic curve <=> b != 0 (mod p)
|
2002-08-02 13:42:24 +00:00
|
|
|
*/
|
2015-01-22 03:40:55 +00:00
|
|
|
int ec_GF2m_simple_group_check_discriminant(const EC_GROUP *group,
|
|
|
|
BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
BIGNUM *b;
|
|
|
|
BN_CTX *new_ctx = NULL;
|
|
|
|
|
|
|
|
if (ctx == NULL) {
|
|
|
|
ctx = new_ctx = BN_CTX_new();
|
|
|
|
if (ctx == NULL) {
|
|
|
|
ECerr(EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT,
|
|
|
|
ERR_R_MALLOC_FAILURE);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BN_CTX_start(ctx);
|
|
|
|
b = BN_CTX_get(ctx);
|
|
|
|
if (b == NULL)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (!BN_GF2m_mod_arr(b, group->b, group->poly))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check the discriminant: y^2 + x*y = x^3 + a*x^2 + b is an elliptic
|
|
|
|
* curve <=> b != 0 (mod p)
|
|
|
|
*/
|
|
|
|
if (BN_is_zero(b))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
ret = 1;
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
err:
|
|
|
|
if (ctx != NULL)
|
|
|
|
BN_CTX_end(ctx);
|
2015-05-01 01:37:06 +00:00
|
|
|
BN_CTX_free(new_ctx);
|
2015-01-22 03:40:55 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
|
|
|
/* Initializes an EC_POINT. */
|
|
|
|
int ec_GF2m_simple_point_init(EC_POINT *point)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
point->X = BN_new();
|
|
|
|
point->Y = BN_new();
|
|
|
|
point->Z = BN_new();
|
|
|
|
|
2015-10-30 11:12:26 +00:00
|
|
|
if (point->X == NULL || point->Y == NULL || point->Z == NULL) {
|
2015-05-01 01:37:06 +00:00
|
|
|
BN_free(point->X);
|
|
|
|
BN_free(point->Y);
|
|
|
|
BN_free(point->Z);
|
2015-01-22 03:40:55 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
|
|
|
/* Frees an EC_POINT. */
|
|
|
|
void ec_GF2m_simple_point_finish(EC_POINT *point)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
BN_free(point->X);
|
|
|
|
BN_free(point->Y);
|
|
|
|
BN_free(point->Z);
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
|
|
|
/* Clears and frees an EC_POINT. */
|
|
|
|
void ec_GF2m_simple_point_clear_finish(EC_POINT *point)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
BN_clear_free(point->X);
|
|
|
|
BN_clear_free(point->Y);
|
|
|
|
BN_clear_free(point->Z);
|
|
|
|
point->Z_is_one = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy the contents of one EC_POINT into another. Assumes dest is
|
|
|
|
* initialized.
|
2002-08-02 13:42:24 +00:00
|
|
|
*/
|
2015-01-22 03:40:55 +00:00
|
|
|
int ec_GF2m_simple_point_copy(EC_POINT *dest, const EC_POINT *src)
|
|
|
|
{
|
|
|
|
if (!BN_copy(dest->X, src->X))
|
|
|
|
return 0;
|
|
|
|
if (!BN_copy(dest->Y, src->Y))
|
|
|
|
return 0;
|
|
|
|
if (!BN_copy(dest->Z, src->Z))
|
|
|
|
return 0;
|
|
|
|
dest->Z_is_one = src->Z_is_one;
|
2018-05-21 14:24:56 +00:00
|
|
|
dest->curve_name = src->curve_name;
|
2015-01-22 03:40:55 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set an EC_POINT to the point at infinity. A point at infinity is
|
|
|
|
* represented by having Z=0.
|
2002-08-02 13:42:24 +00:00
|
|
|
*/
|
2015-01-22 03:40:55 +00:00
|
|
|
int ec_GF2m_simple_point_set_to_infinity(const EC_GROUP *group,
|
|
|
|
EC_POINT *point)
|
|
|
|
{
|
|
|
|
point->Z_is_one = 0;
|
|
|
|
BN_zero(point->Z);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the coordinates of an EC_POINT using affine coordinates. Note that
|
|
|
|
* the simple implementation only uses affine coordinates.
|
2002-08-02 13:42:24 +00:00
|
|
|
*/
|
2015-01-22 03:40:55 +00:00
|
|
|
int ec_GF2m_simple_point_set_affine_coordinates(const EC_GROUP *group,
|
|
|
|
EC_POINT *point,
|
|
|
|
const BIGNUM *x,
|
|
|
|
const BIGNUM *y, BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
if (x == NULL || y == NULL) {
|
|
|
|
ECerr(EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES,
|
|
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!BN_copy(point->X, x))
|
|
|
|
goto err;
|
|
|
|
BN_set_negative(point->X, 0);
|
|
|
|
if (!BN_copy(point->Y, y))
|
|
|
|
goto err;
|
|
|
|
BN_set_negative(point->Y, 0);
|
|
|
|
if (!BN_copy(point->Z, BN_value_one()))
|
|
|
|
goto err;
|
|
|
|
BN_set_negative(point->Z, 0);
|
|
|
|
point->Z_is_one = 1;
|
|
|
|
ret = 1;
|
|
|
|
|
2002-08-02 13:42:24 +00:00
|
|
|
err:
|
2015-01-22 03:40:55 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
/*
|
|
|
|
* Gets the affine coordinates of an EC_POINT. Note that the simple
|
|
|
|
* implementation only uses affine coordinates.
|
2002-08-02 13:42:24 +00:00
|
|
|
*/
|
2015-01-22 03:40:55 +00:00
|
|
|
int ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *group,
|
|
|
|
const EC_POINT *point,
|
|
|
|
BIGNUM *x, BIGNUM *y,
|
|
|
|
BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (EC_POINT_is_at_infinity(group, point)) {
|
|
|
|
ECerr(EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES,
|
|
|
|
EC_R_POINT_AT_INFINITY);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (BN_cmp(point->Z, BN_value_one())) {
|
|
|
|
ECerr(EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES,
|
|
|
|
ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (x != NULL) {
|
|
|
|
if (!BN_copy(x, point->X))
|
|
|
|
goto err;
|
|
|
|
BN_set_negative(x, 0);
|
|
|
|
}
|
|
|
|
if (y != NULL) {
|
|
|
|
if (!BN_copy(y, point->Y))
|
|
|
|
goto err;
|
|
|
|
BN_set_negative(y, 0);
|
|
|
|
}
|
|
|
|
ret = 1;
|
2002-08-02 13:42:24 +00:00
|
|
|
|
|
|
|
err:
|
2015-01-22 03:40:55 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
/*
|
|
|
|
* Computes a + b and stores the result in r. r could be a or b, a could be
|
|
|
|
* b. Uses algorithm A.10.2 of IEEE P1363.
|
2002-08-02 13:42:24 +00:00
|
|
|
*/
|
2015-01-22 03:40:55 +00:00
|
|
|
int ec_GF2m_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
|
|
|
|
const EC_POINT *b, BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
BN_CTX *new_ctx = NULL;
|
|
|
|
BIGNUM *x0, *y0, *x1, *y1, *x2, *y2, *s, *t;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (EC_POINT_is_at_infinity(group, a)) {
|
|
|
|
if (!EC_POINT_copy(r, b))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EC_POINT_is_at_infinity(group, b)) {
|
|
|
|
if (!EC_POINT_copy(r, a))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx == NULL) {
|
|
|
|
ctx = new_ctx = BN_CTX_new();
|
|
|
|
if (ctx == NULL)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
BN_CTX_start(ctx);
|
|
|
|
x0 = BN_CTX_get(ctx);
|
|
|
|
y0 = BN_CTX_get(ctx);
|
|
|
|
x1 = BN_CTX_get(ctx);
|
|
|
|
y1 = BN_CTX_get(ctx);
|
|
|
|
x2 = BN_CTX_get(ctx);
|
|
|
|
y2 = BN_CTX_get(ctx);
|
|
|
|
s = BN_CTX_get(ctx);
|
|
|
|
t = BN_CTX_get(ctx);
|
|
|
|
if (t == NULL)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (a->Z_is_one) {
|
|
|
|
if (!BN_copy(x0, a->X))
|
|
|
|
goto err;
|
|
|
|
if (!BN_copy(y0, a->Y))
|
|
|
|
goto err;
|
|
|
|
} else {
|
|
|
|
if (!EC_POINT_get_affine_coordinates_GF2m(group, a, x0, y0, ctx))
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (b->Z_is_one) {
|
|
|
|
if (!BN_copy(x1, b->X))
|
|
|
|
goto err;
|
|
|
|
if (!BN_copy(y1, b->Y))
|
|
|
|
goto err;
|
|
|
|
} else {
|
|
|
|
if (!EC_POINT_get_affine_coordinates_GF2m(group, b, x1, y1, ctx))
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (BN_GF2m_cmp(x0, x1)) {
|
|
|
|
if (!BN_GF2m_add(t, x0, x1))
|
|
|
|
goto err;
|
|
|
|
if (!BN_GF2m_add(s, y0, y1))
|
|
|
|
goto err;
|
|
|
|
if (!group->meth->field_div(group, s, s, t, ctx))
|
|
|
|
goto err;
|
|
|
|
if (!group->meth->field_sqr(group, x2, s, ctx))
|
|
|
|
goto err;
|
|
|
|
if (!BN_GF2m_add(x2, x2, group->a))
|
|
|
|
goto err;
|
|
|
|
if (!BN_GF2m_add(x2, x2, s))
|
|
|
|
goto err;
|
|
|
|
if (!BN_GF2m_add(x2, x2, t))
|
|
|
|
goto err;
|
|
|
|
} else {
|
|
|
|
if (BN_GF2m_cmp(y0, y1) || BN_is_zero(x1)) {
|
|
|
|
if (!EC_POINT_set_to_infinity(group, r))
|
|
|
|
goto err;
|
|
|
|
ret = 1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (!group->meth->field_div(group, s, y1, x1, ctx))
|
|
|
|
goto err;
|
|
|
|
if (!BN_GF2m_add(s, s, x1))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (!group->meth->field_sqr(group, x2, s, ctx))
|
|
|
|
goto err;
|
|
|
|
if (!BN_GF2m_add(x2, x2, s))
|
|
|
|
goto err;
|
|
|
|
if (!BN_GF2m_add(x2, x2, group->a))
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!BN_GF2m_add(y2, x1, x2))
|
|
|
|
goto err;
|
|
|
|
if (!group->meth->field_mul(group, y2, y2, s, ctx))
|
|
|
|
goto err;
|
|
|
|
if (!BN_GF2m_add(y2, y2, x2))
|
|
|
|
goto err;
|
|
|
|
if (!BN_GF2m_add(y2, y2, y1))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (!EC_POINT_set_affine_coordinates_GF2m(group, r, x2, y2, ctx))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
ret = 1;
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
err:
|
|
|
|
BN_CTX_end(ctx);
|
2015-05-01 01:37:06 +00:00
|
|
|
BN_CTX_free(new_ctx);
|
2015-01-22 03:40:55 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Computes 2 * a and stores the result in r. r could be a. Uses algorithm
|
|
|
|
* A.10.2 of IEEE P1363.
|
|
|
|
*/
|
|
|
|
int ec_GF2m_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
|
|
|
|
BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
return ec_GF2m_simple_add(group, r, a, a, ctx);
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
|
|
|
int ec_GF2m_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(point->Y))
|
|
|
|
/* point is its own inverse */
|
|
|
|
return 1;
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
if (!EC_POINT_make_affine(group, point, ctx))
|
|
|
|
return 0;
|
|
|
|
return BN_GF2m_add(point->Y, point->X, point->Y);
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
|
|
|
/* Indicates whether the given point is the point at infinity. */
|
2015-01-22 03:40:55 +00:00
|
|
|
int ec_GF2m_simple_is_at_infinity(const EC_GROUP *group,
|
|
|
|
const EC_POINT *point)
|
|
|
|
{
|
|
|
|
return BN_is_zero(point->Z);
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2015-01-16 14:43:29 +00:00
|
|
|
/*-
|
|
|
|
* Determines whether the given EC_POINT is an actual point on the curve defined
|
2002-08-02 13:42:24 +00:00
|
|
|
* in the EC_GROUP. A point is valid if it satisfies the Weierstrass equation:
|
|
|
|
* y^2 + x*y = x^3 + a*x^2 + b.
|
|
|
|
*/
|
2015-01-22 03:40:55 +00:00
|
|
|
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;
|
|
|
|
|
2015-01-05 11:30:03 +00:00
|
|
|
/*-
|
|
|
|
* 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
|
|
|
|
*/
|
2015-01-22 03:40:55 +00:00
|
|
|
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);
|
2017-12-08 15:49:41 +00:00
|
|
|
|
2002-08-02 13:42:24 +00:00
|
|
|
err:
|
2017-12-08 15:49:41 +00:00
|
|
|
BN_CTX_end(ctx);
|
2015-05-01 01:37:06 +00:00
|
|
|
BN_CTX_free(new_ctx);
|
2015-01-22 03:40:55 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2014-12-28 02:48:40 +00:00
|
|
|
/*-
|
|
|
|
* Indicates whether two points are equal.
|
2002-08-02 13:42:24 +00:00
|
|
|
* Return values:
|
|
|
|
* -1 error
|
|
|
|
* 0 equal (in affine coordinates)
|
|
|
|
* 1 not equal
|
|
|
|
*/
|
2015-01-22 03:40:55 +00:00
|
|
|
int ec_GF2m_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
|
|
|
|
const EC_POINT *b, BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
BIGNUM *aX, *aY, *bX, *bY;
|
|
|
|
BN_CTX *new_ctx = NULL;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx == NULL) {
|
|
|
|
ctx = new_ctx = BN_CTX_new();
|
|
|
|
if (ctx == NULL)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
BN_CTX_start(ctx);
|
|
|
|
aX = BN_CTX_get(ctx);
|
|
|
|
aY = BN_CTX_get(ctx);
|
|
|
|
bX = BN_CTX_get(ctx);
|
|
|
|
bY = BN_CTX_get(ctx);
|
|
|
|
if (bY == NULL)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (!EC_POINT_get_affine_coordinates_GF2m(group, a, aX, aY, ctx))
|
|
|
|
goto err;
|
|
|
|
if (!EC_POINT_get_affine_coordinates_GF2m(group, b, bX, bY, ctx))
|
|
|
|
goto err;
|
|
|
|
ret = ((BN_cmp(aX, bX) == 0) && BN_cmp(aY, bY) == 0) ? 0 : 1;
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
err:
|
2017-12-08 15:49:41 +00:00
|
|
|
BN_CTX_end(ctx);
|
2015-05-01 01:37:06 +00:00
|
|
|
BN_CTX_free(new_ctx);
|
2015-01-22 03:40:55 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
|
|
|
/* Forces the given EC_POINT to internally use affine coordinates. */
|
2015-01-22 03:40:55 +00:00
|
|
|
int ec_GF2m_simple_make_affine(const EC_GROUP *group, EC_POINT *point,
|
|
|
|
BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
BN_CTX *new_ctx = NULL;
|
|
|
|
BIGNUM *x, *y;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (point->Z_is_one || EC_POINT_is_at_infinity(group, point))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (ctx == NULL) {
|
|
|
|
ctx = new_ctx = BN_CTX_new();
|
|
|
|
if (ctx == NULL)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
BN_CTX_start(ctx);
|
|
|
|
x = BN_CTX_get(ctx);
|
|
|
|
y = BN_CTX_get(ctx);
|
|
|
|
if (y == NULL)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (!EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx))
|
|
|
|
goto err;
|
|
|
|
if (!BN_copy(point->X, x))
|
|
|
|
goto err;
|
|
|
|
if (!BN_copy(point->Y, y))
|
|
|
|
goto err;
|
|
|
|
if (!BN_one(point->Z))
|
|
|
|
goto err;
|
2016-01-21 12:06:57 +00:00
|
|
|
point->Z_is_one = 1;
|
2015-01-22 03:40:55 +00:00
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
err:
|
2017-12-08 15:49:41 +00:00
|
|
|
BN_CTX_end(ctx);
|
2015-05-01 01:37:06 +00:00
|
|
|
BN_CTX_free(new_ctx);
|
2015-01-22 03:40:55 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Forces each of the EC_POINTs in the given array to use affine coordinates.
|
|
|
|
*/
|
|
|
|
int ec_GF2m_simple_points_make_affine(const EC_GROUP *group, size_t num,
|
|
|
|
EC_POINT *points[], BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
size_t i;
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
for (i = 0; i < num; i++) {
|
|
|
|
if (!group->meth->make_affine(group, points[i], ctx))
|
|
|
|
return 0;
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
/* Wrapper to simple binary polynomial field multiplication implementation. */
|
|
|
|
int ec_GF2m_simple_field_mul(const EC_GROUP *group, BIGNUM *r,
|
|
|
|
const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
return BN_GF2m_mod_mul_arr(r, a, b, group->poly, ctx);
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
|
|
|
/* Wrapper to simple binary polynomial field squaring implementation. */
|
2015-01-22 03:40:55 +00:00
|
|
|
int ec_GF2m_simple_field_sqr(const EC_GROUP *group, BIGNUM *r,
|
|
|
|
const BIGNUM *a, BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
return BN_GF2m_mod_sqr_arr(r, a, group->poly, ctx);
|
|
|
|
}
|
2002-08-02 13:42:24 +00:00
|
|
|
|
|
|
|
/* Wrapper to simple binary polynomial field division implementation. */
|
2015-01-22 03:40:55 +00:00
|
|
|
int ec_GF2m_simple_field_div(const EC_GROUP *group, BIGNUM *r,
|
|
|
|
const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
|
|
|
|
{
|
|
|
|
return BN_GF2m_mod_div(r, a, b, group->field, ctx);
|
|
|
|
}
|
2011-02-12 17:23:32 +00:00
|
|
|
|
|
|
|
#endif
|