Skip to content

Commit 7c7b2fe

Browse files
contexts: Forbid randomizing secp256k1_context_static
1 parent f00e471 commit 7c7b2fe

File tree

4 files changed

+56
-17
lines changed

4 files changed

+56
-17
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
#### Changed
1111
- Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.)
12+
- Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization.
1213

1314
## [0.2.0] - 2022-12-12
1415

include/secp256k1.h

+6-10
Original file line numberDiff line numberDiff line change
@@ -824,10 +824,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
824824

825825
/** Randomizes the context to provide enhanced protection against side-channel leakage.
826826
*
827-
* Returns: 1: randomization successful (or called on copy of secp256k1_context_static)
827+
* Returns: 1: randomization successful
828828
* 0: error
829-
* Args: ctx: pointer to a context object.
830-
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
829+
* Args: ctx: pointer to a context object (not secp256k1_context_static).
830+
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state).
831831
*
832832
* While secp256k1 code is written and tested to be constant-time no matter what
833833
* secret values are, it is possible that a compiler may output code which is not,
@@ -842,21 +842,17 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
842842
* functions that perform computations involving secret keys, e.g., signing and
843843
* public key generation. It is possible to call this function more than once on
844844
* the same context, and doing so before every few computations involving secret
845-
* keys is recommended as a defense-in-depth measure.
845+
* keys is recommended as a defense-in-depth measure. Randomization of the static
846+
* context secp256k1_context_static is not supported.
846847
*
847848
* Currently, the random seed is mainly used for blinding multiplications of a
848849
* secret scalar with the elliptic curve base point. Multiplications of this
849850
* kind are performed by exactly those API functions which are documented to
850-
* require a context that is not the secp256k1_context_static. As a rule of thumb,
851+
* require a context that is not secp256k1_context_static. As a rule of thumb,
851852
* these are all functions which take a secret key (or a keypair) as an input.
852853
* A notable exception to that rule is the ECDH module, which relies on a different
853854
* kind of elliptic curve point multiplication and thus does not benefit from
854855
* enhanced protection against side-channel leakage currently.
855-
*
856-
* It is safe to call this function on a copy of secp256k1_context_static in writable
857-
* memory (e.g., obtained via secp256k1_context_clone). In that case, this
858-
* function is guaranteed to return 1, but the call will have no effect because
859-
* the static context (or a copy thereof) is not meant to be randomized.
860856
*/
861857
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
862858
secp256k1_context* ctx,

src/secp256k1.c

+2
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,8 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey
749749

750750
int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) {
751751
VERIFY_CHECK(ctx != NULL);
752+
ARG_CHECK(secp256k1_context_is_proper(ctx));
753+
752754
if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) {
753755
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
754756
}

src/tests.c

