1// Copyright 2014 The Go Authors. All rights reserved.
  2// Use of this source code is governed by a BSD-style
  3// license that can be found in the LICENSE file.
  4
  5package sha3
  6
  7import (
  8	"crypto/sha3"
  9	"hash"
 10	"io"
 11)
 12
 13// ShakeHash defines the interface to hash functions that support
 14// arbitrary-length output. When used as a plain [hash.Hash], it
 15// produces minimum-length outputs that provide full-strength generic
 16// security.
 17type ShakeHash interface {
 18	hash.Hash
 19
 20	// Read reads more output from the hash; reading affects the hash's
 21	// state. (ShakeHash.Read is thus very different from Hash.Sum.)
 22	// It never returns an error, but subsequent calls to Write or Sum
 23	// will panic.
 24	io.Reader
 25
 26	// Clone returns a copy of the ShakeHash in its current state.
 27	Clone() ShakeHash
 28}
 29
 30// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
 31// Its generic security strength is 128 bits against all attacks if at
 32// least 32 bytes of its output are used.
 33func NewShake128() ShakeHash {
 34	return &shakeWrapper{sha3.NewSHAKE128(), 32, false, sha3.NewSHAKE128}
 35}
 36
 37// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
 38// Its generic security strength is 256 bits against all attacks if
 39// at least 64 bytes of its output are used.
 40func NewShake256() ShakeHash {
 41	return &shakeWrapper{sha3.NewSHAKE256(), 64, false, sha3.NewSHAKE256}
 42}
 43
 44// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
 45// a customizable variant of SHAKE128.
 46// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
 47// desired. S is a customization byte string used for domain separation - two cSHAKE
 48// computations on same input with different S yield unrelated outputs.
 49// When N and S are both empty, this is equivalent to NewShake128.
 50func NewCShake128(N, S []byte) ShakeHash {
 51	return &shakeWrapper{sha3.NewCSHAKE128(N, S), 32, false, func() *sha3.SHAKE {
 52		return sha3.NewCSHAKE128(N, S)
 53	}}
 54}
 55
 56// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
 57// a customizable variant of SHAKE256.
 58// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
 59// desired. S is a customization byte string used for domain separation - two cSHAKE
 60// computations on same input with different S yield unrelated outputs.
 61// When N and S are both empty, this is equivalent to NewShake256.
 62func NewCShake256(N, S []byte) ShakeHash {
 63	return &shakeWrapper{sha3.NewCSHAKE256(N, S), 64, false, func() *sha3.SHAKE {
 64		return sha3.NewCSHAKE256(N, S)
 65	}}
 66}
 67
 68// ShakeSum128 writes an arbitrary-length digest of data into hash.
 69func ShakeSum128(hash, data []byte) {
 70	h := NewShake128()
 71	h.Write(data)
 72	h.Read(hash)
 73}
 74
 75// ShakeSum256 writes an arbitrary-length digest of data into hash.
 76func ShakeSum256(hash, data []byte) {
 77	h := NewShake256()
 78	h.Write(data)
 79	h.Read(hash)
 80}
 81
 82// shakeWrapper adds the Size, Sum, and Clone methods to a sha3.SHAKE
 83// to implement the ShakeHash interface.
 84type shakeWrapper struct {
 85	*sha3.SHAKE
 86	outputLen int
 87	squeezing bool
 88	newSHAKE  func() *sha3.SHAKE
 89}
 90
 91func (w *shakeWrapper) Read(p []byte) (n int, err error) {
 92	w.squeezing = true
 93	return w.SHAKE.Read(p)
 94}
 95
 96func (w *shakeWrapper) Clone() ShakeHash {
 97	s := w.newSHAKE()
 98	b, err := w.MarshalBinary()
 99	if err != nil {
100		panic(err) // unreachable
101	}
102	if err := s.UnmarshalBinary(b); err != nil {
103		panic(err) // unreachable
104	}
105	return &shakeWrapper{s, w.outputLen, w.squeezing, w.newSHAKE}
106}
107
108func (w *shakeWrapper) Size() int { return w.outputLen }
109
110func (w *shakeWrapper) Sum(b []byte) []byte {
111	if w.squeezing {
112		panic("sha3: Sum after Read")
113	}
114	out := make([]byte, w.outputLen)
115	// Clone the state so that we don't affect future Write calls.
116	s := w.Clone()
117	s.Read(out)
118	return append(b, out...)
119}