// Written in 2011-2012 by Dmitry Chestnykh.
|
|
//
|
|
// To the extent possible under law, the author have dedicated all copyright
|
|
// and related and neighboring rights to this software to the public domain
|
|
// worldwide. This software is distributed without any warranty.
|
|
// http://creativecommons.org/publicdomain/zero/1.0/
|
|
|
|
// Package blake256 implements BLAKE-256 and BLAKE-224 hash functions (SHA-3
|
|
// candidate).
|
|
package blake256
|
|
|
|
import "hash"
|
|
|
|
// The block size of the hash algorithm in bytes.
|
|
const BlockSize = 64
|
|
|
|
// The size of BLAKE-256 hash in bytes.
|
|
const Size = 32
|
|
|
|
// The size of BLAKE-224 hash in bytes.
|
|
const Size224 = 28
|
|
|
|
type digest struct {
|
|
hashSize int // hash output size in bits (224 or 256)
|
|
h [8]uint32 // current chain value
|
|
s [4]uint32 // salt (zero by default)
|
|
t uint64 // message bits counter
|
|
nullt bool // special case for finalization: skip counter
|
|
x [BlockSize]byte // buffer for data not yet compressed
|
|
nx int // number of bytes in buffer
|
|
}
|
|
|
|
var (
|
|
// Initialization values.
|
|
iv256 = [8]uint32{
|
|
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
|
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19}
|
|
|
|
iv224 = [8]uint32{
|
|
0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939,
|
|
0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4}
|
|
|
|
pad = [64]byte{0x80}
|
|
)
|
|
|
|
// Reset resets the state of digest. It leaves salt intact.
|
|
func (d *digest) Reset() {
|
|
if d.hashSize == 224 {
|
|
d.h = iv224
|
|
} else {
|
|
d.h = iv256
|
|
}
|
|
d.t = 0
|
|
d.nx = 0
|
|
d.nullt = false
|
|
}
|
|
|
|
func (d *digest) Size() int { return d.hashSize >> 3 }
|
|
|
|
func (d *digest) BlockSize() int { return BlockSize }
|
|
|
|
func (d *digest) Write(p []byte) (nn int, err error) {
|
|
nn = len(p)
|
|
if d.nx > 0 {
|
|
n := len(p)
|
|
if n > BlockSize-d.nx {
|
|
n = BlockSize - d.nx
|
|
}
|
|
d.nx += copy(d.x[d.nx:], p)
|
|
if d.nx == BlockSize {
|
|
block(d, d.x[:])
|
|
d.nx = 0
|
|
}
|
|
p = p[n:]
|
|
}
|
|
if len(p) >= BlockSize {
|
|
n := len(p) &^ (BlockSize - 1)
|
|
block(d, p[:n])
|
|
p = p[n:]
|
|
}
|
|
if len(p) > 0 {
|
|
d.nx = copy(d.x[:], p)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Sum returns the calculated checksum.
|
|
func (d0 *digest) Sum(in []byte) []byte {
|
|
// Make a copy of d0 so that caller can keep writing and summing.
|
|
d := *d0
|
|
|
|
nx := uint64(d.nx)
|
|
l := d.t + nx<<3
|
|
len := make([]byte, 8)
|
|
len[0] = byte(l >> 56)
|
|
len[1] = byte(l >> 48)
|
|
len[2] = byte(l >> 40)
|
|
len[3] = byte(l >> 32)
|
|
len[4] = byte(l >> 24)
|
|
len[5] = byte(l >> 16)
|
|
len[6] = byte(l >> 8)
|
|
len[7] = byte(l)
|
|
|
|
if nx == 55 {
|
|
// One padding byte.
|
|
d.t -= 8
|
|
if d.hashSize == 224 {
|
|
d.Write([]byte{0x80})
|
|
} else {
|
|
d.Write([]byte{0x81})
|
|
}
|
|
} else {
|
|
if nx < 55 {
|
|
// Enough space to fill the block.
|
|
if nx == 0 {
|
|
d.nullt = true
|
|
}
|
|
d.t -= 440 - nx<<3
|
|
d.Write(pad[0 : 55-nx])
|
|
} else {
|
|
// Need 2 compressions.
|
|
d.t -= 512 - nx<<3
|
|
d.Write(pad[0 : 64-nx])
|
|
d.t -= 440
|
|
d.Write(pad[1:56])
|
|
d.nullt = true
|
|
}
|
|
if d.hashSize == 224 {
|
|
d.Write([]byte{0x00})
|
|
} else {
|
|
d.Write([]byte{0x01})
|
|
}
|
|
d.t -= 8
|
|
}
|
|
d.t -= 64
|
|
d.Write(len)
|
|
|
|
out := make([]byte, d.Size())
|
|
j := 0
|
|
for _, s := range d.h[:d.hashSize>>5] {
|
|
out[j+0] = byte(s >> 24)
|
|
out[j+1] = byte(s >> 16)
|
|
out[j+2] = byte(s >> 8)
|
|
out[j+3] = byte(s >> 0)
|
|
j += 4
|
|
}
|
|
return append(in, out...)
|
|
}
|
|
|
|
func (d *digest) setSalt(s []byte) {
|
|
if len(s) != 16 {
|
|
panic("salt length must be 16 bytes")
|
|
}
|
|
d.s[0] = uint32(s[0])<<24 | uint32(s[1])<<16 | uint32(s[2])<<8 | uint32(s[3])
|
|
d.s[1] = uint32(s[4])<<24 | uint32(s[5])<<16 | uint32(s[6])<<8 | uint32(s[7])
|
|
d.s[2] = uint32(s[8])<<24 | uint32(s[9])<<16 | uint32(s[10])<<8 | uint32(s[11])
|
|
d.s[3] = uint32(s[12])<<24 | uint32(s[13])<<16 | uint32(s[14])<<8 | uint32(s[15])
|
|
}
|
|
|
|
// New returns a new hash.Hash computing the BLAKE-256 checksum.
|
|
func New() hash.Hash {
|
|
return &digest{
|
|
hashSize: 256,
|
|
h: iv256,
|
|
}
|
|
}
|
|
|
|
// NewSalt is like New but initializes salt with the given 16-byte slice.
|
|
func NewSalt(salt []byte) hash.Hash {
|
|
d := &digest{
|
|
hashSize: 256,
|
|
h: iv256,
|
|
}
|
|
d.setSalt(salt)
|
|
return d
|
|
}
|
|
|
|
// New224 returns a new hash.Hash computing the BLAKE-224 checksum.
|
|
func New224() hash.Hash {
|
|
return &digest{
|
|
hashSize: 224,
|
|
h: iv224,
|
|
}
|
|
}
|
|
|
|
// New224Salt is like New224 but initializes salt with the given 16-byte slice.
|
|
func New224Salt(salt []byte) hash.Hash {
|
|
d := &digest{
|
|
hashSize: 224,
|
|
h: iv224,
|
|
}
|
|
d.setSalt(salt)
|
|
return d
|
|
}
|