{"record":{"id":"0486f691bf4355de","repo":"golang/go","slug":"p-point-not-on-curve","errorCode":null,"errorMessage":"{{.P}} point not on curve","messagePattern":"(.+?)\\} point not on curve","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/nistec/generate.go","lineNumber":271,"sourceCode":"\n// {{.p}}Polynomial sets y2 to x³ - 3x + b, and returns y2.\nfunc {{.p}}Polynomial(y2, x *{{.Element}}) *{{.Element}} {\n\ty2.Square(x)\n\ty2.Mul(y2, x)\n\n\tthreeX := new({{.Element}}).Add(x, x)\n\tthreeX.Add(threeX, x)\n\ty2.Sub(y2, threeX)\n\n\treturn y2.Add(y2, {{.p}}B())\n}\n\nfunc {{.p}}CheckOnCurve(x, y *{{.Element}}) error {\n\t// y² = x³ - 3x + b\n\trhs := {{.p}}Polynomial(new({{.Element}}), x)\n\tlhs := new({{.Element}}).Square(y)\n\tif rhs.Equal(lhs) != 1 {\n\t\treturn errors.New(\"{{.P}} point not on curve\")\n\t}\n\treturn nil\n}\n\n// Bytes returns the uncompressed or infinity encoding of p, as specified in\n// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at\n// infinity is shorter than all other encodings.\nfunc (p *{{.P}}Point) Bytes() []byte {\n\t// This function is outlined to make the allocations inline in the caller\n\t// rather than happen on the heap.\n\tvar out [1+2*{{.p}}ElementLength]byte\n\treturn p.bytes(&out)\n}\n\nfunc (p *{{.P}}Point) bytes(out *[1+2*{{.p}}ElementLength]byte) []byte {\n\tif p.z.IsZero() == 1 {\n\t\treturn append(out[:0], 0)\n\t}","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/nistec/generate.go#L253-L289","documentation":"Generated from generate.go:271. Thrown by {{p}}CheckOnCurve when, for a candidate affine (x,y), y^2 != x^3 - 3x + b. The point fails the curve equation; it is not a valid member of the group.","triggerScenarios":"Passing an (x,y) pair where one coordinate was corrupted, an (x,y) from a different curve, or an uncompressed point whose y was reconstructed incorrectly. Triggered during explicit on-curve verification (not during SetBytes, which already validates).","commonSituations":"Cross-curve confusion (P-384 point checked against P-256 equation), tampered public key, manual point arithmetic that bypassed the curve's invariants, or test data with a transposed coordinate.","solutions":["Confirm the (x,y) coordinates came from the same curve as the check function.","Re-obtain the point from a trusted serialized form via SetBytes which validates internally.","For externally supplied public keys, run CheckOnCurve and reject on error; do not attempt repair.","Verify intermediate results of custom scalar multiplication against the curve's own Add/ScalarMult, not hand-rolled field ops."],"exampleFix":"// before\nif err := nistec.NewP256Point()./*manual*/; ... // coords hand-assembled\n// after (parse through the validated path)\np, err := nistec.NewP256Point().SetBytes(sec1)\nif err != nil { return fmt.Errorf(\"invalid point: %w\", err) }\n// SetBytes already enforces on-curve; no separate CheckOnCurve needed","handlingStrategy":"try-catch","validationCode":"// Prefer the validated point parser; explicit CheckOnCurve is rarely needed.\np, err := curve.NewPoint().SetBytes(sec1)\nif err != nil { return err }","typeGuard":"func pointOnCurve(p *nistec.P256Point) bool {\n    // SetBytes already enforces on-curve; this is a defensive secondary check.\n    return p.Bytes()[0] != 0 || /* infinity allowed */ true\n}","tryCatchPattern":"if err := nistecCheckOnCurve(x, y); err != nil {\n    return fmt.Errorf(\"point not on curve: %w\", err)\n}","preventionTips":["Route externally supplied points through SetBytes which enforces on-curve.","Confirm the (x,y) pair originates from the same curve as the check.","Avoid hand-rolled field arithmetic for point math."],"tags":["elliptic-curve","fips140","crypto","nistec","point-validation","code-generation"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}