mirror of https://gogs.blitter.com/RLabs/xs
191 lines
3.8 KiB
Go
191 lines
3.8 KiB
Go
// Package groestl provides core groestl functionality. It's based on groestl's
|
|
// implementation guide with references in C code.
|
|
package groestl
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"hash"
|
|
)
|
|
|
|
// Toggle verbose output with detailed description of every algorithm's step
|
|
const VERBOSE = false
|
|
|
|
// Struct digest is being used during algorithm execution. Provides easy
|
|
// access to all information about current state of data processing.
|
|
type digest struct {
|
|
hashbitlen int
|
|
chaining [16]uint64
|
|
blocks uint64
|
|
buf [128]byte
|
|
nbuf int
|
|
columns int
|
|
rounds int
|
|
}
|
|
|
|
// Equivalent to Init from reference implementation. Initiates values
|
|
// for digest struct, therefore determines exact type of groestl algorithm.
|
|
func (d *digest) Reset() {
|
|
for i, _ := range d.chaining {
|
|
d.chaining[i] = 0
|
|
}
|
|
|
|
d.blocks = 0
|
|
d.nbuf = 0
|
|
|
|
if d.hashbitlen <= 256 {
|
|
d.columns = 8
|
|
d.rounds = 10
|
|
} else {
|
|
d.columns = 16
|
|
d.rounds = 14
|
|
}
|
|
|
|
d.chaining[d.columns-1] = uint64(d.hashbitlen)
|
|
}
|
|
|
|
// Each New...() function creates new hash digest and initiates it
|
|
// for according hash size.
|
|
func New224() hash.Hash {
|
|
d := new(digest)
|
|
d.hashbitlen = 224
|
|
d.Reset()
|
|
return d
|
|
}
|
|
|
|
func New256() hash.Hash {
|
|
d := new(digest)
|
|
d.hashbitlen = 256
|
|
d.Reset()
|
|
return d
|
|
}
|
|
|
|
func New384() hash.Hash {
|
|
d := new(digest)
|
|
d.hashbitlen = 384
|
|
d.Reset()
|
|
return d
|
|
}
|
|
|
|
func New512() hash.Hash {
|
|
d := new(digest)
|
|
d.hashbitlen = 512
|
|
d.Reset()
|
|
return d
|
|
}
|
|
|
|
// Default function for creating hash digest for 256bit groestl.
|
|
func New() hash.Hash {
|
|
return New256()
|
|
}
|
|
|
|
// Return size of digest
|
|
func (d *digest) Size() int {
|
|
return d.hashbitlen
|
|
}
|
|
|
|
// Return block size for digest. For hash bigger than 256 bit block
|
|
// size is 128, otherwise it's 64.
|
|
func (d *digest) BlockSize() int {
|
|
if d.hashbitlen <= 256 {
|
|
return 64
|
|
} else {
|
|
return 128
|
|
}
|
|
}
|
|
|
|
// Equivalent to Update form reference implementation. Performs processing
|
|
// on all data except the last block that might need padding.
|
|
func (d *digest) Write(p []byte) (n int, err error) {
|
|
n = len(p)
|
|
if d.nbuf > 0 {
|
|
nn := copy(d.buf[d.nbuf:], p)
|
|
d.nbuf += nn
|
|
if d.nbuf == d.BlockSize() {
|
|
err = d.transform(d.buf[:d.BlockSize()])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
d.nbuf = 0
|
|
}
|
|
p = p[nn:]
|
|
}
|
|
if len(p) >= d.BlockSize() {
|
|
nn := len(p) &^ (d.BlockSize() - 1)
|
|
err = d.transform(p[:nn])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
p = p[nn:]
|
|
}
|
|
if len(p) > 0 {
|
|
d.nbuf = copy(d.buf[:], p)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (d *digest) Sum(in []byte) []byte {
|
|
d0 := *d
|
|
hash := d0.checkSum()
|
|
fmt.Printf("groestl-hash:len:%b %v\r\n", len(hash), hash)
|
|
return append(in, hash...)
|
|
}
|
|
|
|
// Equivalent to Final from reference implementation. Creates padding
|
|
// for last block of data and performs final output transformation and trumcate.
|
|
// Returns hash value.
|
|
func (d *digest) checkSum() []byte {
|
|
bs := d.BlockSize()
|
|
var tmp [128]byte
|
|
tmp[0] = 0x80
|
|
|
|
if d.nbuf > (bs - 8) {
|
|
d.Write(tmp[:(bs - d.nbuf)])
|
|
d.Write(tmp[8:bs])
|
|
} else {
|
|
d.Write(tmp[0:(bs - d.nbuf - 8)])
|
|
}
|
|
|
|
binary.BigEndian.PutUint64(tmp[:], d.blocks+1)
|
|
d.Write(tmp[:8])
|
|
|
|
if d.nbuf != 0 {
|
|
panic("padding failed")
|
|
}
|
|
|
|
d.finalTransform()
|
|
|
|
// store chaining in output byteslice
|
|
hash := make([]byte, d.columns*4)
|
|
for i := 0; i < d.columns/2; i++ {
|
|
binary.BigEndian.PutUint64(hash[(i*8):(i+1)*8], d.chaining[i+(d.columns/2)])
|
|
}
|
|
hash = hash[(len(hash) - d.hashbitlen/8):]
|
|
return hash
|
|
}
|
|
|
|
// Each Sum...() function returns according hash value for provided data.
|
|
func Sum224(data []byte) []byte {
|
|
d := New224().(*digest)
|
|
d.Write(data)
|
|
return d.checkSum()
|
|
}
|
|
|
|
func Sum256(data []byte) []byte {
|
|
d := New256().(*digest)
|
|
d.Write(data)
|
|
return d.checkSum()
|
|
}
|
|
|
|
func Sum384(data []byte) []byte {
|
|
d := New384().(*digest)
|
|
d.Write(data)
|
|
return d.checkSum()
|
|
}
|
|
|
|
func Sum512(data []byte) []byte {
|
|
d := New512().(*digest)
|
|
d.Write(data)
|
|
return d.checkSum()
|
|
}
|