Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement blinding for scalar multiplication #11361

Closed
1 change: 1 addition & 0 deletions crypto/ec/ec.h
Expand Up @@ -1182,6 +1182,7 @@ void ERR_load_EC_strings(void);
# define EC_F_EC_KEY_PRINT 180
# define EC_F_EC_KEY_PRINT_FP 181
# define EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES 229
# define EC_F_EC_MUL_CONSTTIME 246
# define EC_F_EC_POINTS_MAKE_AFFINE 136
# define EC_F_EC_POINT_ADD 112
# define EC_F_EC_POINT_CMP 113
Expand Down
34 changes: 30 additions & 4 deletions crypto/ec/ec2_mult.c
Expand Up @@ -315,6 +315,34 @@ static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group,
if (!BN_GF2m_add(x2, x2, &group->b))
goto err; /* x2 = x^4 + b */

/* blinding: make sure z1 and z2 are independently blinded. */
do {
if (!BN_rand(z1, BN_num_bits(&group->field), 0, 0)) {
ECerr(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY, ERR_R_BN_LIB);
return 0;
}
} while (BN_is_zero(z1));

/* first blind (x2,z2) using z1 as the random field element. */
if ((group->meth->field_encode != NULL
&& !group->meth->field_encode(group, z1, z1, ctx))
|| !group->meth->field_mul(group, x2, x2, z1, ctx)
|| !group->meth->field_mul(group, z2, z2, z1, ctx))
return 0;

/* now generate another random field element to blind (x1,z1) */
do {
if (!BN_rand(z1, BN_num_bits(&group->field), 0, 0)) {
Copy link
Contributor

@bbbrumley bbbrumley Apr 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is correct. E.g. for B-233 the field polynomial will have 234 bits while field elements have 233 bits. I think it's

BN_rand(z1, BN_num_bits(&group->field) - 1, -1, 0))

where I think the top=-1 allows the top bit to be random and not fixed.

Can you verify in the debugger?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhm, good point, let me check!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW this is what we're doing in 111 and master

/* s blinding: make sure lambda (s->Z here) is not zero */
do {
if (!BN_priv_rand_ex(s->Z, BN_num_bits(group->field) - 1,
BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY, ctx)) {
ECerr(EC_F_EC_GF2M_SIMPLE_LADDER_PRE, ERR_R_BN_LIB);
return 0;
}
} while (BN_is_zero(s->Z));

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BN_num_bits(group->field) - 1 makes total sense. We wanted to fix the top bit to guarantee that z1 and z2 had exactly the same length, but this is indeed not necessary anymore. I can commit and push both fixes shortly.

ECerr(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY, ERR_R_BN_LIB);
return 0;
}
} while (BN_is_zero(z1));

if ((group->meth->field_encode != NULL
&& !group->meth->field_encode(group, z1, z1, ctx))
|| !group->meth->field_mul(group, x1, x1, z1, ctx))
return 0;

