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 5 package sha3
6 7 import (
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.
17 type 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.
33 func 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.
40 func 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.
50 func 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.
62 func 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.
69 func 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.
76 func 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.
84 type shakeWrapper struct {
85 *sha3.SHAKE
86 outputLen int
87 squeezing bool
88 newSHAKE func() *sha3.SHAKE
89 }
90 91 func (w *shakeWrapper) Read(p []byte) (n int, err error) {
92 w.squeezing = true
93 return w.SHAKE.Read(p)
94 }
95 96 func (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 108 func (w *shakeWrapper) Size() int { return w.outputLen }
109 110 func (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 }
120