mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-11 20:32:35 -03:00
Merge pull request #190
d227579
Add scalar blinding and a secp256k1_context_randomize() call. (Gregory Maxwell)
This commit is contained in:
commit
61c1b1ed46
7 changed files with 209 additions and 3 deletions
|
@ -328,6 +328,18 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
|
|||
const unsigned char *tweak
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Updates the context randomization.
|
||||
* Returns: 1: randomization successfully updated
|
||||
* 0: error
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* seed32: pointer to a 32-byte random seed (NULL resets to initial state)
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
|
||||
secp256k1_context_t* ctx,
|
||||
const unsigned char *seed32
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
|
|
@ -24,6 +24,8 @@ typedef struct {
|
|||
* the intermediate sums while computing a*G.
|
||||
*/
|
||||
secp256k1_ge_storage_t (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */
|
||||
secp256k1_scalar_t blind;
|
||||
secp256k1_gej_t initial;
|
||||
} secp256k1_ecmult_gen_context_t;
|
||||
|
||||
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t* ctx);
|
||||
|
@ -36,4 +38,6 @@ static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_cont
|
|||
/** Multiply with the generator: R = a*G */
|
||||
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t* ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *a);
|
||||
|
||||
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
@ -10,6 +10,7 @@
|
|||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "hash_impl.h"
|
||||
|
||||
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t *ctx) {
|
||||
ctx->prec = NULL;
|
||||
|
@ -74,6 +75,7 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *c
|
|||
secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]);
|
||||
}
|
||||
}
|
||||
secp256k1_ecmult_gen_blind(ctx, NULL);
|
||||
}
|
||||
|
||||
static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx) {
|
||||
|
@ -87,24 +89,31 @@ static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *d
|
|||
} else {
|
||||
dst->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*dst->prec));
|
||||
memcpy(dst->prec, src->prec, sizeof(*dst->prec));
|
||||
dst->initial = src->initial;
|
||||
dst->blind = src->blind;
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t *ctx) {
|
||||
free(ctx->prec);
|
||||
secp256k1_scalar_clear(&ctx->blind);
|
||||
secp256k1_gej_clear(&ctx->initial);
|
||||
ctx->prec = NULL;
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *gn) {
|
||||
secp256k1_ge_t add;
|
||||
secp256k1_ge_storage_t adds;
|
||||
secp256k1_scalar_t gnb;
|
||||
int bits;
|
||||
int i, j;
|
||||
memset(&adds, 0, sizeof(adds));
|
||||
secp256k1_gej_set_infinity(r);
|
||||
*r = ctx->initial;
|
||||
/* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */
|
||||
secp256k1_scalar_add(&gnb, gn, &ctx->blind);
|
||||
add.infinity = 0;
|
||||
for (j = 0; j < 64; j++) {
|
||||
bits = secp256k1_scalar_get_bits(gn, j * 4, 4);
|
||||
bits = secp256k1_scalar_get_bits(&gnb, j * 4, 4);
|
||||
for (i = 0; i < 16; i++) {
|
||||
/** This uses a conditional move to avoid any secret data in array indexes.
|
||||
* _Any_ use of secret indexes has been demonstrated to result in timing
|
||||
|
@ -123,6 +132,53 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp
|
|||
}
|
||||
bits = 0;
|
||||
secp256k1_ge_clear(&add);
|
||||
secp256k1_scalar_clear(&gnb);
|
||||
}
|
||||
|
||||
/* Setup blinding values for secp256k1_ecmult_gen. */
|
||||
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32) {
|
||||
secp256k1_scalar_t b;
|
||||
secp256k1_gej_t gb;
|
||||
secp256k1_fe_t s;
|
||||
unsigned char nonce32[32];
|
||||
secp256k1_rfc6979_hmac_sha256_t rng;
|
||||
int retry;
|
||||
if (!seed32) {
|
||||
/* When seed is NULL, reset the initial point and blinding value. */
|
||||
secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g);
|
||||
secp256k1_gej_neg(&ctx->initial, &ctx->initial);
|
||||
secp256k1_scalar_set_int(&ctx->blind, 1);
|
||||
}
|
||||
/* The prior blinding value (if not reset) is chained forward by including it in the hash. */
|
||||
secp256k1_scalar_get_b32(nonce32, &ctx->blind);
|
||||
/** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data,
|
||||
* and guards against weak or adversarial seeds. This is a simpler and safer interface than
|
||||
* asking the caller for blinding values directly and expecting them to retry on failure.
|
||||
*/
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed32 ? seed32 : nonce32, 32, nonce32, 32, NULL, 0);
|
||||
/* Retry for out of range results to achieve uniformity. */
|
||||
do {
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||
retry = !secp256k1_fe_set_b32(&s, nonce32);
|
||||
retry |= secp256k1_fe_is_zero(&s);
|
||||
} while (retry);
|
||||
/* Randomize the projection to defend against multiplier sidechannels. */
|
||||
secp256k1_gej_rescale(&ctx->initial, &s);
|
||||
secp256k1_fe_clear(&s);
|
||||
do {
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||
secp256k1_scalar_set_b32(&b, nonce32, &retry);
|
||||
/* A blinding value of 0 works, but would undermine the projection hardening. */
|
||||
retry |= secp256k1_scalar_is_zero(&b);
|
||||
} while (retry);
|
||||
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
||||
memset(nonce32, 0, 32);
|
||||
secp256k1_ecmult_gen(ctx, &gb, &b);
|
||||
secp256k1_scalar_negate(&b, &b);
|
||||
ctx->blind = b;
|
||||
ctx->initial = gb;
|
||||
secp256k1_scalar_clear(&b);
|
||||
secp256k1_gej_clear(&gb);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -115,4 +115,7 @@ static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_stor
|
|||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
|
||||
static void secp256k1_ge_storage_cmov(secp256k1_ge_storage_t *r, const secp256k1_ge_storage_t *a, int flag);
|
||||
|
||||
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
|
||||
static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *b);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -396,6 +396,17 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c
|
|||
r->infinity = infinity;
|
||||
}
|
||||
|
||||
static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *s) {
|
||||
/* Operations: 4 mul, 1 sqr */
|
||||
secp256k1_fe_t zz;
|
||||
VERIFY_CHECK(!secp256k1_fe_is_zero(s));
|
||||
secp256k1_fe_sqr(&zz, s);
|
||||
secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */
|
||||
secp256k1_fe_mul(&r->y, &r->y, &zz);
|
||||
secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */
|
||||
secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */
|
||||
}
|
||||
|
||||
static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t *a) {
|
||||
secp256k1_fe_t x, y;
|
||||
VERIFY_CHECK(!a->infinity);
|
||||
|
|
|
@ -410,3 +410,10 @@ int secp256k1_ec_privkey_import(const secp256k1_context_t* ctx, unsigned char *s
|
|||
secp256k1_scalar_clear(&key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_context_randomize(secp256k1_context_t* ctx, const unsigned char *seed32) {
|
||||
DEBUG_CHECK(ctx != NULL);
|
||||
DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
|
||||
return 1;
|
||||
}
|
||||
|
|
113
src/tests.c
113
src/tests.c
|
@ -907,6 +907,28 @@ void ge_equals_ge(const secp256k1_ge_t *a, const secp256k1_ge_t *b) {
|
|||
CHECK(secp256k1_fe_equal_var(&b->y, &b->y));
|
||||
}
|
||||
|
||||
/* This compares jacobian points including their Z, not just their geometric meaning. */
|
||||
int gej_xyz_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
|
||||
secp256k1_gej_t a2;
|
||||
secp256k1_gej_t b2;
|
||||
int ret = 1;
|
||||
ret &= a->infinity == b->infinity;
|
||||
if (ret && !a->infinity) {
|
||||
a2 = *a;
|
||||
b2 = *b;
|
||||
secp256k1_fe_normalize(&a2.x);
|
||||
secp256k1_fe_normalize(&a2.y);
|
||||
secp256k1_fe_normalize(&a2.z);
|
||||
secp256k1_fe_normalize(&b2.x);
|
||||
secp256k1_fe_normalize(&b2.y);
|
||||
secp256k1_fe_normalize(&b2.z);
|
||||
ret &= secp256k1_fe_cmp_var(&a2.x, &b2.x) == 0;
|
||||
ret &= secp256k1_fe_cmp_var(&a2.y, &b2.y) == 0;
|
||||
ret &= secp256k1_fe_cmp_var(&a2.z, &b2.z) == 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) {
|
||||
secp256k1_fe_t z2s;
|
||||
secp256k1_fe_t u1, u2, s1, s2;
|
||||
|
@ -1033,6 +1055,9 @@ void test_ge(void) {
|
|||
secp256k1_ge_t *ge_set_all = (secp256k1_ge_t *)malloc((4 * runs + 1) * sizeof(secp256k1_ge_t));
|
||||
secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej);
|
||||
for (i = 0; i < 4 * runs + 1; i++) {
|
||||
secp256k1_fe_t s;
|
||||
random_fe_non_zero(&s);
|
||||
secp256k1_gej_rescale(&gej[i], &s);
|
||||
ge_equals_gej(&ge_set_all[i], &gej[i]);
|
||||
}
|
||||
free(ge_set_all);
|
||||
|
@ -1203,6 +1228,87 @@ void run_wnaf(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void test_ecmult_constants(void) {
|
||||
/* Test ecmult_gen() for [0..36) and [order-36..0). */
|
||||
secp256k1_scalar_t x;
|
||||
secp256k1_gej_t r;
|
||||
secp256k1_ge_t ng;
|
||||
int i;
|
||||
int j;
|
||||
secp256k1_ge_neg(&ng, &secp256k1_ge_const_g);
|
||||
for (i = 0; i < 36; i++ ) {
|
||||
secp256k1_scalar_set_int(&x, i);
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x);
|
||||
for (j = 0; j < i; j++) {
|
||||
if (j == i - 1) {
|
||||
ge_equals_gej(&secp256k1_ge_const_g, &r);
|
||||
}
|
||||
secp256k1_gej_add_ge(&r, &r, &ng);
|
||||
}
|
||||
CHECK(secp256k1_gej_is_infinity(&r));
|
||||
}
|
||||
for (i = 1; i <= 36; i++ ) {
|
||||
secp256k1_scalar_set_int(&x, i);
|
||||
secp256k1_scalar_negate(&x, &x);
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x);
|
||||
for (j = 0; j < i; j++) {
|
||||
if (j == i - 1) {
|
||||
ge_equals_gej(&ng, &r);
|
||||
}
|
||||
secp256k1_gej_add_ge(&r, &r, &secp256k1_ge_const_g);
|
||||
}
|
||||
CHECK(secp256k1_gej_is_infinity(&r));
|
||||
}
|
||||
}
|
||||
|
||||
void run_ecmult_constants(void) {
|
||||
test_ecmult_constants();
|
||||
}
|
||||
|
||||
void test_ecmult_gen_blind(void) {
|
||||
/* Test ecmult_gen() blinding and confirm that the blinding changes, the affline points match, and the z's don't match. */
|
||||
secp256k1_scalar_t key;
|
||||
secp256k1_scalar_t b;
|
||||
unsigned char seed32[32];
|
||||
secp256k1_gej_t pgej;
|
||||
secp256k1_gej_t pgej2;
|
||||
secp256k1_gej_t i;
|
||||
secp256k1_ge_t pge;
|
||||
random_scalar_order_test(&key);
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key);
|
||||
secp256k1_rand256(seed32);
|
||||
b = ctx->ecmult_gen_ctx.blind;
|
||||
i = ctx->ecmult_gen_ctx.initial;
|
||||
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
|
||||
CHECK(!secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind));
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej2, &key);
|
||||
CHECK(!gej_xyz_equals_gej(&pgej, &pgej2));
|
||||
CHECK(!gej_xyz_equals_gej(&i, &ctx->ecmult_gen_ctx.initial));
|
||||
secp256k1_ge_set_gej(&pge, &pgej);
|
||||
ge_equals_gej(&pge, &pgej2);
|
||||
}
|
||||
|
||||
void test_ecmult_gen_blind_reset(void) {
|
||||
/* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */
|
||||
secp256k1_scalar_t b;
|
||||
secp256k1_gej_t initial;
|
||||
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0);
|
||||
b = ctx->ecmult_gen_ctx.blind;
|
||||
initial = ctx->ecmult_gen_ctx.initial;
|
||||
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0);
|
||||
CHECK(secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind));
|
||||
CHECK(gej_xyz_equals_gej(&initial, &ctx->ecmult_gen_ctx.initial));
|
||||
}
|
||||
|
||||
void run_ecmult_gen_blind(void) {
|
||||
int i;
|
||||
test_ecmult_gen_blind_reset();
|
||||
for (i = 0; i < 10; i++) {
|
||||
test_ecmult_gen_blind();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, const secp256k1_scalar_t *msg, int *recid) {
|
||||
secp256k1_scalar_t nonce;
|
||||
do {
|
||||
|
@ -1913,6 +2019,11 @@ int main(int argc, char **argv) {
|
|||
run_context_tests();
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
|
||||
if (secp256k1_rand32() & 1) {
|
||||
secp256k1_rand256(run32);
|
||||
CHECK(secp256k1_context_randomize(ctx, secp256k1_rand32() & 1 ? run32 : NULL));
|
||||
}
|
||||
|
||||
run_sha256_tests();
|
||||
run_hmac_sha256_tests();
|
||||
run_rfc6979_hmac_sha256_tests();
|
||||
|
@ -1941,6 +2052,8 @@ int main(int argc, char **argv) {
|
|||
run_wnaf();
|
||||
run_point_times_order();
|
||||
run_ecmult_chain();
|
||||
run_ecmult_constants();
|
||||
run_ecmult_gen_blind();
|
||||
|
||||
/* ecdsa tests */
|
||||
run_random_pubkeys();
|
||||
|
|
Loading…
Reference in a new issue