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 // This file defines the ShakeHash interface, and provides 8 // functions for creating SHAKE and cSHAKE instances, as well as utility 9 // functions for hashing bytes to arbitrary-length output. 10 // 11 // 12 // SHAKE implementation is based on FIPS PUB 202 [1] 13 // cSHAKE implementations is based on NIST SP 800-185 [2] 14 // 15 // [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf 16 // [2] https://doi.org/10.6028/NIST.SP.800-185 17 18 import ( 19 "encoding/binary" 20 "hash" 21 "io" 22 ) 23 24 // ShakeHash defines the interface to hash functions that support 25 // arbitrary-length output. When used as a plain [hash.Hash], it 26 // produces minimum-length outputs that provide full-strength generic 27 // security. 28 type ShakeHash interface { 29 hash.Hash 30 31 // Read reads more output from the hash; reading affects the hash's 32 // state. (ShakeHash.Read is thus very different from Hash.Sum) 33 // It never returns an error, but subsequent calls to Write or Sum 34 // will panic. 35 io.Reader 36 37 // Clone returns a copy of the ShakeHash in its current state. 38 Clone() ShakeHash 39 } 40 41 // cSHAKE specific context 42 type cshakeState struct { 43 *state // SHA-3 state context and Read/Write operations 44 45 // initBlock is the cSHAKE specific initialization set of bytes. It is initialized 46 // by newCShake function and stores concatenation of N followed by S, encoded 47 // by the method specified in 3.3 of [1]. 48 // It is stored here in order for Reset() to be able to put context into 49 // initial state. 50 initBlock []byte 51 } 52 53 // Consts for configuring initial SHA-3 state 54 const ( 55 dsbyteShake = 0x1f 56 dsbyteCShake = 0x04 57 rate128 = 168 58 rate256 = 136 59 ) 60 61 func bytepad(input []byte, w int) []byte { 62 // leftEncode always returns max 9 bytes 63 buf := make([]byte, 0, 9+len(input)+w) 64 buf = append(buf, leftEncode(uint64(w))...) 65 buf = append(buf, input...) 66 padlen := w - (len(buf) % w) 67 return append(buf, make([]byte, padlen)...) 68 } 69 70 func leftEncode(value uint64) []byte { 71 var b [9]byte 72 binary.BigEndian.PutUint64(b[1:], value) 73 // Trim all but last leading zero bytes 74 i := byte(1) 75 for i < 8 && b[i] == 0 { 76 i++ 77 } 78 // Prepend number of encoded bytes 79 b[i-1] = 9 - i 80 return b[i-1:] 81 } 82 83 func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash { 84 c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}} 85 86 // leftEncode returns max 9 bytes 87 c.initBlock = make([]byte, 0, 9*2+len(N)+len(S)) 88 c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...) 89 c.initBlock = append(c.initBlock, N...) 90 c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...) 91 c.initBlock = append(c.initBlock, S...) 92 c.Write(bytepad(c.initBlock, c.rate)) 93 return &c 94 } 95 96 // Reset resets the hash to initial state. 97 func (c *cshakeState) Reset() { 98 c.state.Reset() 99 c.Write(bytepad(c.initBlock, c.rate)) 100 } 101 102 // Clone returns copy of a cSHAKE context within its current state. 103 func (c *cshakeState) Clone() ShakeHash { 104 b := make([]byte, len(c.initBlock)) 105 copy(b, c.initBlock) 106 return &cshakeState{state: c.clone(), initBlock: b} 107 } 108 109 // Clone returns copy of SHAKE context within its current state. 110 func (c *state) Clone() ShakeHash { 111 return c.clone() 112 } 113 114 // NewShake128 creates a new SHAKE128 variable-output-length ShakeHash. 115 // Its generic security strength is 128 bits against all attacks if at 116 // least 32 bytes of its output are used. 117 func NewShake128() ShakeHash { 118 return newShake128() 119 } 120 121 // NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. 122 // Its generic security strength is 256 bits against all attacks if 123 // at least 64 bytes of its output are used. 124 func NewShake256() ShakeHash { 125 return newShake256() 126 } 127 128 func newShake128Generic() *state { 129 return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake} 130 } 131 132 func newShake256Generic() *state { 133 return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake} 134 } 135 136 // NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash, 137 // a customizable variant of SHAKE128. 138 // N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is 139 // desired. S is a customization byte string used for domain separation - two cSHAKE 140 // computations on same input with different S yield unrelated outputs. 141 // When N and S are both empty, this is equivalent to NewShake128. 142 func NewCShake128(N, S []byte) ShakeHash { 143 if len(N) == 0 && len(S) == 0 { 144 return NewShake128() 145 } 146 return newCShake(N, S, rate128, 32, dsbyteCShake) 147 } 148 149 // NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash, 150 // a customizable variant of SHAKE256. 151 // N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is 152 // desired. S is a customization byte string used for domain separation - two cSHAKE 153 // computations on same input with different S yield unrelated outputs. 154 // When N and S are both empty, this is equivalent to NewShake256. 155 func NewCShake256(N, S []byte) ShakeHash { 156 if len(N) == 0 && len(S) == 0 { 157 return NewShake256() 158 } 159 return newCShake(N, S, rate256, 64, dsbyteCShake) 160 } 161 162 // ShakeSum128 writes an arbitrary-length digest of data into hash. 163 func ShakeSum128(hash, data []byte) { 164 h := NewShake128() 165 h.Write(data) 166 h.Read(hash) 167 } 168 169 // ShakeSum256 writes an arbitrary-length digest of data into hash. 170 func ShakeSum256(hash, data []byte) { 171 h := NewShake256() 172 h.Write(data) 173 h.Read(hash) 174 } 175