github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/golang.org/x/crypto/sha3/shake.go (about) 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 if h := newShake128Asm(); h != nil { 119 return h 120 } 121 return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake} 122 } 123 124 // NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. 125 // Its generic security strength is 256 bits against all attacks if 126 // at least 64 bytes of its output are used. 127 func NewShake256() ShakeHash { 128 if h := newShake256Asm(); h != nil { 129 return h 130 } 131 return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake} 132 } 133 134 // NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash, 135 // a customizable variant of SHAKE128. 136 // N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is 137 // desired. S is a customization byte string used for domain separation - two cSHAKE 138 // computations on same input with different S yield unrelated outputs. 139 // When N and S are both empty, this is equivalent to NewShake128. 140 func NewCShake128(N, S []byte) ShakeHash { 141 if len(N) == 0 && len(S) == 0 { 142 return NewShake128() 143 } 144 return newCShake(N, S, rate128, 32, dsbyteCShake) 145 } 146 147 // NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash, 148 // a customizable variant of SHAKE256. 149 // N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is 150 // desired. S is a customization byte string used for domain separation - two cSHAKE 151 // computations on same input with different S yield unrelated outputs. 152 // When N and S are both empty, this is equivalent to NewShake256. 153 func NewCShake256(N, S []byte) ShakeHash { 154 if len(N) == 0 && len(S) == 0 { 155 return NewShake256() 156 } 157 return newCShake(N, S, rate256, 64, dsbyteCShake) 158 } 159 160 // ShakeSum128 writes an arbitrary-length digest of data into hash. 161 func ShakeSum128(hash, data []byte) { 162 h := NewShake128() 163 h.Write(data) 164 h.Read(hash) 165 } 166 167 // ShakeSum256 writes an arbitrary-length digest of data into hash. 168 func ShakeSum256(hash, data []byte) { 169 h := NewShake256() 170 h.Write(data) 171 h.Read(hash) 172 }