/* find top most bit and go one past it */
i = scalar->top - 1;
mask = BN_TBIT;
Expand Down Expand Up @@ -393,11 +421,9 @@ int ec_GF2m_simple_mul(const EC_GROUP *group, EC_POINT *r,
/*
* This implementation is more efficient than the wNAF implementation for
* 2 or fewer points. Use the ec_wNAF_mul implementation for 3 or more
* points, or if we can perform a fast multiplication based on
* precomputation.
* points.
*/
if ((scalar && (num > 1)) || (num > 2)
|| (num == 0 && EC_GROUP_have_precompute_mult(group))) {
if ((scalar && (num > 1)) || (num > 2)) {
ret = ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx);
goto err;
}
Expand Down
3 changes: 2 additions & 1 deletion crypto/ec/ec_err.c
@@ -1,6 +1,6 @@
/* crypto/ec/ec_err.c */
/* ====================================================================
* Copyright (c) 1999-2019 The OpenSSL Project. All rights reserved.
* Copyright (c) 1999-2020 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -205,6 +205,7 @@ static ERR_STRING_DATA EC_str_functs[] = {
{ERR_FUNC(EC_F_EC_KEY_PRINT_FP), "EC_KEY_print_fp"},
{ERR_FUNC(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES),
"EC_KEY_set_public_key_affine_coordinates"},
{ERR_FUNC(EC_F_EC_MUL_CONSTTIME), "EC_MUL_CONSTTIME"},
{ERR_FUNC(EC_F_EC_POINTS_MAKE_AFFINE), "EC_POINTs_make_affine"},
{ERR_FUNC(EC_F_EC_POINT_ADD), "EC_POINT_add"},
{ERR_FUNC(EC_F_EC_POINT_CMP), "EC_POINT_cmp"},
Expand Down
77 changes: 74 additions & 3 deletions crypto/ec/ec_mult.c
Expand Up @@ -421,9 +421,80 @@ static int ec_mul_consttime(const EC_GROUP *group, EC_POINT *r,
|| (bn_wexpand(&r->Z, group_top) == NULL))
goto err;

/* top bit is a 1, in a fixed pos */
if (!EC_POINT_copy(r, s))
goto err;
if (group->meth->field_type == NID_X9_62_prime_field) {
/*
* Apply blinding independently to r and s: use point r as temporary
* variable.
*
* Blinding requires using a projective representation, and later we
* implement the ladder step using EC_POINT_add() and EC_POINT_dbl():
* this requires EC_METHODs that support projective coordinates in their
* point addition and point doubling implementations.
*
* All the built-in EC_METHODs for prime curves at the moment satisfy
* this condition, while the EC_METHOD for binary curves does not.
*
* This is why we check for a prime field to apply blinding.
*/

/* first randomize r->Z to blind s. */
do {
if (!BN_rand(&r->Z, BN_num_bits(&group->field), 0, 0)) {
Copy link
Contributor

@bbbrumley bbbrumley Apr 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: sorry wrong place in the code for that comment :\

Here you want

BN_rand_range(&r->Z, &group->field);

ECerr(EC_F_EC_MUL_CONSTTIME, ERR_R_BN_LIB);
goto err;
}
} while (BN_is_zero(&r->Z));

/* convert r->Z to the correct field representation. */
if (group->meth->field_encode != NULL
&& !group->meth->field_encode(group, &r->Z, &r->Z, ctx)) {
goto err;
}

/* scale s->X and s->Y by r->Z^2 and r->Z^3, respectively. */
if (!group->meth->field_sqr(group, &r->X, &r->Z, ctx)
|| !group->meth->field_mul(group, &r->Y, &r->X, &r->Z, ctx)) {
goto err;
}
if (!group->meth->field_mul(group, &s->X, &s->X, &r->X, ctx)
|| !group->meth->field_mul(group, &s->Y, &s->Y, &r->Y, ctx)
|| !group->meth->field_mul(group, &s->Z, &s->Z, &r->Z, ctx)) {
goto err;
}
/* mark the flag in s to full projective coordinates. */
s->Z_is_one = 0;

/* blinding: now rerandomize r->Z to make r a blinded copy of s. */
do {
if (!BN_rand(&r->Z, BN_num_bits(&group->field), 0, 0)) {
ECerr(EC_F_EC_MUL_CONSTTIME, ERR_R_BN_LIB);
goto err;
}
} while (BN_is_zero(&r->Z));

/* convert r->Z to the correct field representation. */
if (group->meth->field_encode != NULL
&& !group->meth->field_encode(group, &r->Z, &r->Z, ctx)) {
goto err;
}

/* scale r->X and r->Y by r->Z^2 and r->Z^3, respectively. */
if (!group->meth->field_sqr(group, &r->X, &r->Z, ctx)
|| !group->meth->field_mul(group, &r->Y, &r->X, &r->Z, ctx)) {
goto err;
}
if (!group->meth->field_mul(group, &r->X, &s->X, &r->X, ctx)
|| !group->meth->field_mul(group, &r->Y, &s->Y, &r->Y, ctx)
|| !group->meth->field_mul(group, &r->Z, &s->Z, &r->Z, ctx)) {
goto err;
}
/* mark the flag in s to full projective coordinates. */
r->Z_is_one = 0;
} else {
/* top bit is a 1, in a fixed pos; binary curves are not blinded here */
if (!EC_POINT_copy(r, s))
goto err;
}

EC_POINT_BN_set_flags(r, BN_FLG_CONSTTIME);

Expand Down