{"record":{"id":"aa7d8b32df97f74f","repo":"golang/go","slug":"p256-point-not-on-curve-aa7d8b","errorCode":null,"errorMessage":"P256 point not on curve","messagePattern":"P256 point not on curve","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/crypto/internal/fips140/nistec/p256_asm.go","lineNumber":164,"sourceCode":"\tp256NegCond(threeX, 1)\n\n\tp256B := &p256Element{0xd89cdf6229c4bddf, 0xacf005cd78843090,\n\t\t0xe5a220abf7212ed6, 0xdc30061d04874834}\n\n\tp256Add(x3, x3, threeX)\n\tp256Add(x3, x3, p256B)\n\n\t*y2 = *x3\n\treturn y2\n}\n\nfunc p256CheckOnCurve(x, y *p256Element) error {\n\t// y² = x³ - 3x + b\n\trhs := p256Polynomial(new(p256Element), x)\n\tlhs := new(p256Element)\n\tp256Sqr(lhs, y, 1)\n\tif p256Equal(lhs, rhs) != 1 {\n\t\treturn errors.New(\"P256 point not on curve\")\n\t}\n\treturn nil\n}\n\n// p256LessThanP returns 1 if x < p, and 0 otherwise. Note that a p256Element is\n// not allowed to be equal to or greater than p, so if this function returns 0\n// then x is invalid.\nfunc p256LessThanP(x *p256Element) int {\n\tvar b uint64\n\t_, b = bits.Sub64(x[0], p256P[0], b)\n\t_, b = bits.Sub64(x[1], p256P[1], b)\n\t_, b = bits.Sub64(x[2], p256P[2], b)\n\t_, b = bits.Sub64(x[3], p256P[3], b)\n\treturn int(b)\n}\n\nfunc p256BigToLittle(l *p256Element, b *[32]byte) {\n\tbytesToLimbs((*[4]uint64)(l), b)","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/nistec/p256_asm.go#L146-L182","documentation":"After decoding an uncompressed P-256 point's x and y coordinates (both individually < p), p256CheckOnCurve verifies the curve equation y² == x³ - 3x + b over the field. If the equation does not hold, the (x,y) pair is not a point on P-256, even though each coordinate passed its individual range check. This is a critical cryptographic validity check that prevents invalid-curve attacks.","triggerScenarios":"Calling SetBytes with a 65-byte uncompressed point where x and y are both valid field elements (< p) but their combination does not satisfy y² = x³ - 3x + b mod p.","commonSituations":"Adversarially crafted public keys designed for invalid-curve attacks; corrupted key material where the corruption happens to keep each coordinate < p; manually assembling x and y from independent sources that don't correspond to the same point.","solutions":["Reject the input key — it is not a valid P-256 point","Re-obtain the key from a trusted, authenticated source","Always validate points before use in cryptographic operations (the library does this automatically via SetBytes)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"_, err := point.SetBytes(b)\nif err != nil {\n    // Point failed on-curve check — possible invalid-curve attack.\n    // Log the event and reject the key.\n    log.Printf(\"rejected off-curve P-256 point: %v\", err)\n    return fmt.Errorf(\"invalid P-256 point: %w\", err)\n}","preventionTips":["Treat off-curve point rejections as potential attacks, not just data errors","Always validate points via SetBytes before any scalar multiplication","Use high-level APIs (crypto/ecdh, crypto/ecdsa) that never skip validation"],"tags":["crypto","fips140","p256","elliptic-curve","on-curve-check","invalid-curve-attack"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}