// Copyright 2020 Kris Kwiatkowski. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package sha3 import ( "errors" "hash" ) type spongeDesc struct { r int // rate d int // output size of SHA-3 name string // human readable name of the scheme } // Id's of SHA3 instantiations const ( SHA3_224 uint8 = iota SHA3_256 SHA3_384 SHA3_512 SHAKE128 SHAKE256 ) const ( // maximum value for rate used by keccak functions maxRate = 168 ) // Statically allocated error message var ErrWriteAfterRead = errors.New("sha3: can't write after read") var Sha3Desc = map[uint8]spongeDesc{ SHA3_224: {r: 144, d: 224 / 8, name: "SHA3-224"}, SHA3_256: {r: 136, d: 256 / 8, name: "SHA3-256"}, SHA3_384: {r: 104, d: 384 / 8, name: "SHA3-384"}, SHA3_512: {r: 72, d: 512 / 8, name: "SHA3-512"}, SHAKE128: {r: 168, d: 0, name: "SHAKE-128"}, SHAKE256: {r: 136, d: 0, name: "SHAKE-128"}, } type state struct { // Structure describing the details of hash algorithm desc spongeDesc // permuation state. 25*64 is a width of the keccak permutation used a [25]uint64 // sfx is a concatenation of "domain separator" as described in FIPS-202, // (section 6.1 and 6.2) with first bit of a pad10*1 (see section 5.1). sfx byte // Temporary data buffer data storageBuf // Index in the buffer. it points to the next available possition // in the data buffer if isSquezing is false. In case it is true // it indicates amount of unconsumed data. idx int // Indicates state of the sponge function. Whether it is absorbing // or squezing isSquezing bool } func min(a, b int) int { if a < b { return a } return b } // BlockSize returns block size in bytes. Corresponds to the input // block size B of the HMAC func (d *state) BlockSize() int { return d.desc.r } // Size returns the output size of the hash function in bytes. func (d *state) Size() int { return d.desc.d } // Reset clears the internal state by zeroing the sponge state and // the byte buffer, and setting spongeState to absorbing. func (d *state) Reset() { // Zero the permutation's state. for i := range d.a { d.a[i] = 0 } for i := range d.data { d.data[i] = 0 } d.isSquezing = false d.idx = 0 } // Write consumes data from the user. The data may change state of the // hash in case caller provided at least "rate" bytes of data. The "rate" value // for the hash is returned by the BlockSize() function. It may return an // error if sponge state has changed to "squeezing", meaning - Write was // called after at least one call to Read() has been done. func (c *state) Write(in []byte) (nwrite int, err error) { if c.isSquezing { return 0, ErrWriteAfterRead } nwrite = len(in) rate := c.BlockSize() buf := c.data.asBytes() processLen := c.idx + len(in) if processLen < c.BlockSize() { // not enough data to process copy(buf[c.idx:], in) c.idx = processLen return nwrite, nil } // process first block fbLen := rate - c.idx copy(buf[c.idx:], in[:fbLen]) xorIn(c, buf[:]) keccakF1600(&c.a) // process remaining blocks in = in[fbLen:] for len(in) >= rate { xorIn(c, in[:rate]) keccakF1600(&c.a) in = in[rate:] } // store unprocessed data copy(buf[:], in) c.idx = len(in) return nwrite, nil } func (c *state) finalize_sha3() { buf := c.data.asBytes()[:] rate := c.BlockSize() // there is at least one byte free, otherise // buf would be squezed already for i := c.idx + 1; i < rate; i++ { buf[i] = 0 } buf[c.idx] = c.sfx buf[rate-1] |= 0x80 xorIn(c, buf[:rate]) keccakF1600(&c.a) copyOut(c, buf[:rate]) c.idx = rate // now, idx indicates unconsumed amount of data c.isSquezing = true } // Read changes state of the hash if called first time. It will // return len(out) bytes of data. Never fails. func (c *state) Read(out []byte) (nread int, err error) { buf := c.data.asBytes()[:] rate := c.BlockSize() nread = len(out) // finalize if not done yet if !c.isSquezing { c.finalize_sha3() } // Copy-out bytes that are still kept in the buffer l := min(c.idx, len(out)) copy(out, buf[rate-c.idx:rate-c.idx+l]) out = out[l:] c.idx -= l if len(out) == 0 { // nothing else todo return nread, nil } // copy out full blocks and squeeze. at this point // there is no more data in the buffer. nblocks := len(out) / rate for nblocks > 0 { keccakF1600(&c.a) copyOut(c, out[:rate]) out = out[rate:] nblocks-- } keccakF1600(&c.a) copyOut(c, buf) copy(out, buf[:len(out)]) c.idx = rate - len(out) return nread, nil } // Sum applies padding to the hash state and then squeezes out the desired // number of output bytes. func (c *state) Sum(in []byte) []byte { l := len(in) // create buffer if nil has been provided if in == nil { in = make([]byte, c.Size()) } // enlarge capacity of the buffer if needed if cap(in) < (l + c.Size()) { b := make([]byte, l+c.Size()-cap(in)) in = append(in[:cap(in)], b...) } in = in[:l+c.Size()] c.Read(in[l:]) return in } func (c *state) digest(out, in []byte) { nread := len(out) rate := c.BlockSize() nblocks := nread / rate c.Write(in) c.finalize_sha3() for i := 0; i < nblocks-1; i++ { keccakF1600(&c.a) copyOut(c, out[:]) out = out[rate:] } keccakF1600(&c.a) copyOut(c, out[:len(out)]) } // New224 creates a new SHA3-224 hash. // Its generic security strength is 224 bits against preimage attacks, // and 112 bits against collision attacks. func New224() hash.Hash { return &state{sfx: 0x06, desc: Sha3Desc[SHA3_224]} } // New256 creates a new SHA3-256 hash. // Its generic security strength is 256 bits against preimage attacks, // and 128 bits against collision attacks. func New256() hash.Hash { return &state{sfx: 0x06, desc: Sha3Desc[SHA3_256]} } // New384 creates a new SHA3-384 hash. // Its generic security strength is 384 bits against preimage attacks, // and 192 bits against collision attacks. func New384() hash.Hash { return &state{sfx: 0x06, desc: Sha3Desc[SHA3_384]} } // New512 creates a new SHA3-512 hash. // Its generic security strength is 512 bits against preimage attacks, // and 256 bits against collision attacks. func New512() hash.Hash { return &state{sfx: 0x06, desc: Sha3Desc[SHA3_512]} }