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