Skip to content

Commit 0c6ab2f

Browse files
committed
Introduce explicit lower-S normalization
ECDSA signature verification now requires normalized signatures (with S in the lower half of the range). In case the input cannot be guaranteed to provide this, a new function secp256k1_ecdsa_signature_normalize is provided to preprocess it.
1 parent fea19e7 commit 0c6ab2f

File tree

3 files changed

+97
-28
lines changed

3 files changed

+97
-28
lines changed

include/secp256k1.h

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,15 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
355355
* In: sig: the signature being verified (cannot be NULL)
356356
* msg32: the 32-byte message hash being verified (cannot be NULL)
357357
* pubkey: pointer to an initialized public key to verify with (cannot be NULL)
358+
*
359+
* To avoid accepting malleable signatures, only ECDSA signatures in lower-S
360+
* form are accepted.
361+
*
362+
* If you need to accept ECDSA signatures from sources that do not obey this
363+
* rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to
364+
* validation, but be aware that doing so results in malleable signatures.
365+
*
366+
* For details, see the comments for that function.
358367
*/
359368
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
360369
const secp256k1_context* ctx,
@@ -363,6 +372,54 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
363372
const secp256k1_pubkey *pubkey
364373
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
365374

375+
/** Convert a signature to a normalized lower-S form.
376+
*
377+
* Returns: 1 if sigin was not normalized, 0 if it already was.
378+
* Args: ctx: a secp256k1 context object
379+
* Out: sigout: a pointer to a signature to fill with the normalized form,
380+
* or copy if the input was already normalized. (can be NULL if
381+
* you're only interested in whether the input was already
382+
* normalized).
383+
* In: sigin: a pointer to a signature to check/normalize (cannot be NULL,
384+
* can be identical to sigout)
385+
*
386+
* With ECDSA a third-party can forge a second distinct signature of the same
387+
* message, given a single initial signature, but without knowing the key. This
388+
* is done by negating the S value modulo the order of the curve, 'flipping'
389+
* the sign of the random point R which is not included in the signature.
390+
*
391+
* Forgery of the same message isn't universally problematic, but in systems
392+
* where message malleability or uniqueness of signatures is important this can
393+
* cause issues. This forgery can be blocked by all verifiers forcing signers
394+
* to use a normalized form.
395+
*
396+
* The lower-S form reduces the size of signatures slightly on average when
397+
* variable length encodings (such as DER) are used and is cheap to verify,
398+
* making it a good choice. Security of always using lower-S is assured because
399+
* anyone can trivially modify a signature after the fact to enforce this
400+
* property anyway.
401+
*
402+
* The lower S value is always between 0x1 and
403+
* 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
404+
* inclusive.
405+
*
406+
* No other forms of ECDSA malleability are known and none seem likely, but
407+
* there is no formal proof that ECDSA, even with this additional restriction,
408+
* is free of other malleability. Commonly used serialization schemes will also
409+
* accept various non-unique encodings, so care should be taken when this
410+
* property is required for an application.
411+
*
412+
* The secp256k1_ecdsa_sign function will by default create signatures in the
413+
* lower-S form, and secp256k1_ecdsa_verify will not accept others. In case
414+
* signatures come from a system that cannot enforce this property,
415+
* secp256k1_ecdsa_signature_normalize must be called before verification.
416+
*/
417+
SECP256K1_API int secp256k1_ecdsa_signature_normalize(
418+
const secp256k1_context* ctx,
419+
secp256k1_ecdsa_signature *sigout,
420+
const secp256k1_ecdsa_signature *sigin
421+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3);
422+
366423
/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function.
367424
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
368425
* extra entropy.
@@ -383,32 +440,8 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_def
383440
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
384441
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
385442
*
386-
* The sig always has an s value in the lower half of the range (From 0x1
387-
* to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
388-
* inclusive), unlike many other implementations.
389-
*
390-
* With ECDSA a third-party can can forge a second distinct signature
391-
* of the same message given a single initial signature without knowing
392-
* the key by setting s to its additive inverse mod-order, 'flipping' the
393-
* sign of the random point R which is not included in the signature.
394-
* Since the forgery is of the same message this isn't universally
395-
* problematic, but in systems where message malleability or uniqueness
396-
* of signatures is important this can cause issues. This forgery can be
397-
* blocked by all verifiers forcing signers to use a canonical form. The
398-
* lower-S form reduces the size of signatures slightly on average when
399-
* variable length encodings (such as DER) are used and is cheap to
400-
* verify, making it a good choice. Security of always using lower-S is
401-
* assured because anyone can trivially modify a signature after the
402-
* fact to enforce this property. Adjusting it inside the signing
403-
* function avoids the need to re-serialize or have curve specific
404-
* constants outside of the library. By always using a canonical form
405-
* even in applications where it isn't needed it becomes possible to
406-
* impose a requirement later if a need is discovered.
407-
* No other forms of ECDSA malleability are known and none seem likely,
408-
* but there is no formal proof that ECDSA, even with this additional
409-
* restriction, is free of other malleability. Commonly used serialization
410-
* schemes will also accept various non-unique encodings, so care should
411-
* be taken when this property is required for an application.
443+
* The created signature is always in lower-S form. See
444+
* secp256k1_ecdsa_signature_normalize for more details.
412445
*/
413446
SECP256K1_API int secp256k1_ecdsa_sign(
414447
const secp256k1_context* ctx,

src/secp256k1.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,25 @@ int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, un
256256
return 1;
257257
}
258258

