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 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 18import ( 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. 28type 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 42type 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 54const ( 55 dsbyteShake = 0x1f 56 dsbyteCShake = 0x04 57 rate128 = 168 58 rate256 = 136 59) 60 61func 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 70func 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 83func 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. 97func (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. 103func (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. 110func (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. 117func 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. 124func NewShake256() ShakeHash { 125 return newShake256() 126} 127 128func newShake128Generic() *state { 129 return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake} 130} 131 132func 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. 142func 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. 155func 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. 163func 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. 170func ShakeSum256(hash, data []byte) { 171 h := NewShake256() 172 h.Write(data) 173 h.Read(hash) 174} 175