From a69a662d052f2a3839798fdb7d98864d26ccf2cb Mon Sep 17 00:00:00 2001 From: mllwchrry Date: Fri, 10 Jul 2026 19:06:29 +0300 Subject: [PATCH] Fix missing clears on secret values --- src/modules/ecdsa_s2c/main_impl.h | 1 + src/modules/generator/main_impl.h | 3 +++ src/modules/rangeproof/rangeproof_impl.h | 16 +++++++++++++++- src/modules/surjection/main_impl.h | 13 +++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/modules/ecdsa_s2c/main_impl.h b/src/modules/ecdsa_s2c/main_impl.h index d9957773..c6030245 100644 --- a/src/modules/ecdsa_s2c/main_impl.h +++ b/src/modules/ecdsa_s2c/main_impl.h @@ -171,6 +171,7 @@ int secp256k1_ecdsa_anti_exfil_signer_commit(const secp256k1_context* ctx, secp2 secp256k1_ecmult_gen_ge(&ctx->ecmult_gen_ctx, &r, &k); secp256k1_ecdsa_s2c_opening_save(opening, &r); + secp256k1_scalar_clear(&k); secp256k1_memclear_explicit(nonce32, 32); return 1; } diff --git a/src/modules/generator/main_impl.h b/src/modules/generator/main_impl.h index ec9484a9..b5d68672 100644 --- a/src/modules/generator/main_impl.h +++ b/src/modules/generator/main_impl.h @@ -218,6 +218,7 @@ static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, s secp256k1_scalar_set_b32(&blind, blind32, &overflow); ret = !overflow; secp256k1_ecmult_gen_gej(&ctx->ecmult_gen_ctx, &accum, &blind); + secp256k1_scalar_clear(&blind); } secp256k1_sha256_initialize(&sha256); @@ -356,6 +357,8 @@ int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *bl for (i = 0; i < n; i++) { secp256k1_scalar_set_b32(&x, blinds[i], &overflow); if (overflow) { + secp256k1_scalar_clear(&acc); + secp256k1_scalar_clear(&x); return 0; } if (i >= npositive) { diff --git a/src/modules/rangeproof/rangeproof_impl.h b/src/modules/rangeproof/rangeproof_impl.h index 50211b07..8907a0d2 100644 --- a/src/modules/rangeproof/rangeproof_impl.h +++ b/src/modules/rangeproof/rangeproof_impl.h @@ -268,6 +268,8 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_hash_ prep[idx] = 128; } if (!secp256k1_rangeproof_genrand(hash_ctx, sec, s, prep, rsizes, rings, nonce, commit, proof, len, genp)) { + secp256k1_memclear_explicit(prep, sizeof(prep)); + secp256k1_memclear_explicit(sec, sizeof(sec)); return 0; } secp256k1_memclear_explicit(prep, 4096); @@ -284,7 +286,10 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_hash_ */ secp256k1_scalar_set_b32(&stmp, blind, &overflow); secp256k1_scalar_add(&sec[rings - 1], &sec[rings - 1], &stmp); + secp256k1_scalar_clear(&stmp); if (overflow || secp256k1_scalar_is_zero(&sec[rings - 1])) { + secp256k1_memclear_explicit(sec, sizeof(sec)); + secp256k1_memclear_explicit(k, sizeof(k)); return 0; } signs = &proof[len]; @@ -298,6 +303,8 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_hash_ /*OPT: Use the precomputed gen2 basis?*/ secp256k1_pedersen_ecmult(ecmult_gen_ctx, &pubs[npub], &sec[i], ((uint64_t)secidx[i] * scale) << (i*2), genp); if (secp256k1_gej_is_infinity(&pubs[npub])) { + secp256k1_memclear_explicit(sec, sizeof(sec)); + secp256k1_memclear_explicit(k, sizeof(k)); return 0; } if (i < rings - 1) { @@ -323,6 +330,8 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_hash_ secp256k1_sha256_finalize(hash_ctx, &sha256_m, tmp); secp256k1_sha256_clear(&sha256_m); if (!secp256k1_borromean_sign(hash_ctx, ecmult_gen_ctx, &proof[len], s, pubs, k, sec, rsizes, secidx, rings, tmp, 32)) { + secp256k1_memclear_explicit(sec, sizeof(sec)); + secp256k1_memclear_explicit(k, sizeof(k)); return 0; } len += 32; @@ -332,7 +341,8 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_hash_ } VERIFY_CHECK(len <= *plen); *plen = len; - secp256k1_memclear_explicit(prep, 4096); + secp256k1_memclear_explicit(sec, sizeof(sec)); + secp256k1_memclear_explicit(k, sizeof(k)); return 1; } @@ -658,6 +668,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_has return 0; } if (!secp256k1_rangeproof_rewind_inner(hash_ctx, &blind, &vv, message_out, outlen, evalues, s, rsizes, rings, nonce, commit, proof, offset_post_header, genp)) { + secp256k1_scalar_clear(&blind); return 0; } /* Unwind apparently successful, see if the commitment can be reconstructed. */ @@ -665,11 +676,13 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_has vv = (vv * scale) + *min_value; secp256k1_pedersen_ecmult(ecmult_gen_ctx, &accj, &blind, vv, genp); if (secp256k1_gej_is_infinity(&accj)) { + secp256k1_scalar_clear(&blind); return 0; } secp256k1_gej_neg(&accj, &accj); secp256k1_gej_add_ge_var(&accj, &accj, commit, NULL); if (!secp256k1_gej_is_infinity(&accj)) { + secp256k1_scalar_clear(&blind); return 0; } if (blindout) { @@ -678,6 +691,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_has if (value_out) { *value_out = vv; } + secp256k1_scalar_clear(&blind); } return ret; } diff --git a/src/modules/surjection/main_impl.h b/src/modules/surjection/main_impl.h index 80dbd7f3..8dfe794c 100644 --- a/src/modules/surjection/main_impl.h +++ b/src/modules/surjection/main_impl.h @@ -304,10 +304,13 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s /* Compute secret key */ secp256k1_scalar_set_b32(&tmps, input_blinding_key, &overflow); if (overflow) { + secp256k1_scalar_clear(&tmps); return 0; } secp256k1_scalar_set_b32(&blinding_key, output_blinding_key, &overflow); if (overflow) { + secp256k1_scalar_clear(&tmps); + secp256k1_scalar_clear(&blinding_key); return 0; } /* If any input tag is equal to an output tag, verification will fail, because our ring @@ -316,20 +319,25 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s * this at the same time that we relax the max-256-inputs rule. */ for (i = 0; i < n_ephemeral_input_tags; i++) { if (secp256k1_memcmp_var(ephemeral_input_tags[i].data, ephemeral_output_tag->data, sizeof(ephemeral_output_tag->data)) == 0) { + secp256k1_scalar_clear(&tmps); + secp256k1_scalar_clear(&blinding_key); return 0; } } secp256k1_scalar_negate(&tmps, &tmps); secp256k1_scalar_add(&blinding_key, &blinding_key, &tmps); + secp256k1_scalar_clear(&tmps); /* Compute public keys */ n_total_pubkeys = secp256k1_surjectionproof_n_total_inputs(ctx, proof); if (n_used_pubkeys > n_total_pubkeys || n_total_pubkeys != n_ephemeral_input_tags) { + secp256k1_scalar_clear(&blinding_key); return 0; } if (secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, ephemeral_input_tags, n_total_pubkeys, proof->used_inputs, ephemeral_output_tag, input_index, &ring_input_index) == 0) { + secp256k1_scalar_clear(&blinding_key); return 0; } @@ -351,6 +359,7 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s * checked above; ephemeral_output_tag is committed by msg32; input_index * and both blinding keys are passed directly. */ if (secp256k1_surjection_genrand(hash_ctx, borromean_s, n_used_pubkeys, n_total_pubkeys, proof->used_inputs, msg32, input_index, input_blinding_key, output_blinding_key) == 0) { + secp256k1_scalar_clear(&blinding_key); return 0; } /* Borromean sign will overwrite one of the s values we just generated, so use @@ -359,11 +368,15 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s nonce = borromean_s[ring_input_index]; secp256k1_scalar_clear(&borromean_s[ring_input_index]); if (secp256k1_borromean_sign(hash_ctx, &ctx->ecmult_gen_ctx, &proof->data[0], borromean_s, ring_pubkeys, &nonce, &blinding_key, rsizes, indices, 1, msg32, 32) == 0) { + secp256k1_scalar_clear(&blinding_key); + secp256k1_scalar_clear(&nonce); return 0; } for (i = 0; i < n_used_pubkeys; i++) { secp256k1_scalar_get_b32(&proof->data[32 + 32 * i], &borromean_s[i]); } + secp256k1_scalar_clear(&blinding_key); + secp256k1_scalar_clear(&nonce); return 1; }