259+
int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) {
260+
secp256k1_scalar r, s;
261+
int ret = 0;
262+
263+
VERIFY_CHECK(ctx != NULL);
264+
ARG_CHECK(sigin != NULL);
265+
266+
secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin);
267+
ret = secp256k1_scalar_is_high(&s);
268+
if (sigout != NULL) {
269+
if (ret) {
270+
secp256k1_scalar_negate(&s, &s);
271+
}
272+
secp256k1_ecdsa_signature_save(sigout, &r, &s);
273+
}
274+
275+
return ret;
276+
}
277+
259278
int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey) {
260279
secp256k1_ge q;
261280
secp256k1_scalar r, s;
@@ -268,7 +287,8 @@ int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_s
268287

269288
secp256k1_scalar_set_b32(&m, msg32, NULL);
270289
secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
271-
return (secp256k1_pubkey_load(ctx, &q, pubkey) &&
290+
return (!secp256k1_scalar_is_high(&s) &&
291+
secp256k1_pubkey_load(ctx, &q, pubkey) &&
272292
secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m));
273293
}
274294

src/tests.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2322,7 +2322,8 @@ void test_ecdsa_end_to_end(void) {
23222322
unsigned char privkey[32];
23232323
unsigned char message[32];
23242324
unsigned char privkey2[32];
2325-
secp256k1_ecdsa_signature signature[5];
2325+
secp256k1_ecdsa_signature signature[6];
2326+
secp256k1_scalar r, s;
23262327
unsigned char sig[74];
23272328
size_t siglen = 74;
23282329
unsigned char pubkeyc[65];
@@ -2409,6 +2410,21 @@ void test_ecdsa_end_to_end(void) {
24092410
CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1);
24102411
CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1);
24112412
CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1);
2413+
/* Test lower-S form, malleate, verify and fail, test again, malleate again */
2414+
CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[0]));
2415+
secp256k1_ecdsa_signature_load(ctx, &r, &s, &signature[0]);
2416+
secp256k1_scalar_negate(&s, &s);
2417+
secp256k1_ecdsa_signature_save(&signature[5], &r, &s);
2418+
CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0);
2419+
CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5]));
2420+
CHECK(secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5]));
2421+
CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5]));
2422+
CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1);
2423+
secp256k1_scalar_negate(&s, &s);
2424+
secp256k1_ecdsa_signature_save(&signature[5], &r, &s);
2425+
CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5]));
2426+
CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1);
2427+
CHECK(memcmp(&signature[5], &signature[0], 64) == 0);
24122428

24132429
/* Serialize/parse DER and verify again */
24142430
CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1);

0 commit comments

Comments
 (0)