{"record":{"id":"744b5e8a8666e825","repo":"golang/go","slug":"sha3-invalid-hash-state-function","errorCode":null,"errorMessage":"sha3: invalid hash state function","messagePattern":"sha3: invalid hash state function","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/sha3/sha3.go","lineNumber":216,"sourceCode":"\tif len(b) != marshaledSize {\n\t\treturn errors.New(\"sha3: invalid hash state\")\n\t}\n\n\tmagic := string(b[:len(magicSHA3)])\n\tb = b[len(magicSHA3):]\n\tswitch {\n\tcase magic == magicSHA3 && d.dsbyte == dsbyteSHA3:\n\tcase magic == magicShake && d.dsbyte == dsbyteShake:\n\tcase magic == magicCShake && d.dsbyte == dsbyteCShake:\n\tcase magic == magicKeccak && d.dsbyte == dsbyteKeccak:\n\tdefault:\n\t\treturn errors.New(\"sha3: invalid hash state identifier\")\n\t}\n\n\trate := int(b[0])\n\tb = b[1:]\n\tif rate != d.rate {\n\t\treturn errors.New(\"sha3: invalid hash state function\")\n\t}\n\n\tcopy(d.a[:], b)\n\tb = b[len(d.a):]\n\n\tn, state := int(b[0]), spongeDirection(b[1])\n\tif n > d.rate {\n\t\treturn errors.New(\"sha3: invalid hash state\")\n\t}\n\td.n = n\n\tif state != spongeAbsorbing && state != spongeSqueezing {\n\t\treturn errors.New(\"sha3: invalid hash state\")\n\t}\n\td.state = state\n\n\treturn nil\n}\n","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/sha3/sha3.go#L198-L234","documentation":"Returned by sha3 Digest.UnmarshalBinary when the rate byte embedded in the marshaled state does not equal the digest instance's configured rate. The rate (block size in bytes) is what distinguishes SHA3-224 (rate 144), SHA3-256 (rate 136), SHA3-384 (rate 104), SHA3-512 (rate 72), and the SHAKE variants. A mismatch means the bytes belong to a different output size of the family even if the magic matched.","triggerScenarios":"Calling UnmarshalBinary on a SHA3-256 digest with state produced by a SHA3-512 digest (both use dsbyteSHA3 / magicSHA3, so they pass the magic check but differ in rate); or on a SHAKE128 with SHAKE256 state.","commonSituations":"Switching the application from SHA3-256 to SHA3-512 (or between SHAKE128 and SHAKE256) without invalidating previously persisted hash state; constructor-vs-producer mismatch on output size.","solutions":["Use the exact same output-size constructor on both ends (e.g. New256 with New256-produced bytes).","If you changed the digest size, treat old persisted state as invalid and re-hash.","Store the output size alongside the state and verify it before calling UnmarshalBinary."],"exampleFix":"// before\nd := sha3.New256() // rate 136\nd.(*sha3.Digest).UnmarshalBinary(stateFromSHA3_512) // rate 72 -> error\n// after\nd := sha3.New512()\nd.(*sha3.Digest).UnmarshalBinary(stateFromSHA3_512)","handlingStrategy":"validation","validationCode":"wantRate := digestInstance.rate // inspect or expose on your type\nif int(b[0]) != wantRate {\n    return errors.New(\"marshaled state belongs to a different SHA-3 output size\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use the same output-size constructor on both ends (New256 with New256 bytes, etc.).","When changing digest size, invalidate previously persisted state.","Store the output size alongside the marshaled state and verify before UnmarshalBinary."],"tags":["crypto","hash","sha3","serialization","go-stdlib"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}