The API doc for ecdsa_recover
states the following:
0/** Recover an ECDSA public key from a signature.
1 *
2 * Returns: 1: public key successfully recovered (which guarantees a correct signature).
3 * 0: otherwise.
After reading this, one may assume that when ecdsa_recover
successfully recovers a pubkey, ecdsa_verify
on the same signature, message and public key will never fail. Or more precisely, the assertion in the following code snippet never fails:
0secp256k1_ecdsa_signature sig;
1secp256k1_ecdsa_recoverable_signature rsig;
2
3/* Set rsig to something */
4/* ... */
5
6if (secp256k1_ecdsa_recover(ctx, pubkey, rsig, msg)) {
7 secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
8 assert(secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey));
9
10}
However, this is not true due to “s-malleability” of ECDSA signatures: ecdsa_verify
requires low-s while ecdsa_recover
does not. Thus, if we add
0 secp256k1_ecdsa_signature_normalize(CTX, &sig, &sig);
after the ecdsa_recoverable_signature_convert
call in above code snipped, then the assertion never fails.
In other words, ecdsa_recover
returning 1 does guarantee a correct signature, but ecdsa_verify
passes only after the signature is normalized. We should document this fact more clearly.
Thanks to @erickcestari for reporting this!