diff --git a/include/secp256k1.h b/include/secp256k1.h index 063791d3425..61e8dd6b13f 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -355,6 +355,15 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( * In: sig: the signature being verified (cannot be NULL) * msg32: the 32-byte message hash being verified (cannot be NULL) * pubkey: pointer to an initialized public key to verify with (cannot be NULL) + * + * To avoid accepting malleable signatures, only ECDSA signatures in lower-S + * form are accepted. + * + * If you need to accept ECDSA signatures from sources that do not obey this + * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to + * validation, but be aware that doing so results in malleable signatures. + * + * For details, see the comments for that function. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( const secp256k1_context* ctx, @@ -363,6 +372,54 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( const secp256k1_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +/** Convert a signature to a normalized lower-S form. + * + * Returns: 1 if sigin was not normalized, 0 if it already was. + * Args: ctx: a secp256k1 context object + * Out: sigout: a pointer to a signature to fill with the normalized form, + * or copy if the input was already normalized. (can be NULL if + * you're only interested in whether the input was already + * normalized). + * In: sigin: a pointer to a signature to check/normalize (cannot be NULL, + * can be identical to sigout) + * + * With ECDSA a third-party can forge a second distinct signature of the same + * message, given a single initial signature, but without knowing the key. This + * is done by negating the S value modulo the order of the curve, 'flipping' + * the sign of the random point R which is not included in the signature. + * + * Forgery of the same message isn't universally problematic, but in systems + * where message malleability or uniqueness of signatures is important this can + * cause issues. This forgery can be blocked by all verifiers forcing signers + * to use a normalized form. + * + * The lower-S form reduces the size of signatures slightly on average when + * variable length encodings (such as DER) are used and is cheap to verify, + * making it a good choice. Security of always using lower-S is assured because + * anyone can trivially modify a signature after the fact to enforce this + * property anyway. + * + * The lower S value is always between 0x1 and + * 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, + * inclusive. + * + * No other forms of ECDSA malleability are known and none seem likely, but + * there is no formal proof that ECDSA, even with this additional restriction, + * is free of other malleability. Commonly used serialization schemes will also + * accept various non-unique encodings, so care should be taken when this + * property is required for an application. + * + * The secp256k1_ecdsa_sign function will by default create signatures in the + * lower-S form, and secp256k1_ecdsa_verify will not accept others. In case + * signatures come from a system that cannot enforce this property, + * secp256k1_ecdsa_signature_normalize must be called before verification. + */ +SECP256K1_API int secp256k1_ecdsa_signature_normalize( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature *sigout, + const secp256k1_ecdsa_signature *sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); + /** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of * extra entropy. @@ -383,32 +440,8 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_def * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) * - * The sig always has an s value in the lower half of the range (From 0x1 - * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, - * inclusive), unlike many other implementations. - * - * With ECDSA a third-party can can forge a second distinct signature - * of the same message given a single initial signature without knowing - * the key by setting s to its additive inverse mod-order, 'flipping' the - * sign of the random point R which is not included in the signature. - * Since the forgery is of the same message this isn't universally - * problematic, but in systems where message malleability or uniqueness - * of signatures is important this can cause issues. This forgery can be - * blocked by all verifiers forcing signers to use a canonical form. The - * lower-S form reduces the size of signatures slightly on average when - * variable length encodings (such as DER) are used and is cheap to - * verify, making it a good choice. Security of always using lower-S is - * assured because anyone can trivially modify a signature after the - * fact to enforce this property. Adjusting it inside the signing - * function avoids the need to re-serialize or have curve specific - * constants outside of the library. By always using a canonical form - * even in applications where it isn't needed it becomes possible to - * impose a requirement later if a need is discovered. - * No other forms of ECDSA malleability are known and none seem likely, - * but there is no formal proof that ECDSA, even with this additional - * restriction, is free of other malleability. Commonly used serialization - * schemes will also accept various non-unique encodings, so care should - * be taken when this property is required for an application. + * The created signature is always in lower-S form. See + * secp256k1_ecdsa_signature_normalize for more details. */ SECP256K1_API int secp256k1_ecdsa_sign( const secp256k1_context* ctx, diff --git a/src/secp256k1.c b/src/secp256k1.c index cb3dab853d2..9529d9f6bc2 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -256,6 +256,25 @@ int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, un return 1; } +int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) { + secp256k1_scalar r, s; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin); + ret = secp256k1_scalar_is_high(&s); + if (sigout != NULL) { + if (ret) { + secp256k1_scalar_negate(&s, &s); + } + secp256k1_ecdsa_signature_save(sigout, &r, &s); + } + + return ret; +} + int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { secp256k1_ge q; secp256k1_scalar r, s; @@ -268,7 +287,8 @@ int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_s secp256k1_scalar_set_b32(&m, msg32, NULL); secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); - return (secp256k1_pubkey_load(ctx, &q, pubkey) && + return (!secp256k1_scalar_is_high(&s) && + secp256k1_pubkey_load(ctx, &q, pubkey) && secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m)); } diff --git a/src/tests.c b/src/tests.c index c520d12615a..0e047173fff 100644 --- a/src/tests.c +++ b/src/tests.c @@ -2322,7 +2322,8 @@ void test_ecdsa_end_to_end(void) { unsigned char privkey[32]; unsigned char message[32]; unsigned char privkey2[32]; - secp256k1_ecdsa_signature signature[5]; + secp256k1_ecdsa_signature signature[6]; + secp256k1_scalar r, s; unsigned char sig[74]; size_t siglen = 74; unsigned char pubkeyc[65]; @@ -2409,6 +2410,21 @@ void test_ecdsa_end_to_end(void) { CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1); CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1); CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1); + /* Test lower-S form, malleate, verify and fail, test again, malleate again */ + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[0])); + secp256k1_ecdsa_signature_load(ctx, &r, &s, &signature[0]); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0); + CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + CHECK(memcmp(&signature[5], &signature[0], 64) == 0); /* Serialize/parse DER and verify again */ CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1);