Skip to content

Commit ab45c3e

Browse files
committed
Initial gej blinding -> final ge blinding
Instead of having the starting point of the ecmult_gen computation be offset, do it with the final point. This enables reasoning over the set of points reachable in intermediary computations, which can be leveraged by potential future optimization. Because the final point is in affine coordinates, its projective blinding is no longer possible. It will be reintroduced again in a different way, in a later commit. Also introduce some more comments and more descriptive names.
1 parent aa00a6b commit ab45c3e

File tree

3 files changed

+43
-39
lines changed

3 files changed

+43
-39
lines changed

src/ecmult_gen.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ typedef struct {
3232
/* Whether the context has been built. */
3333
int built;
3434

35-
/* Blinding values used when computing (n-b)G + bG. */
36-
secp256k1_scalar blind; /* -b */
37-
secp256k1_gej initial; /* bG */
35+
/* Blinding values used when computing nG as (n-b)G + bG. */
36+
secp256k1_scalar scalar_offset; /* -b */
37+
secp256k1_ge ge_offset; /* bG */
3838
} secp256k1_ecmult_gen_context;
3939

4040
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx);

src/ecmult_gen_impl.h

+27-24
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_cont
2525

2626
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
2727
ctx->built = 0;
28-
secp256k1_scalar_clear(&ctx->blind);
29-
secp256k1_gej_clear(&ctx->initial);
28+
secp256k1_scalar_clear(&ctx->scalar_offset);
29+
secp256k1_ge_clear(&ctx->ge_offset);
3030
}
3131

3232
/* For accelerating the computation of a*G:
@@ -51,12 +51,13 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
5151
secp256k1_ge_storage adds;
5252
secp256k1_scalar gnb;
5353
int i, j, n_i;
54-
54+
5555
memset(&adds, 0, sizeof(adds));
56-
*r = ctx->initial;
57-
/* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */
58-
secp256k1_scalar_add(&gnb, gn, &ctx->blind);
59-
add.infinity = 0;
56+
secp256k1_gej_set_infinity(r);
57+
58+
/* Blind scalar/point multiplication by computing (gn-b)*G + b*G instead of gn*G. */
59+
secp256k1_scalar_add(&gnb, gn, &ctx->scalar_offset);
60+
6061
for (i = 0; i < n; i++) {
6162
n_i = secp256k1_scalar_get_bits(&gnb, i * bits, bits);
6263
for (j = 0; j < g; j++) {
@@ -76,6 +77,11 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
7677
secp256k1_gej_add_ge(r, r, &add);
7778
}
7879
n_i = 0;
80+
81+
/* Correct for the scalar_offset added at the start (ge_offset = b*G, while b was
82+
* subtracted from the input scalar gn). */
83+
secp256k1_gej_add_ge(r, r, &ctx->ge_offset);
84+
7985
secp256k1_ge_clear(&add);
8086
secp256k1_scalar_clear(&gnb);
8187
}
@@ -84,19 +90,17 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
8490
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) {
8591
secp256k1_scalar b;
8692
secp256k1_gej gb;
87-
secp256k1_fe s;
8893
unsigned char nonce32[32];
8994
secp256k1_rfc6979_hmac_sha256 rng;
9095
unsigned char keydata[64];
9196
if (seed32 == NULL) {
92-
/* When seed is NULL, reset the initial point and blinding value. */
93-
secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g);
94-
secp256k1_gej_neg(&ctx->initial, &ctx->initial);
95-
secp256k1_scalar_set_int(&ctx->blind, 1);
97+
/* When seed is NULL, reset the final point and blinding value. */
98+
secp256k1_ge_neg(&ctx->ge_offset, &secp256k1_ge_const_g);
99+
ctx->scalar_offset = secp256k1_scalar_one;
96100
return;
97101
}
98102
/* The prior blinding value (if not reset) is chained forward by including it in the hash. */
99-
secp256k1_scalar_get_b32(keydata, &ctx->blind);
103+
secp256k1_scalar_get_b32(keydata, &ctx->scalar_offset);
100104
/** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data,
101105
* and guards against weak or adversarial seeds. This is a simpler and safer interface than
102106
* asking the caller for blinding values directly and expecting them to retry on failure.
@@ -105,24 +109,23 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
105109
memcpy(keydata + 32, seed32, 32);
106110
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
107111
memset(keydata, 0, sizeof(keydata));
108-
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
109-
secp256k1_fe_set_b32_mod(&s, nonce32);
110-
secp256k1_fe_cmov(&s, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&s));
111-
/* Randomize the projection to defend against multiplier sidechannels.
112-
Do this before our own call to secp256k1_ecmult_gen below. */
113-
secp256k1_gej_rescale(&ctx->initial, &s);
114-
secp256k1_fe_clear(&s);
112+
113+
/* TODO: reintroduce projective blinding. */
114+
115+
/* For a random blinding value b, set ctx->scalar_offset=-b, ctx->ge_offset=bG. */
115116
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
116117
secp256k1_scalar_set_b32(&b, nonce32, NULL);
117-
/* A blinding value of 0 works, but would undermine the projection hardening. */
118+
/* The blinding value cannot be zero, as that would mean ge_offset = infinity,
119+
* which secp256k1_gej_add_ge cannot handle. */
118120
secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
119121
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
120122
memset(nonce32, 0, 32);
121-
/* The random projection in ctx->initial ensures that gb will have a random projection. */
122123
secp256k1_ecmult_gen(ctx, &gb, &b);
123124
secp256k1_scalar_negate(&b, &b);
124-
ctx->blind = b;
125-
ctx->initial = gb;
125+
ctx->scalar_offset = b;
126+
secp256k1_ge_set_gej(&ctx->ge_offset, &gb);
127+
128+
/* Clean up. */
126129
secp256k1_scalar_clear(&b);
127130
secp256k1_gej_clear(&gb);
128131
}

