{"record":{"id":"05600410e2ab0f90","repo":"golang/go","slug":"invalid-p256-compressed-point-encoding-056004","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_asm.go","lineNumber":119,"sourceCode":"\t\tif err := p256CheckOnCurve(&r.x, &r.y); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tr.z = p256One\n\t\treturn p.Set(&r), nil\n\n\t// Compressed form.\n\tcase len(b) == p256CompressedLength && (b[0] == 2 || b[0] == 3):\n\t\tvar r P256Point\n\t\tp256BigToLittle(&r.x, (*[32]byte)(b[1:33]))\n\t\tif p256LessThanP(&r.x) == 0 {\n\t\t\treturn nil, errors.New(\"invalid P256 element encoding\")\n\t\t}\n\t\tp256Mul(&r.x, &r.x, &rr)\n\n\t\t// y² = x³ - 3x + b\n\t\tp256Polynomial(&r.y, &r.x)\n\t\tif !p256Sqrt(&r.y, &r.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\tyy := new(p256Element)\n\t\tp256FromMont(yy, &r.y)\n\t\tcond := int(yy[0]&1) ^ int(b[0]&1)\n\t\tp256NegCond(&r.y, cond)\n\n\t\tr.z = p256One\n\t\treturn p.Set(&r), nil\n\n\tdefault:\n\t\treturn nil, errors.New(\"invalid P256 point encoding\")\n\t}\n}\n\n// p256Polynomial sets y2 to x³ - 3x + b, and returns y2.","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/nistec/p256_asm.go#L101-L137","documentation":"When decompressing a P-256 point, the library computes y² = x³ - 3x + b and attempts to extract a square root via p256Sqrt. If p256Sqrt returns false, the value is not a quadratic residue mod p, meaning no valid y exists for the given x and the point is not on the curve. The encoding is therefore invalid.","triggerScenarios":"Calling P256Point.SetBytes with a compressed point whose x coordinate does not correspond to any actual point on the P-256 curve — i.e., x³ - 3x + b is a quadratic non-residue mod p.","commonSituations":"Random or fabricated data passed as a compressed public key; an x coordinate from a different curve (e.g., secp256k1) mistakenly used with P-256; bit-flip corruption in the x field.","solutions":["Reject the peer's public key and request a valid one","Verify the key was generated for the correct curve (P-256/secp256r1/prime256v1)","Use crypto/ecdsa.UnmarshalCompressed or ecdh.P256().NewPublicKey which propagate this error for proper handling"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"_, err := point.SetBytes(b)\nif err != nil {\n    // The compressed x-coordinate does not yield a valid curve point.\n    // This key is invalid or forged; do not use it.\n    return fmt.Errorf(\"invalid compressed point (no valid y): %w\", err)\n}","preventionTips":["Reject peer public keys that fail decompression — they may be adversarial","Verify the curve parameter (P-256) matches what the peer claims","Always use the library's SetBytes which performs full validation rather than manual decompression"],"tags":["crypto","fips140","p256","elliptic-curve","compressed-point","quadratic-residue"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}