{"record":{"id":"64365d07296bb697","repo":"golang/go","slug":"p256-point-is-the-point-at-infinity-64365d","errorCode":null,"errorMessage":"P256 point is the point at infinity","messagePattern":"P256 point is the point at infinity","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/nistec/p256_asm.go","lineNumber":523,"sourceCode":"\tp256Mul(x, &p.x, x)\n\tp256Mul(y, &p.y, y)\n\n\tp256FromMont(x, x)\n\tp256FromMont(y, y)\n}\n\n// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,\n// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.\nfunc (p *P256Point) BytesX() ([]byte, error) {\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 [p256ElementLength]byte\n\treturn p.bytesX(&out)\n}\n\nfunc (p *P256Point) bytesX(out *[p256ElementLength]byte) ([]byte, error) {\n\tif p.isInfinity() == 1 {\n\t\treturn nil, errors.New(\"P256 point is the point at infinity\")\n\t}\n\n\tx := new(p256Element)\n\tp256Inverse(x, &p.z)\n\tp256Sqr(x, x, 1)\n\tp256Mul(x, &p.x, x)\n\tp256FromMont(x, x)\n\tp256LittleToBig((*[32]byte)(out[:]), x)\n\n\treturn out[:], nil\n}\n\n// BytesCompressed returns the compressed or infinity encoding of p, as\n// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the\n// point at infinity is shorter than all other encodings.\nfunc (p *P256Point) BytesCompressed() []byte {\n\t// This function is outlined to make the allocations inline in the caller\n\t// rather than happen on the heap.","sourceCodeStart":505,"sourceCodeEnd":541,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/nistec/p256_asm.go#L505-L541","documentation":"The same error as 400 but from the assembly-optimized P256Point implementation (p256_asm.go). BytesX() returns the SEC 1 x-coordinate encoding and rejects the identity point (detected via isInfinity() == 1). The asm path uses p256Inverse/p256Sqr/p256Mul/p256FromMont internally instead of fiat inversion, but the precondition is identical: the point must not be at infinity.","triggerScenarios":"Calling p.BytesX() on an asm-path P256Point that is the identity element (z is zero). Occurs after ScalarMult with a zero-reducing scalar, or on an uninitialized point.","commonSituations":"ECDH with an identity public key; ECDSA where the per-message nonce produces an infinity result; this is the same root cause as error 400 — only the internal implementation differs.","solutions":["Check p.Bytes() for the 1-byte 0x00 infinity encoding before calling BytesX","Validate ScalarMult results before coordinate extraction","Reject identity points at the protocol/peer-validation layer"],"exampleFix":"// before\nx, err := point.BytesX()\n\n// after\nif enc := point.Bytes(); len(enc) == 1 && enc[0] == 0 {\n    return errors.New(\"identity point has no x-coordinate\")\n}\nx, err := point.BytesX()","handlingStrategy":"validation","validationCode":"func mustNotBeInfinity(p *nistec.P256Point) error {\n    enc := p.Bytes()\n    if len(enc) == 1 && enc[0] == 0 {\n        return errors.New(\"point is identity\")\n    }\n    return nil\n}\n\nif err := mustNotBeInfinity(point); err != nil { return err }\nx, err := point.BytesX()","typeGuard":null,"tryCatchPattern":"x, err := point.BytesX()\nif err != nil {\n    return fmt.Errorf(\"cannot extract x-coordinate: %w\", err)\n}","preventionTips":["Check for the identity point before extracting any affine coordinate","In ECDH, validate the shared secret point is not infinity before using it","Ensure scalars are non-zero before scalar multiplication"],"tags":["crypto","fips140","p256","elliptic-curve","point-at-infinity","asm"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}