shake.go (5421B)
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 "io" 21 ) 22 23 // ShakeHash defines the interface to hash functions that 24 // support arbitrary-length output. 25 type 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 43 type 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 55 const ( 56 dsbyteShake = 0x1f 57 dsbyteCShake = 0x04 58 rate128 = 168 59 rate256 = 136 60 ) 61 62 func 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 71 func 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 84 func 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. 98 func (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. 104 func (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. 111 func (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. 118 func 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. 128 func 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. 141 func 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. 154 func 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. 162 func 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. 169 func ShakeSum256(hash, data []byte) { 170 h := NewShake256() 171 h.Write(data) 172 h.Read(hash) 173 }