{"record":{"id":"55e6c18c4d513bb0","repo":"golang/go","slug":"ecdsa-signature-did-not-verify","errorCode":null,"errorMessage":"ecdsa: signature did not verify","messagePattern":"ecdsa: signature did not verify","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/ecdsa/ecdsa.go","lineNumber":514,"sourceCode":"\t}\n\t// p₂ = [r * s⁻¹]Q\n\tp2, err := Q.ScalarMult(Q, w.Mul(r, c.N).Bytes(c.N))\n\tif err != nil {\n\t\treturn err\n\t}\n\t// BytesX returns an error for the point at infinity.\n\tRx, err := p1.Add(p1, p2).BytesX()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tv, err := bigmod.NewNat().SetOverflowingBytes(Rx, c.N)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif v.Equal(r) != 1 {\n\t\treturn errors.New(\"ecdsa: signature did not verify\")\n\t}\n\treturn nil\n}\n","sourceCodeStart":496,"sourceCodeEnd":518,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/ecdsa/ecdsa.go#L496-L518","documentation":"Thrown by the ECDSA verifier when the recomputed x-coordinate of the point R = [u1]G + [u2]Q does not equal the signature's r (v.Equal(r) != 1). This is the final verdict that the signature is not valid for the given key and hash under FIPS 186-5 §6.4.2. Any earlier structural failure (zero r/s, bad point, curve mismatch) returns a different error; this one means the math checked out but the signature is wrong.","triggerScenarios":"Verifying a signature produced with a different private key, over a different message/hash, with a tampered r or s, for the wrong curve, or after any byte-level corruption of key/hash/signature.","commonSituations":"Wrong public key paired with the signature, mismatched hash function between signer and verifier, message alteration, or a deliberately forged signature.","solutions":["Confirm signer and verifier use the same hash function and curve.","Confirm the public key is the counterpart of the signing private key.","Confirm the message bytes hashed at both ends are identical (no re-encoding).","Treat this as an authentication failure: do not retry blindly; surface it to the caller."],"exampleFix":"// before\nif err := ecdsa.Verify(curve, pub, hash, sig); err != nil {\n    // generic failure\n}\n\n// after: distinguish causes before calling Verify\nif pub.Curve() != signerCurve { return ErrCurveMismatch }\nif !bytes.Equal(hash, expectedDigest) { return ErrHashMismatch }\nif err := ecdsa.Verify(curve, pub, hash, sig); err != nil {\n    return ErrInvalidSignature // genuine verification failure\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check the deterministic causes of verification mismatch.\nif pub.Curve() != signerCurve { return ErrCurveMismatch }\nif len(hash) == 0 { return ErrEmptyHash }\nif allZero(sig.R) || allZero(sig.S) { return ErrMalformedSignature }\n// Remaining failures are genuine: wrong key, message, or signature.","typeGuard":"func verifyInputsPlausible(pub *ecdsa.PublicKey, hash []byte, sig *ecdsa.Signature) bool {\n    return len(hash) > 0 && !allZero(sig.R) && !allZero(sig.S)\n}","tryCatchPattern":"if err := ecdsa.Verify(c, pub, hash, sig); err != nil {\n    // Distinguish structural errors from the final verdict if needed,\n    // but for 'signature did not verify' the correct action is to reject.\n    return ErrAuthenticationFailed\n}","preventionTips":["Pin the hash function and curve at both signer and verifier.","Bind the public key to the identity that produced the signature.","Hash the canonical (identically-encoded) message on both sides.","Never retry verification with mutated inputs to 'make it pass'."],"tags":["go","crypto","fips","ecdsa","verification","signature"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}