The API doc for ecdsa_recover states the following:
/** Recover an ECDSA public key from a signature.
*
* Returns: 1: public key successfully recovered (which guarantees a correct signature).
* 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:
secp256k1_ecdsa_signature sig;
secp256k1_ecdsa_recoverable_signature rsig;
/* Set rsig to something */
/* ... */
if (secp256k1_ecdsa_recover(ctx, pubkey, rsig, msg)) {
secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
assert(secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey));
}
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
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!
The API doc for
ecdsa_recoverstates the following:After reading this, one may assume that when
ecdsa_recoversuccessfully recovers a pubkey,ecdsa_verifyon the same signature, message and public key will never fail. Or more precisely, the assertion in the following code snippet never fails:However, this is not true due to "s-malleability" of ECDSA signatures:
ecdsa_verifyrequires low-s whileecdsa_recoverdoes not. Thus, if we addafter the
ecdsa_recoverable_signature_convertcall in above code snipped, then the assertion never fails.In other words,
ecdsa_recoverreturning 1 does guarantee a correct signature, butecdsa_verifypasses only after the signature is normalized. We should document this fact more clearly.Thanks to @erickcestari for reporting this!