+47-7
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,16 @@ static void run_static_context_tests(int use_prealloc) {
247247

248248
{
249249
int ecount = 0;
250+
unsigned char seed[32] = {0x17};
250251
secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
252+
253+
/* Randomizing secp256k1_context_static is not supported. */
254+
CHECK(secp256k1_context_randomize(STATIC_CTX, seed) == 0);
255+
CHECK(ecount == 1);
256+
CHECK(secp256k1_context_randomize(STATIC_CTX, NULL) == 0);
257+
CHECK(ecount == 2);
258+
ecount = 0;
259+
251260
/* Destroying or cloning secp256k1_context_static is not supported. */
252261
if (use_prealloc) {
253262
CHECK(secp256k1_context_preallocated_clone_size(STATIC_CTX) == 0);
@@ -284,13 +293,18 @@ static void run_static_context_tests(int use_prealloc) {
284293

285294
static void run_proper_context_tests(int use_prealloc) {
286295
int32_t dummy = 0;
287-
secp256k1_context *my_ctx;
296+
secp256k1_context *my_ctx, *my_ctx_fresh;
288297
void *my_ctx_prealloc = NULL;
298+
unsigned char seed[32] = {0x17};
289299

290300
secp256k1_gej pubj;
291301
secp256k1_ge pub;
292302
secp256k1_scalar msg, key, nonce;
293303
secp256k1_scalar sigr, sigs;
304+
305+
/* Fresh reference context for comparison */
306+
my_ctx_fresh = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
307+
294308
if (use_prealloc) {
295309
my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
296310
CHECK(my_ctx_prealloc != NULL);
@@ -299,6 +313,13 @@ static void run_proper_context_tests(int use_prealloc) {
299313
my_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
300314
}
301315

316+
/* Randomize and reset randomization */
317+
CHECK(context_eq(my_ctx, my_ctx_fresh));
318+
CHECK(secp256k1_context_randomize(my_ctx, seed) == 1);
319+
CHECK(!context_eq(my_ctx, my_ctx_fresh));
320+
CHECK(secp256k1_context_randomize(my_ctx, NULL) == 1);
321+
CHECK(context_eq(my_ctx, my_ctx_fresh));
322+
302323
/* set error callback (to a function that still aborts in case malloc() fails in secp256k1_context_clone() below) */
303324
secp256k1_context_set_error_callback(my_ctx, secp256k1_default_illegal_callback_fn, NULL);
304325
CHECK(my_ctx->error_callback.fn != secp256k1_default_error_callback_fn);
@@ -313,16 +334,33 @@ static void run_proper_context_tests(int use_prealloc) {
313334

314335
if (use_prealloc) {
315336
/* clone into a non-preallocated context and then again into a new preallocated one. */
316-
ctx_tmp = my_ctx; my_ctx = secp256k1_context_clone(my_ctx); secp256k1_context_preallocated_destroy(ctx_tmp);
317-
free(my_ctx_prealloc); my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(my_ctx_prealloc != NULL);
318-
ctx_tmp = my_ctx; my_ctx = secp256k1_context_preallocated_clone(my_ctx, my_ctx_prealloc); secp256k1_context_destroy(ctx_tmp);
337+
ctx_tmp = my_ctx;
338+
my_ctx = secp256k1_context_clone(my_ctx);
339+
CHECK(context_eq(ctx_tmp, my_ctx));
340+
secp256k1_context_preallocated_destroy(ctx_tmp);
341+
342+
free(my_ctx_prealloc);
343+
my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
344+
CHECK(my_ctx_prealloc != NULL);
345+
ctx_tmp = my_ctx;
346+
my_ctx = secp256k1_context_preallocated_clone(my_ctx, my_ctx_prealloc);
347+
CHECK(context_eq(ctx_tmp, my_ctx));
348+
secp256k1_context_destroy(ctx_tmp);
319349
} else {
320350
/* clone into a preallocated context and then again into a new non-preallocated one. */
321351
void *prealloc_tmp;
322352

323-
prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(prealloc_tmp != NULL);
324-
ctx_tmp = my_ctx; my_ctx = secp256k1_context_preallocated_clone(my_ctx, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
325-
ctx_tmp = my_ctx; my_ctx = secp256k1_context_clone(my_ctx); secp256k1_context_preallocated_destroy(ctx_tmp);
353+
prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
354+
CHECK(prealloc_tmp != NULL);
355+
ctx_tmp = my_ctx;
356+
my_ctx = secp256k1_context_preallocated_clone(my_ctx, prealloc_tmp);
357+
CHECK(context_eq(ctx_tmp, my_ctx));
358+
secp256k1_context_destroy(ctx_tmp);
359+
360+
ctx_tmp = my_ctx;
361+
my_ctx = secp256k1_context_clone(my_ctx);
362+
CHECK(context_eq(ctx_tmp, my_ctx));
363+
secp256k1_context_preallocated_destroy(ctx_tmp);
326364
free(prealloc_tmp);
327365
}
328366
}
@@ -333,12 +371,14 @@ static void run_proper_context_tests(int use_prealloc) {
333371
/* And that it resets back to default. */
334372
secp256k1_context_set_error_callback(my_ctx, NULL, NULL);
335373
CHECK(my_ctx->error_callback.fn == secp256k1_default_error_callback_fn);
374+
CHECK(context_eq(my_ctx, my_ctx_fresh));
336375

337376
/* Verify that setting and resetting illegal callback works */
338377
secp256k1_context_set_illegal_callback(my_ctx, counting_illegal_callback_fn, &dummy);
339378
CHECK(my_ctx->illegal_callback.fn == counting_illegal_callback_fn);
340379
secp256k1_context_set_illegal_callback(my_ctx, NULL, NULL);
341380
CHECK(my_ctx->illegal_callback.fn == secp256k1_default_illegal_callback_fn);
381+
CHECK(context_eq(my_ctx, my_ctx_fresh));
342382

343383
/*** attempt to use them ***/
344384
random_scalar_order_test(&msg);

0 commit comments

Comments
 (0)