golang/go · error

sha3: invalid hash state function

Error message

sha3: invalid hash state function

What it means

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.

Source

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

	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")
	}
	d.state = state

	return nil
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Use the exact same output-size constructor on both ends (e.g. New256 with New256-produced bytes).
  2. If you changed the digest size, treat old persisted state as invalid and re-hash.
  3. Store the output size alongside the state and verify it before calling UnmarshalBinary.

Example fix

// before
d := sha3.New256() // rate 136
d.(*sha3.Digest).UnmarshalBinary(stateFromSHA3_512) // rate 72 -> error
// after
d := sha3.New512()
d.(*sha3.Digest).UnmarshalBinary(stateFromSHA3_512)
Defensive patterns

Strategy: validation

Validate before calling

wantRate := digestInstance.rate // inspect or expose on your type
if int(b[0]) != wantRate {
    return errors.New("marshaled state belongs to a different SHA-3 output size")
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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