{"record":{"id":"4e8d382fd8b35705","repo":"golang/go","slug":"invalid-p256-compressed-point-encoding","errorCode":null,"errorMessage":"invalid P256 compressed point encoding","messagePattern":"invalid P256 compressed point encoding","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/nistec/p256.go","lineNumber":96,"sourceCode":"\t\tif err := p256CheckOnCurve(x, y); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tp.x.Set(x)\n\t\tp.y.Set(y)\n\t\tp.z.One()\n\t\treturn p, nil\n\n\t// Compressed form.\n\tcase len(b) == p256CompressedLength && (b[0] == 2 || b[0] == 3):\n\t\tx, err := new(fiat.P256Element).SetBytes(b[1:])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// y² = x³ - 3x + b\n\t\ty := p256Polynomial(new(fiat.P256Element), x)\n\t\tif !p256Sqrt(y, y) {\n\t\t\treturn nil, errors.New(\"invalid P256 compressed point encoding\")\n\t\t}\n\n\t\t// Select the positive or negative root, as indicated by the least\n\t\t// significant bit, based on the encoding type byte.\n\t\totherRoot := new(fiat.P256Element)\n\t\totherRoot.Sub(otherRoot, y)\n\t\tcond := y.Bytes()[p256ElementLength-1]&1 ^ b[0]&1\n\t\ty.Select(otherRoot, y, int(cond))\n\n\t\tp.x.Set(x)\n\t\tp.y.Set(y)\n\t\tp.z.One()\n\t\treturn p, nil\n\n\tdefault:\n\t\treturn nil, errors.New(\"invalid P256 point encoding\")\n\t}\n}","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/nistec/p256.go#L78-L114","documentation":"Concrete P-256 instance of the generated compressed-point error (generate.go:223 expanded into p256.go:96). Thrown when decompressing a SEC1 compressed P-256 point (type byte 0x02/0x03, length 1+32) whose x-coordinate yields no valid y (x^3-3x+b not a quadratic residue mod the P-256 prime).","triggerScenarios":"Compressed P-256 point whose x is off-curve, an x byte-swapped or end-flipped, or a compressed encoding sized for a different curve passed to the P-256 parser.","commonSituations":"Fuzzed/adversarial public keys, cross-curve mix-ups, transit corruption, or a copy-paste of a P-384 compressed point.","solutions":["Reject malformed compressed P-256 points from untrusted sources with explicit error handling.","Verify len(b) == 33 and b[0] in {2,3} before calling SetBytes.","Re-serialize the point from a known-good P-256 point via BytesCompressed and compare.","If decompressing from raw x, prefer the curve's own SetBytes to apply the constant-time validation."],"exampleFix":"// before\np, err := nistec.NewP256Point().SetBytes(b) // b corrupted\n// after\nif len(b) != 33 || (b[0] != 2 && b[0] != 3) {\n    return errors.New(\"not a compressed P-256 point\")\n}\np, err := nistec.NewP256Point().SetBytes(b)\nif err != nil { return fmt.Errorf(\"off-curve: %w\", err) }","handlingStrategy":"validation","validationCode":"// Validate compressed P-256 shape before SetBytes.\nif len(b) != 33 || (b[0] != 2 && b[0] != 3) {\n    return errors.New(\"not a compressed P-256 point\")\n}","typeGuard":"func isCompressedP256(b []byte) bool {\n    return len(b) == 33 && (b[0] == 2 || b[0] == 3)\n}","tryCatchPattern":"p, err := nistec.NewP256Point().SetBytes(b)\nif err != nil {\n    return fmt.Errorf(\"P-256 decompression failed (len=%d): %w\", len(b), err)\n}","preventionTips":["Reject malformed compressed P-256 points from untrusted peers explicitly.","Verify length and prefix byte before calling SetBytes.","Re-encode from a known-good point and diff suspect inputs."],"tags":["elliptic-curve","fips140","crypto","nistec","p256","point-parsing","sec1"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}