{"record":{"id":"f33987900792515f","repo":"golang/go","slug":"sha3-invalid-hash-state-f33987","errorCode":null,"errorMessage":"sha3: invalid hash state","messagePattern":"sha3: invalid hash state","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/sha3/shake.go","lineNumber":110,"sourceCode":"\treturn &ret\n}\n\nfunc (s *SHAKE) MarshalBinary() ([]byte, error) {\n\treturn s.AppendBinary(make([]byte, 0, marshaledSize+len(s.initBlock)))\n}\n\nfunc (s *SHAKE) AppendBinary(b []byte) ([]byte, error) {\n\tb, err := s.d.AppendBinary(b)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tb = append(b, s.initBlock...)\n\treturn b, nil\n}\n\nfunc (s *SHAKE) UnmarshalBinary(b []byte) error {\n\tif len(b) < marshaledSize {\n\t\treturn errors.New(\"sha3: invalid hash state\")\n\t}\n\tif err := s.d.UnmarshalBinary(b[:marshaledSize]); err != nil {\n\t\treturn err\n\t}\n\ts.initBlock = bytes.Clone(b[marshaledSize:])\n\treturn nil\n}\n\n// NewShake128 creates a new SHAKE128 XOF.\nfunc NewShake128() *SHAKE {\n\treturn &SHAKE{d: Digest{rate: rateK256, outputLen: 32, dsbyte: dsbyteShake}}\n}\n\n// NewShake256 creates a new SHAKE256 XOF.\nfunc NewShake256() *SHAKE {\n\treturn &SHAKE{d: Digest{rate: rateK512, outputLen: 64, dsbyte: dsbyteShake}}\n}\n","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/sha3/shake.go#L92-L128","documentation":"Returned by SHAKE.UnmarshalBinary when the input is shorter than marshaledSize. SHAKE state is the inner sha3 Digest marshaled state plus a trailing initBlock (the cSHAKE/SHAKE prefix block); the SHAKE wrapper first checks the minimum length, then delegates the prefix to the inner Digest.UnmarshalBinary and clones the remainder into initBlock.","triggerScenarios":"Calling UnmarshalBinary on a SHAKE instance with a buffer shorter than the inner Digest's marshaledSize; e.g. passing plain SHA-3 state (no initBlock), passing a truncated buffer, or passing bytes from a non-SHAKE source.","commonSituations":"Storing SHAKE state without the initBlock suffix (older code path, hand-rolled serialization); buffer truncation in transit; confusion between SHAKE-128/256 inner-state size and the full SHAKE marshaled size.","solutions":["Always marshal/unmarshal SHAKE state through SHAKE's own AppendBinary/UnmarshalBinary so the initBlock is included.","Verify len(b) >= marshaledSize before calling; if not, re-XOF from scratch.","Tag persisted state with the XOF variant and validate length against the known SHAKE marshaled size."],"exampleFix":"// before\nshake.UnmarshalBinary(innerDigestBytesOnly) // too short -> error\n// after\nfull, _ := producer.AppendBinary(nil) // includes initBlock\nshake.UnmarshalBinary(full)","handlingStrategy":"validation","validationCode":"if len(b) < marshaledSize {\n    return fmt.Errorf(\"SHAKE state too short: got %d want >= %d\", len(b), marshaledSize)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Marshal/unmarshal SHAKE state through the SHAKE wrapper so the initBlock is included.","Persist the XOF variant name and validate the length against the known SHAKE marshaled size.","Use io.ReadFull and check its error when loading."],"tags":["crypto","hash","sha3","shake","serialization","go-stdlib"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}