// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package sha3 import ( "crypto/sha3" "hash" "io" ) // ShakeHash defines the interface to hash functions that support // arbitrary-length output. When used as a plain [hash.Hash], it // produces minimum-length outputs that provide full-strength generic // security. type ShakeHash interface { hash.Hash // Read reads more output from the hash; reading affects the hash's // state. (ShakeHash.Read is thus very different from Hash.Sum.) // It never returns an error, but subsequent calls to Write or Sum // will panic. io.Reader // Clone returns a copy of the ShakeHash in its current state. Clone() ShakeHash } // NewShake128 creates a new SHAKE128 variable-output-length ShakeHash. // Its generic security strength is 128 bits against all attacks if at // least 32 bytes of its output are used. func NewShake128() ShakeHash { return &shakeWrapper{sha3.NewSHAKE128(), 32, false, sha3.NewSHAKE128} } // NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. // Its generic security strength is 256 bits against all attacks if // at least 64 bytes of its output are used. func NewShake256() ShakeHash { return &shakeWrapper{sha3.NewSHAKE256(), 64, false, sha3.NewSHAKE256} } // NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash, // a customizable variant of SHAKE128. // N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is // desired. S is a customization byte string used for domain separation - two cSHAKE // computations on same input with different S yield unrelated outputs. // When N and S are both empty, this is equivalent to NewShake128. func NewCShake128(N, S []byte) ShakeHash { return &shakeWrapper{sha3.NewCSHAKE128(N, S), 32, false, func() *sha3.SHAKE { return sha3.NewCSHAKE128(N, S) }} } // NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash, // a customizable variant of SHAKE256. // N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is // desired. S is a customization byte string used for domain separation - two cSHAKE // computations on same input with different S yield unrelated outputs. // When N and S are both empty, this is equivalent to NewShake256. func NewCShake256(N, S []byte) ShakeHash { return &shakeWrapper{sha3.NewCSHAKE256(N, S), 64, false, func() *sha3.SHAKE { return sha3.NewCSHAKE256(N, S) }} } // ShakeSum128 writes an arbitrary-length digest of data into hash. func ShakeSum128(hash, data []byte) { h := NewShake128() h.Write(data) h.Read(hash) } // ShakeSum256 writes an arbitrary-length digest of data into hash. func ShakeSum256(hash, data []byte) { h := NewShake256() h.Write(data) h.Read(hash) } // shakeWrapper adds the Size, Sum, and Clone methods to a sha3.SHAKE // to implement the ShakeHash interface. type shakeWrapper struct { *sha3.SHAKE outputLen int squeezing bool newSHAKE func() *sha3.SHAKE } func (w *shakeWrapper) Read(p []byte) (n int, err error) { w.squeezing = true return w.SHAKE.Read(p) } func (w *shakeWrapper) Clone() ShakeHash { s := w.newSHAKE() b, err := w.MarshalBinary() if err != nil { panic(err) // unreachable } if err := s.UnmarshalBinary(b); err != nil { panic(err) // unreachable } return &shakeWrapper{s, w.outputLen, w.squeezing, w.newSHAKE} } func (w *shakeWrapper) Size() int { return w.outputLen } func (w *shakeWrapper) Sum(b []byte) []byte { if w.squeezing { panic("sha3: Sum after Read") } out := make([]byte, w.outputLen) // Clone the state so that we don't affect future Write calls. s := w.Clone() s.Read(out) return append(b, out...) }