src/tests.c

+13-12
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,8 @@ static void run_selftest_tests(void) {
248248

249249
static int ecmult_gen_context_eq(const secp256k1_ecmult_gen_context *a, const secp256k1_ecmult_gen_context *b) {
250250
return a->built == b->built
251-
&& secp256k1_scalar_eq(&a->blind, &b->blind)
252-
&& secp256k1_gej_eq_var(&a->initial, &b->initial);
251+
&& secp256k1_scalar_eq(&a->scalar_offset, &b->scalar_offset)
252+
&& secp256k1_ge_eq_var(&a->ge_offset, &b->ge_offset);
253253
}
254254

255255
static int context_eq(const secp256k1_context *a, const secp256k1_context *b) {
@@ -5570,32 +5570,33 @@ static void test_ecmult_gen_blind(void) {
55705570
unsigned char seed32[32];
55715571
secp256k1_gej pgej;
55725572
secp256k1_gej pgej2;
5573-
secp256k1_gej i;
5573+
secp256k1_ge p;
55745574
secp256k1_ge pge;
55755575
random_scalar_order_test(&key);
55765576
secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej, &key);
55775577
secp256k1_testrand256(seed32);
5578-
b = CTX->ecmult_gen_ctx.blind;
5579-
i = CTX->ecmult_gen_ctx.initial;
5578+
b = CTX->ecmult_gen_ctx.scalar_offset;
5579+
p = CTX->ecmult_gen_ctx.ge_offset;
55805580
secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, seed32);
5581-
CHECK(!secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.blind));
5581+
CHECK(!secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset));
55825582
secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej2, &key);
55835583
CHECK(!gej_xyz_equals_gej(&pgej, &pgej2));
5584-
CHECK(!gej_xyz_equals_gej(&i, &CTX->ecmult_gen_ctx.initial));
5584+
CHECK(!secp256k1_ge_eq_var(&p, &CTX->ecmult_gen_ctx.ge_offset));
55855585
secp256k1_ge_set_gej(&pge, &pgej);
55865586
CHECK(secp256k1_gej_eq_ge_var(&pgej2, &pge));
55875587
}
55885588

55895589
static void test_ecmult_gen_blind_reset(void) {
55905590
/* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */
55915591
secp256k1_scalar b;
5592-
secp256k1_gej initial;
5592+
secp256k1_ge p1, p2;
55935593
secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0);
5594-
b = CTX->ecmult_gen_ctx.blind;
5595-
initial = CTX->ecmult_gen_ctx.initial;
5594+
b = CTX->ecmult_gen_ctx.scalar_offset;
5595+
p1 = CTX->ecmult_gen_ctx.ge_offset;
55965596
secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0);
5597-
CHECK(secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.blind));
5598-
CHECK(gej_xyz_equals_gej(&initial, &CTX->ecmult_gen_ctx.initial));
5597+
CHECK(secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset));
5598+
p2 = CTX->ecmult_gen_ctx.ge_offset;
5599+
CHECK(secp256k1_ge_eq_var(&p1, &p2));
55995600
}
56005601

56015602
static void run_ecmult_gen_blind(void) {

0 commit comments

Comments
 (0)