mirror of
https://github.com/henrydcase/nobs.git
synced 2024-11-28 18:01:21 +00:00
Henry Case
8474981cfc
* add function for one-off calculation * sha3: simplifies Read function * sha3: remove if from Read
255 lines
6.1 KiB
Go
255 lines
6.1 KiB
Go
// 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]}
|
|
}
|