golang/go · error

sha3: invalid hash state identifier

Error message

sha3: invalid hash state identifier

What it means

Returned in the default branch of the magic/dsbyte switch in sha3 Digest.UnmarshalBinary. The state's stored magic (magicSHA3, magicShake, magicCShake, magicKeccak) must match the digest instance's preconfigured dsbyte (dsbyteSHA3, dsbyteShake, dsbyteCShake, dsbyteKeccak). A mismatch means the bytes belong to a different SHA-3 family member than the digest instance was constructed for.

Source

Thrown at src/crypto/internal/fips140/sha3/sha3.go:210

	b = append(b, d.a[:]...)
	b = append(b, byte(d.n), byte(d.state))
	return b, nil
}

func (d *Digest) UnmarshalBinary(b []byte) error {
	if len(b) != marshaledSize {
		return errors.New("sha3: invalid hash state")
	}

	magic := string(b[:len(magicSHA3)])
	b = b[len(magicSHA3):]
	switch {
	case magic == magicSHA3 && d.dsbyte == dsbyteSHA3:
	case magic == magicShake && d.dsbyte == dsbyteShake:
	case magic == magicCShake && d.dsbyte == dsbyteCShake:
	case magic == magicKeccak && d.dsbyte == dsbyteKeccak:
	default:
		return errors.New("sha3: invalid hash state identifier")
	}

	rate := int(b[0])
	b = b[1:]
	if rate != d.rate {
		return errors.New("sha3: invalid hash state function")
	}

	copy(d.a[:], b)
	b = b[len(d.a):]

	n, state := int(b[0]), spongeDirection(b[1])
	if n > d.rate {
		return errors.New("sha3: invalid hash state")
	}
	d.n = n
	if state != spongeAbsorbing && state != spongeSqueezing {
		return errors.New("sha3: invalid hash state")

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Always construct the Digest via the package constructor (New224, New256, NewShake128, etc.) matching the original producer.
  2. If crossing variants, re-hash from the original input.
  3. Tag persisted state with the variant name and dispatch to the matching constructor before UnmarshalBinary.
  4. Never instantiate Digest{} literally with a zero dsbyte and then call UnmarshalBinary.

Example fix

// before
d := sha3.Digest{} // zero dsbyte -> default branch
d.UnmarshalBinary(b)
// after
d := sha3.New224() // constructs digest with dsbyteSHA3 + 224 rate
d.(*sha3.Digest).UnmarshalBinary(b)
Defensive patterns

Strategy: validation

Validate before calling

// ensure the digest instance was constructed with the matching variant
switch string(b[:len(magicSHAKE)]) {
case magicSHA3, magicShake, magicCShake, magicKeccak:
default:
    return errors.New("bytes are not any SHA-3 family state")
}

Prevention

When it happens

Trigger: Calling UnmarshalBinary on a SHAKE digest with bytes marshaled by a plain SHA3-256 digest; on a cSHAKE digest with SHAKE bytes; on a Keccak digest with SHA3 bytes; or on a freshly zero-value Digest whose dsbyte does not match any producer.

Common situations: Code that creates a zero-value Digest{} directly instead of via New224/New256/NewLegacyKeccak256/etc.; mixing SHAKE (extendable output) and fixed-output SHA-3 state in the same persistence layer; a refactor that changed the digest constructor but not the persisted state.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/97e57d9a9ed3088e. Report an issue: GitHub.