#include <string.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include "bn_internal.h"
#include "crypto_internal.h"
#include "ec_local.h"
#include "ec_internal.h"
#include "err_local.h"
static int
ec_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *ctx)
{
BIGNUM *t;
int ret = 0;
BN_CTX_start(ctx);
if (!bn_copy(group->p, p))
goto err;
if (!bn_copy(group->a, a))
goto err;
if (!bn_copy(group->b, b))
goto err;
BN_set_negative(group->p, 0);
if (!BN_nnmod(group->a, group->a, group->p, ctx))
goto err;
if (!BN_nnmod(group->b, group->b, group->p, ctx))
goto err;
if ((t = BN_CTX_get(ctx)) == NULL)
goto err;
if (!BN_set_word(t, 3))
goto err;
if (!BN_mod_add(t, t, a, group->p, ctx))
goto err;
group->a_is_minus3 = BN_is_zero(t);
if (!ec_field_modulus_from_bn(&group->fm, group->p, ctx))
goto err;
if (!ec_field_element_from_bn(&group->fm, group, &group->fe_a, group->a, ctx))
goto err;
if (!ec_field_element_from_bn(&group->fm, group, &group->fe_b, group->b, ctx))
goto err;
ret = 1;
err:
BN_CTX_end(ctx);
return ret;
}
static int
ec_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
BIGNUM *b, BN_CTX *ctx)
{
if (p != NULL) {
if (!bn_copy(p, group->p))
return 0;
}
if (a != NULL) {
if (!bn_copy(a, group->a))
return 0;
}
if (b != NULL) {
if (!bn_copy(b, group->b))
return 0;
}
return 1;
}
static int
ec_point_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
{
return ec_field_element_is_zero(&group->fm, &point->fe_z);
}
static int
ec_point_set_to_infinity(const EC_GROUP *group, EC_POINT *point)
{
memset(&point->fe_x, 0, sizeof(point->fe_x));
memset(&point->fe_y, 0, sizeof(point->fe_y));
memset(&point->fe_z, 0, sizeof(point->fe_z));
point->fe_y.w[0] = 1;
return 1;
}
static int
ec_point_set_affine_coordinates(const EC_GROUP *group, EC_POINT *point,
const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx)
{
if (x == NULL || y == NULL) {
ECerror(ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (!bn_copy(point->X, x))
return 0;
if (!bn_copy(point->Y, y))
return 0;
if (!BN_one(point->Z))
return 0;
if (!BN_nnmod(point->X, point->X, group->p, ctx))
return 0;
if (!BN_nnmod(point->Y, point->Y, group->p, ctx))
return 0;
if (!ec_field_element_from_bn(&group->fm, group, &point->fe_x, point->X, ctx))
return 0;
if (!ec_field_element_from_bn(&group->fm, group, &point->fe_y, point->Y, ctx))
return 0;
if (!ec_field_element_from_bn(&group->fm, group, &point->fe_z, point->Z, ctx))
return 0;
return 1;
}
static int
ec_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point,
BIGNUM *x, BIGNUM *y, BN_CTX *ctx)
{
BIGNUM *zinv;
int ret = 0;
if (!ec_field_element_to_bn(&group->fm, &point->fe_x, point->X, ctx))
return 0;
if (!ec_field_element_to_bn(&group->fm, &point->fe_y, point->Y, ctx))
return 0;
if (!ec_field_element_to_bn(&group->fm, &point->fe_z, point->Z, ctx))
return 0;
BN_CTX_start(ctx);
if ((zinv = BN_CTX_get(ctx)) == NULL)
goto err;
if (BN_mod_inverse_ct(zinv, point->Z, group->p, ctx) == NULL)
goto err;
if (x != NULL) {
if (!BN_mod_mul(x, point->X, zinv, group->p, ctx))
goto err;
}
if (y != NULL) {
if (!BN_mod_mul(y, point->Y, zinv, group->p, ctx))
goto err;
}
ret = 1;
err:
BN_CTX_end(ctx);
return ret;
}
static int
ec_point_add_a1(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
const EC_POINT *b, BN_CTX *ctx)
{
EC_FIELD_ELEMENT X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3;
EC_FIELD_ELEMENT b3, t0, t1, t2, t3, t4, t5;
EC_FIELD_ELEMENT ga, gb;
ec_field_element_copy(&ga, &group->fe_a);
ec_field_element_copy(&gb, &group->fe_b);
ec_field_element_copy(&X1, &a->fe_x);
ec_field_element_copy(&Y1, &a->fe_y);
ec_field_element_copy(&Z1, &a->fe_z);
ec_field_element_copy(&X2, &b->fe_x);
ec_field_element_copy(&Y2, &b->fe_y);
ec_field_element_copy(&Z2, &b->fe_z);
ec_field_element_add(&group->fm, &b3, &gb, &gb);
ec_field_element_add(&group->fm, &b3, &b3, &gb);
ec_field_element_mul(&group->fm, &t0, &X1, &X2);
ec_field_element_mul(&group->fm, &t1, &Y1, &Y2);
ec_field_element_mul(&group->fm, &t2, &Z1, &Z2);
ec_field_element_add(&group->fm, &t3, &X1, &Y1);
ec_field_element_add(&group->fm, &t4, &X2, &Y2);
ec_field_element_mul(&group->fm, &t3, &t3, &t4);
ec_field_element_add(&group->fm, &t4, &t0, &t1);
ec_field_element_sub(&group->fm, &t3, &t3, &t4);
ec_field_element_add(&group->fm, &t4, &X1, &Z1);
ec_field_element_add(&group->fm, &t5, &X2, &Z2);
ec_field_element_mul(&group->fm, &t4, &t4, &t5);
ec_field_element_add(&group->fm, &t5, &t0, &t2);
ec_field_element_sub(&group->fm, &t4, &t4, &t5);
ec_field_element_add(&group->fm, &t5, &Y1, &Z1);
ec_field_element_add(&group->fm, &X3, &Y2, &Z2);
ec_field_element_mul(&group->fm, &t5, &t5, &X3);
ec_field_element_add(&group->fm, &X3, &t1, &t2);
ec_field_element_sub(&group->fm, &t5, &t5, &X3);
ec_field_element_mul(&group->fm, &Z3, &ga, &t4);
ec_field_element_mul(&group->fm, &X3, &b3, &t2);
ec_field_element_add(&group->fm, &Z3, &X3, &Z3);
ec_field_element_sub(&group->fm, &X3, &t1, &Z3);
ec_field_element_add(&group->fm, &Z3, &t1, &Z3);
ec_field_element_mul(&group->fm, &Y3, &X3, &Z3);
ec_field_element_add(&group->fm, &t1, &t0, &t0);
ec_field_element_add(&group->fm, &t1, &t1, &t0);
ec_field_element_mul(&group->fm, &t2, &ga, &t2);
ec_field_element_mul(&group->fm, &t4, &b3, &t4);
ec_field_element_add(&group->fm, &t1, &t1, &t2);
ec_field_element_sub(&group->fm, &t2, &t0, &t2);
ec_field_element_mul(&group->fm, &t2, &ga, &t2);
ec_field_element_add(&group->fm, &t4, &t4, &t2);
ec_field_element_mul(&group->fm, &t0, &t1, &t4);
ec_field_element_add(&group->fm, &Y3, &Y3, &t0);
ec_field_element_mul(&group->fm, &t0, &t5, &t4);
ec_field_element_mul(&group->fm, &X3, &t3, &X3);
ec_field_element_sub(&group->fm, &X3, &X3, &t0);
ec_field_element_mul(&group->fm, &t0, &t3, &t1);
ec_field_element_mul(&group->fm, &Z3, &t5, &Z3);
ec_field_element_add(&group->fm, &Z3, &Z3, &t0);
ec_field_element_copy(&r->fe_x, &X3);
ec_field_element_copy(&r->fe_y, &Y3);
ec_field_element_copy(&r->fe_z, &Z3);
return 1;
}
static int
ec_point_add_a2(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
const EC_POINT *b, BN_CTX *ctx)
{
EC_FIELD_ELEMENT X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3;
EC_FIELD_ELEMENT t0, t1, t2, t3, t4;
EC_FIELD_ELEMENT gb;
ec_field_element_copy(&gb, &group->fe_b);
ec_field_element_copy(&X1, &a->fe_x);
ec_field_element_copy(&Y1, &a->fe_y);
ec_field_element_copy(&Z1, &a->fe_z);
ec_field_element_copy(&X2, &b->fe_x);
ec_field_element_copy(&Y2, &b->fe_y);
ec_field_element_copy(&Z2, &b->fe_z);
ec_field_element_mul(&group->fm, &t0, &X1, &X2);
ec_field_element_mul(&group->fm, &t1, &Y1, &Y2);
ec_field_element_mul(&group->fm, &t2, &Z1, &Z2);
ec_field_element_add(&group->fm, &t3, &X1, &Y1);
ec_field_element_add(&group->fm, &t4, &X2, &Y2);
ec_field_element_mul(&group->fm, &t3, &t3, &t4);
ec_field_element_add(&group->fm, &t4, &t0, &t1);
ec_field_element_sub(&group->fm, &t3, &t3, &t4);
ec_field_element_add(&group->fm, &t4, &Y1, &Z1);
ec_field_element_add(&group->fm, &X3, &Y2, &Z2);
ec_field_element_mul(&group->fm, &t4, &t4, &X3);
ec_field_element_add(&group->fm, &X3, &t1, &t2);
ec_field_element_sub(&group->fm, &t4, &t4, &X3);
ec_field_element_add(&group->fm, &X3, &X1, &Z1);
ec_field_element_add(&group->fm, &Y3, &X2, &Z2);
ec_field_element_mul(&group->fm, &X3, &X3, &Y3);
ec_field_element_add(&group->fm, &Y3, &t0, &t2);
ec_field_element_sub(&group->fm, &Y3, &X3, &Y3);
ec_field_element_mul(&group->fm, &Z3, &gb, &t2);
ec_field_element_sub(&group->fm, &X3, &Y3, &Z3);
ec_field_element_add(&group->fm, &Z3, &X3, &X3);
ec_field_element_add(&group->fm, &X3, &X3, &Z3);
ec_field_element_sub(&group->fm, &Z3, &t1, &X3);
ec_field_element_add(&group->fm, &X3, &t1, &X3);
ec_field_element_mul(&group->fm, &Y3, &gb, &Y3);
ec_field_element_add(&group->fm, &t1, &t2, &t2);
ec_field_element_add(&group->fm, &t2, &t1, &t2);
ec_field_element_sub(&group->fm, &Y3, &Y3, &t2);
ec_field_element_sub(&group->fm, &Y3, &Y3, &t0);
ec_field_element_add(&group->fm, &t1, &Y3, &Y3);
ec_field_element_add(&group->fm, &Y3, &t1, &Y3);
ec_field_element_add(&group->fm, &t1, &t0, &t0);
ec_field_element_add(&group->fm, &t0, &t1, &t0);
ec_field_element_sub(&group->fm, &t0, &t0, &t2);
ec_field_element_mul(&group->fm, &t1, &t4, &Y3);
ec_field_element_mul(&group->fm, &t2, &t0, &Y3);
ec_field_element_mul(&group->fm, &Y3, &X3, &Z3);
ec_field_element_add(&group->fm, &Y3, &Y3, &t2);
ec_field_element_mul(&group->fm, &X3, &t3, &X3);
ec_field_element_sub(&group->fm, &X3, &X3, &t1);
ec_field_element_mul(&group->fm, &Z3, &t4, &Z3);
ec_field_element_mul(&group->fm, &t1, &t3, &t0);
ec_field_element_add(&group->fm, &Z3, &Z3, &t1);
ec_field_element_copy(&r->fe_x, &X3);
ec_field_element_copy(&r->fe_y, &Y3);
ec_field_element_copy(&r->fe_z, &Z3);
return 1;
}
static int
ec_point_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
const EC_POINT *b, BN_CTX *ctx)
{
if (group->a_is_minus3)
return ec_point_add_a2(group, r, a, b, ctx);
return ec_point_add_a1(group, r, a, b, ctx);
}
static int
ec_point_dbl_a1(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx)
{
EC_FIELD_ELEMENT X1, Y1, Z1, X3, Y3, Z3;
EC_FIELD_ELEMENT b3, t0, t1, t2, t3;
EC_FIELD_ELEMENT ga, gb;
ec_field_element_copy(&ga, &group->fe_a);
ec_field_element_copy(&gb, &group->fe_b);
ec_field_element_copy(&X1, &a->fe_x);
ec_field_element_copy(&Y1, &a->fe_y);
ec_field_element_copy(&Z1, &a->fe_z);
ec_field_element_add(&group->fm, &b3, &gb, &gb);
ec_field_element_add(&group->fm, &b3, &b3, &gb);
ec_field_element_sqr(&group->fm, &t0, &X1);
ec_field_element_sqr(&group->fm, &t1, &Y1);
ec_field_element_sqr(&group->fm, &t2, &Z1);
ec_field_element_mul(&group->fm, &t3, &X1, &Y1);
ec_field_element_add(&group->fm, &t3, &t3, &t3);
ec_field_element_mul(&group->fm, &Z3, &X1, &Z1);
ec_field_element_add(&group->fm, &Z3, &Z3, &Z3);
ec_field_element_mul(&group->fm, &X3, &ga, &Z3);
ec_field_element_mul(&group->fm, &Y3, &b3, &t2);
ec_field_element_add(&group->fm, &Y3, &X3, &Y3);
ec_field_element_sub(&group->fm, &X3, &t1, &Y3);
ec_field_element_add(&group->fm, &Y3, &t1, &Y3);
ec_field_element_mul(&group->fm, &Y3, &X3, &Y3);
ec_field_element_mul(&group->fm, &X3, &t3, &X3);
ec_field_element_mul(&group->fm, &Z3, &b3, &Z3);
ec_field_element_mul(&group->fm, &t2, &ga, &t2);
ec_field_element_sub(&group->fm, &t3, &t0, &t2);
ec_field_element_mul(&group->fm, &t3, &ga, &t3);
ec_field_element_add(&group->fm, &t3, &t3, &Z3);
ec_field_element_add(&group->fm, &Z3, &t0, &t0);
ec_field_element_add(&group->fm, &t0, &Z3, &t0);
ec_field_element_add(&group->fm, &t0, &t0, &t2);
ec_field_element_mul(&group->fm, &t0, &t0, &t3);
ec_field_element_add(&group->fm, &Y3, &Y3, &t0);
ec_field_element_mul(&group->fm, &t2, &Y1, &Z1);
ec_field_element_add(&group->fm, &t2, &t2, &t2);
ec_field_element_mul(&group->fm, &t0, &t2, &t3);
ec_field_element_sub(&group->fm, &X3, &X3, &t0);
ec_field_element_mul(&group->fm, &Z3, &t2, &t1);
ec_field_element_add(&group->fm, &Z3, &Z3, &Z3);
ec_field_element_add(&group->fm, &Z3, &Z3, &Z3);
ec_field_element_copy(&r->fe_x, &X3);
ec_field_element_copy(&r->fe_y, &Y3);
ec_field_element_copy(&r->fe_z, &Z3);
return 1;
}
static int
ec_point_dbl_a2(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx)
{
EC_FIELD_ELEMENT X1, Y1, Z1, X3, Y3, Z3;
EC_FIELD_ELEMENT t0, t1, t2, t3;
EC_FIELD_ELEMENT ga, gb;
ec_field_element_copy(&ga, &group->fe_a);
ec_field_element_copy(&gb, &group->fe_b);
ec_field_element_copy(&X1, &a->fe_x);
ec_field_element_copy(&Y1, &a->fe_y);
ec_field_element_copy(&Z1, &a->fe_z);
ec_field_element_sqr(&group->fm, &t0, &X1);
ec_field_element_sqr(&group->fm, &t1, &Y1);
ec_field_element_sqr(&group->fm, &t2, &Z1);
ec_field_element_mul(&group->fm, &t3, &X1, &Y1);
ec_field_element_add(&group->fm, &t3, &t3, &t3);
ec_field_element_mul(&group->fm, &Z3, &X1, &Z1);
ec_field_element_add(&group->fm, &Z3, &Z3, &Z3);
ec_field_element_mul(&group->fm, &Y3, &gb, &t2);
ec_field_element_sub(&group->fm, &Y3, &Y3, &Z3);
ec_field_element_add(&group->fm, &X3, &Y3, &Y3);
ec_field_element_add(&group->fm, &Y3, &X3, &Y3);
ec_field_element_sub(&group->fm, &X3, &t1, &Y3);
ec_field_element_add(&group->fm, &Y3, &t1, &Y3);
ec_field_element_mul(&group->fm, &Y3, &X3, &Y3);
ec_field_element_mul(&group->fm, &X3, &X3, &t3);
ec_field_element_add(&group->fm, &t3, &t2, &t2);
ec_field_element_add(&group->fm, &t2, &t2, &t3);
ec_field_element_mul(&group->fm, &Z3, &gb, &Z3);
ec_field_element_sub(&group->fm, &Z3, &Z3, &t2);
ec_field_element_sub(&group->fm, &Z3, &Z3, &t0);
ec_field_element_add(&group->fm, &t3, &Z3, &Z3);
ec_field_element_add(&group->fm, &Z3, &Z3, &t3);
ec_field_element_add(&group->fm, &t3, &t0, &t0);
ec_field_element_add(&group->fm, &t0, &t3, &t0);
ec_field_element_sub(&group->fm, &t0, &t0, &t2);
ec_field_element_mul(&group->fm, &t0, &t0, &Z3);
ec_field_element_add(&group->fm, &Y3, &Y3, &t0);
ec_field_element_mul(&group->fm, &t0, &Y1, &Z1);
ec_field_element_add(&group->fm, &t0, &t0, &t0);
ec_field_element_mul(&group->fm, &Z3, &t0, &Z3);
ec_field_element_sub(&group->fm, &X3, &X3, &Z3);
ec_field_element_mul(&group->fm, &Z3, &t0, &t1);
ec_field_element_add(&group->fm, &Z3, &Z3, &Z3);
ec_field_element_add(&group->fm, &Z3, &Z3, &Z3);
ec_field_element_copy(&r->fe_x, &X3);
ec_field_element_copy(&r->fe_y, &Y3);
ec_field_element_copy(&r->fe_z, &Z3);
return 1;
}
static int
ec_point_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx)
{
if (group->a_is_minus3)
return ec_point_dbl_a2(group, r, a, ctx);
return ec_point_dbl_a1(group, r, a, ctx);
}
static int
ec_point_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
{
EC_FIELD_ELEMENT y;
BN_ULONG mask;
int i;
mask = ~(0 - (ec_point_is_at_infinity(group, point) |
ec_field_element_is_zero(&group->fm, &point->fe_y)));
ec_field_element_sub(&group->fm, &y, &group->fm.m, &point->fe_y);
for (i = 0; i < group->fm.n; i++)
point->fe_y.w[i] = (point->fe_y.w[i] & ~mask) | (y.w[i] & mask);
return 1;
}
static int
ec_point_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx)
{
EC_FIELD_ELEMENT sum, axz2, bz3, x3, y2z, z2;
ec_field_element_sqr(&group->fm, &z2, &point->fe_z);
ec_field_element_sqr(&group->fm, &y2z, &point->fe_y);
ec_field_element_mul(&group->fm, &y2z, &y2z, &point->fe_z);
ec_field_element_sqr(&group->fm, &x3, &point->fe_x);
ec_field_element_mul(&group->fm, &x3, &x3, &point->fe_x);
ec_field_element_mul(&group->fm, &axz2, &group->fe_a, &point->fe_x);
ec_field_element_mul(&group->fm, &axz2, &axz2, &z2);
ec_field_element_mul(&group->fm, &bz3, &group->fe_b, &point->fe_z);
ec_field_element_mul(&group->fm, &bz3, &bz3, &z2);
ec_field_element_add(&group->fm, &sum, &x3, &axz2);
ec_field_element_add(&group->fm, &sum, &sum, &bz3);
return ec_field_element_equal(&group->fm, &y2z, &sum) |
ec_point_is_at_infinity(group, point);
}
static int
ec_point_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx)
{
EC_FIELD_ELEMENT ax, ay, bx, by;
ec_field_element_mul(&group->fm, &ax, &a->fe_x, &b->fe_z);
ec_field_element_mul(&group->fm, &ay, &a->fe_y, &b->fe_z);
ec_field_element_mul(&group->fm, &bx, &b->fe_x, &a->fe_z);
ec_field_element_mul(&group->fm, &by, &b->fe_y, &a->fe_z);
return 1 - (ec_field_element_equal(&group->fm, &ax, &bx) &
ec_field_element_equal(&group->fm, &ay, &by));
}
#if 0
static int
ec_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[],
BN_CTX *ctx)
{
size_t i;
for (i = 0; i < num; i++) {
if (!EC_POINT_make_affine(group, points[0], ctx))
return 0;
}
return 1;
}
#else
static int
ec_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[],
BN_CTX *ctx)
{
BIGNUM **prod_Z = NULL;
BIGNUM *tmp, *tmp_Z;
size_t i;
int ret = 0;
if (num == 0)
return 1;
BN_CTX_start(ctx);
if ((tmp = BN_CTX_get(ctx)) == NULL)
goto err;
if ((tmp_Z = BN_CTX_get(ctx)) == NULL)
goto err;
if ((prod_Z = calloc(num, sizeof *prod_Z)) == NULL)
goto err;
for (i = 0; i < num; i++) {
if ((prod_Z[i] = BN_CTX_get(ctx)) == NULL)
goto err;
}
if (!BN_is_zero(points[0]->Z)) {
if (!bn_copy(prod_Z[0], points[0]->Z))
goto err;
} else {
if (!BN_one(prod_Z[0]))
goto err;
}
for (i = 1; i < num; i++) {
if (!BN_is_zero(points[i]->Z)) {
if (!BN_mod_mul(prod_Z[i], prod_Z[i - 1], points[i]->Z,
group->p, ctx))
goto err;
} else {
if (!bn_copy(prod_Z[i], prod_Z[i - 1]))
goto err;
}
}
if (!BN_mod_inverse_nonct(tmp, prod_Z[num - 1], group->p, ctx)) {
ECerror(ERR_R_BN_LIB);
goto err;
}
for (i = num - 1; i > 0; i--) {
if (BN_is_zero(points[i]->Z))
continue;
if (!BN_mod_mul(tmp_Z, prod_Z[i - 1], tmp, group->p, ctx))
goto err;
if (!BN_mod_mul(tmp, tmp, points[i]->Z, group->p, ctx))
goto err;
if (!bn_copy(points[i]->Z, tmp_Z))
goto err;
}
for (i = 0; i < num; i++) {
EC_POINT *p = points[i];
if (BN_is_zero(p->Z))
continue;
if (!BN_mod_mul(p->X, p->X, p->Z, group->p, ctx))
goto err;
if (!BN_mod_mul(p->Y, p->Y, p->Z, group->p, ctx))
goto err;
if (!BN_one(p->Z))
goto err;
}
ret = 1;
err:
BN_CTX_end(ctx);
free(prod_Z);
return ret;
}
#endif
static void
ec_point_select(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
const EC_POINT *b, int conditional)
{
ec_field_element_select(&group->fm, &r->fe_x, &a->fe_x, &b->fe_x, conditional);
ec_field_element_select(&group->fm, &r->fe_y, &a->fe_y, &b->fe_y, conditional);
ec_field_element_select(&group->fm, &r->fe_z, &a->fe_z, &b->fe_z, conditional);
}
static int
ec_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, const EC_POINT *point,
BN_CTX *ctx)
{
BIGNUM *cardinality;
EC_POINT *multiples[15];
EC_POINT *rr = NULL, *t = NULL;
uint8_t *scalar_bytes = NULL;
int scalar_len = 0;
uint8_t j, wv;
int conditional, i;
int ret = 0;
memset(multiples, 0, sizeof(multiples));
BN_CTX_start(ctx);
if ((cardinality = BN_CTX_get(ctx)) == NULL)
goto err;
if (!BN_mul(cardinality, group->order, group->cofactor, ctx))
goto err;
scalar_len = BN_num_bytes(cardinality);
if ((scalar_bytes = calloc(1, scalar_len)) == NULL)
goto err;
if (!BN_bn2binpad(scalar, scalar_bytes, scalar_len))
goto err;
if ((multiples[0] = EC_POINT_dup(point, group)) == NULL)
goto err;
for (i = 1; i < 15; i += 2) {
if ((multiples[i] = EC_POINT_new(group)) == NULL)
goto err;
if (!EC_POINT_dbl(group, multiples[i], multiples[i / 2], ctx))
goto err;
if ((multiples[i + 1] = EC_POINT_new(group)) == NULL)
goto err;
if (!EC_POINT_add(group, multiples[i + 1], multiples[i], point, ctx))
goto err;
}
if ((rr = EC_POINT_new(group)) == NULL)
goto err;
if ((t = EC_POINT_new(group)) == NULL)
goto err;
if (!EC_POINT_set_to_infinity(group, rr))
goto err;
for (i = 0; i < scalar_len; i++) {
if (i != 0) {
if (!EC_POINT_dbl(group, rr, rr, ctx))
goto err;
if (!EC_POINT_dbl(group, rr, rr, ctx))
goto err;
if (!EC_POINT_dbl(group, rr, rr, ctx))
goto err;
if (!EC_POINT_dbl(group, rr, rr, ctx))
goto err;
}
if (!EC_POINT_set_to_infinity(group, t))
goto err;
wv = scalar_bytes[i] >> 4;
for (j = 1; j < 16; j++) {
conditional = crypto_ct_eq_u8(j, wv);
ec_point_select(group, t, t, multiples[j - 1], conditional);
}
if (!EC_POINT_add(group, rr, rr, t, ctx))
goto err;
if (!EC_POINT_dbl(group, rr, rr, ctx))
goto err;
if (!EC_POINT_dbl(group, rr, rr, ctx))
goto err;
if (!EC_POINT_dbl(group, rr, rr, ctx))
goto err;
if (!EC_POINT_dbl(group, rr, rr, ctx))
goto err;
if (!EC_POINT_set_to_infinity(group, t))
goto err;
wv = scalar_bytes[i] & 0xf;
for (j = 1; j < 16; j++) {
conditional = crypto_ct_eq_u8(j, wv);
ec_point_select(group, t, t, multiples[j - 1], conditional);
}
if (!EC_POINT_add(group, rr, rr, t, ctx))
goto err;
}
if (!EC_POINT_copy(r, rr))
goto err;
ret = 1;
err:
for (i = 0; i < 15; i++)
EC_POINT_free(multiples[i]);
EC_POINT_free(rr);
EC_POINT_free(t);
freezero(scalar_bytes, scalar_len);
BN_CTX_end(ctx);
return ret;
}
static int
ec_mul_single_ct(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
const EC_POINT *point, BN_CTX *ctx)
{
return ec_mul(group, r, scalar, point, ctx);
}
static int
ec_mul_double_nonct(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar1,
const EC_POINT *point1, const BIGNUM *scalar2, const EC_POINT *point2,
BN_CTX *ctx)
{
return ec_wnaf_mul(group, r, scalar1, point1, scalar2, point2, ctx);
}
static const EC_METHOD ec_GFp_homogeneous_projective_method = {
.group_set_curve = ec_group_set_curve,
.group_get_curve = ec_group_get_curve,
.point_set_to_infinity = ec_point_set_to_infinity,
.point_is_at_infinity = ec_point_is_at_infinity,
.point_set_affine_coordinates = ec_point_set_affine_coordinates,
.point_get_affine_coordinates = ec_point_get_affine_coordinates,
.add = ec_point_add,
.dbl = ec_point_dbl,
.invert = ec_point_invert,
.point_is_on_curve = ec_point_is_on_curve,
.point_cmp = ec_point_cmp,
.points_make_affine = ec_points_make_affine,
.mul_single_ct = ec_mul_single_ct,
.mul_double_nonct = ec_mul_double_nonct,
};
const EC_METHOD *
EC_GFp_homogeneous_projective_method(void)
{
return &ec_GFp_homogeneous_projective_method;
}