github.com/cloudflare/circl@v1.5.0/internal/sha3/sha3.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 // spongeDirection indicates the direction bytes are flowing through the sponge. 8 type spongeDirection int 9 10 const ( 11 // spongeAbsorbing indicates that the sponge is absorbing input. 12 spongeAbsorbing spongeDirection = iota 13 // spongeSqueezing indicates that the sponge is being squeezed. 14 spongeSqueezing 15 ) 16 17 const ( 18 // maxRate is the maximum size of the internal buffer. SHAKE-256 19 // currently needs the largest buffer. 20 maxRate = 168 21 ) 22 23 func (d *State) buf() []byte { 24 return d.storage.asBytes()[d.bufo:d.bufe] 25 } 26 27 type State struct { 28 // Generic sponge components. 29 a [25]uint64 // main state of the hash 30 rate int // the number of bytes of state to use 31 32 bufo int // offset of buffer in storage 33 bufe int // end of buffer in storage 34 35 // dsbyte contains the "domain separation" bits and the first bit of 36 // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the 37 // SHA-3 and SHAKE functions by appending bitstrings to the message. 38 // Using a little-endian bit-ordering convention, these are "01" for SHA-3 39 // and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the 40 // padding rule from section 5.1 is applied to pad the message to a multiple 41 // of the rate, which involves adding a "1" bit, zero or more "0" bits, and 42 // a final "1" bit. We merge the first "1" bit from the padding into dsbyte, 43 // giving 00000110b (0x06) and 00011111b (0x1f). 44 // [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf 45 // "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and 46 // Extendable-Output Functions (May 2014)" 47 dsbyte byte 48 49 storage storageBuf 50 51 // Specific to SHA-3 and SHAKE. 52 outputLen int // the default output size in bytes 53 state spongeDirection // whether the sponge is absorbing or squeezing 54 turbo bool // Whether we're using 12 rounds instead of 24 55 } 56 57 // BlockSize returns the rate of sponge underlying this hash function. 58 func (d *State) BlockSize() int { return d.rate } 59 60 // Size returns the output size of the hash function in bytes. 61 func (d *State) Size() int { return d.outputLen } 62 63 // Reset clears the internal state by zeroing the sponge state and 64 // the byte buffer, and setting Sponge.state to absorbing. 65 func (d *State) Reset() { 66 // Zero the permutation's state. 67 for i := range d.a { 68 d.a[i] = 0 69 } 70 d.state = spongeAbsorbing 71 d.bufo = 0 72 d.bufe = 0 73 } 74 75 func (d *State) clone() *State { 76 ret := *d 77 return &ret 78 } 79 80 // permute applies the KeccakF-1600 permutation. It handles 81 // any input-output buffering. 82 func (d *State) permute() { 83 switch d.state { 84 case spongeAbsorbing: 85 // If we're absorbing, we need to xor the input into the state 86 // before applying the permutation. 87 xorIn(d, d.buf()) 88 d.bufe = 0 89 d.bufo = 0 90 KeccakF1600(&d.a, d.turbo) 91 case spongeSqueezing: 92 // If we're squeezing, we need to apply the permutation before 93 // copying more output. 94 KeccakF1600(&d.a, d.turbo) 95 d.bufe = d.rate 96 d.bufo = 0 97 copyOut(d, d.buf()) 98 } 99 } 100 101 // pads appends the domain separation bits in dsbyte, applies 102 // the multi-bitrate 10..1 padding rule, and permutes the state. 103 func (d *State) padAndPermute(dsbyte byte) { 104 // Pad with this instance's domain-separator bits. We know that there's 105 // at least one byte of space in d.buf() because, if it were full, 106 // permute would have been called to empty it. dsbyte also contains the 107 // first one bit for the padding. See the comment in the state struct. 108 zerosStart := d.bufe + 1 109 d.bufe = d.rate 110 buf := d.buf() 111 buf[zerosStart-1] = dsbyte 112 for i := zerosStart; i < d.rate; i++ { 113 buf[i] = 0 114 } 115 // This adds the final one bit for the padding. Because of the way that 116 // bits are numbered from the LSB upwards, the final bit is the MSB of 117 // the last byte. 118 buf[d.rate-1] ^= 0x80 119 // Apply the permutation 120 d.permute() 121 d.state = spongeSqueezing 122 d.bufe = d.rate 123 copyOut(d, buf) 124 } 125 126 // Write absorbs more data into the hash's state. It produces an error 127 // if more data is written to the ShakeHash after writing 128 func (d *State) Write(p []byte) (written int, err error) { 129 if d.state != spongeAbsorbing { 130 panic("sha3: write to sponge after read") 131 } 132 written = len(p) 133 134 for len(p) > 0 { 135 bufl := d.bufe - d.bufo 136 if bufl == 0 && len(p) >= d.rate { 137 // The fast path; absorb a full "rate" bytes of input and apply the permutation. 138 xorIn(d, p[:d.rate]) 139 p = p[d.rate:] 140 KeccakF1600(&d.a, d.turbo) 141 } else { 142 // The slow path; buffer the input until we can fill the sponge, and then xor it in. 143 todo := d.rate - bufl 144 if todo > len(p) { 145 todo = len(p) 146 } 147 d.bufe += todo 148 buf := d.buf() 149 copy(buf[bufl:], p[:todo]) 150 p = p[todo:] 151 152 // If the sponge is full, apply the permutation. 153 if d.bufe == d.rate { 154 d.permute() 155 } 156 } 157 } 158 159 return written, nil 160 } 161 162 // Read squeezes an arbitrary number of bytes from the sponge. 163 func (d *State) Read(out []byte) (n int, err error) { 164 // If we're still absorbing, pad and apply the permutation. 165 if d.state == spongeAbsorbing { 166 d.padAndPermute(d.dsbyte) 167 } 168 169 n = len(out) 170 171 // Now, do the squeezing. 172 for len(out) > 0 { 173 buf := d.buf() 174 n := copy(out, buf) 175 d.bufo += n 176 out = out[n:] 177 178 // Apply the permutation if we've squeezed the sponge dry. 179 if d.bufo == d.bufe { 180 d.permute() 181 } 182 } 183 184 return 185 } 186 187 // Sum applies padding to the hash state and then squeezes out the desired 188 // number of output bytes. 189 func (d *State) Sum(in []byte) []byte { 190 // Make a copy of the original hash so that caller can keep writing 191 // and summing. 192 dup := d.clone() 193 hash := make([]byte, dup.outputLen) 194 _, _ = dup.Read(hash) 195 return append(in, hash...) 196 } 197 198 func (d *State) IsAbsorbing() bool { 199 return d.state == spongeAbsorbing 200 }