|
|
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package echo
import ( "fmt"
"gitlab.com/nitya-sattva/go-x11/aesr" "gitlab.com/nitya-sattva/go-x11/hash" )
// HashSize holds the size of a hash in bytes.
const HashSize = uintptr(64)
// BlockSize holds the size of a block in bytes.
const BlockSize = uintptr(128)
////////////////
type digest struct { ptr uintptr
h [8][2]uint64 c [4]uint32
b [BlockSize]byte }
// New returns a new digest compute a ECHO512 hash.
func New() hash.Digest { ref := &digest{} ref.Reset() return ref }
////////////////
// Reset resets the digest to its initial state.
func (ref *digest) Reset() { ref.ptr = 0
ref.h[0][0] = uint64(8 * HashSize) ref.h[0][1] = 0 ref.h[1][0] = uint64(8 * HashSize) ref.h[1][1] = 0 ref.h[2][0] = uint64(8 * HashSize) ref.h[2][1] = 0 ref.h[3][0] = uint64(8 * HashSize) ref.h[3][1] = 0 ref.h[4][0] = uint64(8 * HashSize) ref.h[4][1] = 0 ref.h[5][0] = uint64(8 * HashSize) ref.h[5][1] = 0 ref.h[6][0] = uint64(8 * HashSize) ref.h[6][1] = 0 ref.h[7][0] = uint64(8 * HashSize) ref.h[7][1] = 0
memset32(ref.c[:], 0) }
// Sum appends the current hash to dst and returns the result
// as a slice. It does not change the underlying hash state.
func (ref *digest) Sum(dst []byte) []byte { dgt := *ref hsh := [64]byte{} dgt.Close(hsh[:], 0, 0) return append(dst, hsh[:]...) }
// Write more data to the running hash, never returns an error.
func (ref *digest) Write(src []byte) (int, error) { sln := uintptr(len(src)) fln := len(src) ptr := ref.ptr
if sln < (BlockSize - ptr) { copy(ref.b[ptr:], src) ref.ptr += sln return int(sln), nil }
for sln > 0 { cln := BlockSize - ptr
if cln > sln { cln = sln } sln -= cln
copy(ref.b[ptr:], src[:cln]) src = src[cln:] ptr += cln
if ptr == BlockSize { ref.c[0] += 1024 if ref.c[0] < 1024 { ref.c[1] += 1 if ref.c[1] == 0 { ref.c[2] += 1 if ref.c[2] == 0 { ref.c[3] += 1 } } }
compress(ref) ptr = 0 } }
ref.ptr = ptr return fln, nil }
// Close the digest by writing the last bits and storing the hash
// in dst. This prepares the digest for reuse by calling reset. A call
// to Close with a dst that is smaller then HashSize will return an error.
func (ref *digest) Close(dst []byte, bits uint8, bcnt uint8) error { if ln := len(dst); HashSize > uintptr(ln) { return fmt.Errorf("Echo Close: dst min length: %d, got %d", HashSize, ln) }
ptr := ref.ptr buf := ref.b[:]
eln := uint32(ptr<<3) + uint32(bcnt)
ref.c[0] += eln if ref.c[0] < eln { ref.c[1] += 1 if ref.c[1] == 0 { ref.c[2] += 1 if ref.c[2] == 0 { ref.c[3] += 1 } } }
var tmp [64]uint8 encUInt32le(tmp[:], ref.c[0]) encUInt32le(tmp[4:], ref.c[1]) encUInt32le(tmp[8:], ref.c[2]) encUInt32le(tmp[12:], ref.c[3])
if eln == 0 { memset32(ref.c[:], 0) }
{ off := uint8(0x80) >> bcnt buf[ptr] = uint8((bits & -off) | off) }
ptr += 1 memset8(buf[ptr:], 0)
if ptr > (BlockSize - 18) { compress(ref) memset8(buf[:], 0) memset32(ref.c[:], 0) }
encUInt16le(buf[(BlockSize-18):], uint16(16<<5)) copy(buf[(BlockSize-16):], tmp[:]) compress(ref)
h := ref.h[:] for x := uintptr(0); x < 4; x++ { for y := uintptr(0); y < 2; y++ { encUInt64le(dst[(((x*2)+y)*8):], h[x][y]) } }
ref.Reset() return nil }
// Size returns the number of bytes required to store the hash.
func (*digest) Size() int { return int(HashSize) }
// BlockSize returns the block size of the hash.
func (*digest) BlockSize() int { return int(BlockSize) }
////////////////
func memset8(dst []byte, src byte) { for i := range dst { dst[i] = src } }
func memset32(dst []uint32, src uint32) { for i := range dst { dst[i] = src } }
func compress(ref *digest) { var w [16][2]uint64
k0 := ref.c[0] k1 := ref.c[1] k2 := ref.c[2] k3 := ref.c[3]
for i := uintptr(0); i < 8; i++ { w[i][0] = ref.h[i][0] w[i+8][0] = decUInt64le(ref.b[(16 * i):]) w[i][1] = ref.h[i][1] w[i+8][1] = decUInt64le(ref.b[((16 * i) + 8):]) }
var a0, a1, a2 uint64 var b0, b1, b2 uint64
var w0, w1, w2, w3 uint64
var x0, x1, x2, x3 uint32 var y0, y1, y2, y3 uint32
for u := uintptr(0); u < 10; u++ { for n := uintptr(0); n < 16; n++ { x0 = uint32(w[n][0]) x1 = uint32(w[n][0] >> 32) x2 = uint32(w[n][1]) x3 = uint32(w[n][1] >> 32)
y0, y1, y2, y3 = aesr.Round32ble( x0, x1, x2, x3, k0, k1, k2, k3, ) x0, x1, x2, x3 = aesr.Round32ble( y0, y1, y2, y3, 0, 0, 0, 0, )
w[n][0] = uint64(x0) | (uint64(x1) << 32) w[n][1] = uint64(x2) | (uint64(x3) << 32)
k0 += 1 if k0 == 0 { k1 += 1 if k1 == 0 { k2 += 1 if k2 == 0 { k3 += 1 } } } }
a0 = w[1][0] w[1][0] = w[5][0] w[5][0] = w[9][0] w[9][0] = w[13][0] w[13][0] = a0
a0 = w[1][1] w[1][1] = w[5][1] w[5][1] = w[9][1] w[9][1] = w[13][1] w[13][1] = a0
a0 = w[2][0] w[2][0] = w[10][0] w[10][0] = a0
a0 = w[6][0] w[6][0] = w[14][0] w[14][0] = a0
a0 = w[2][1] w[2][1] = w[10][1] w[10][1] = a0
a0 = w[6][1] w[6][1] = w[14][1] w[14][1] = a0
a0 = w[15][0] w[15][0] = w[11][0] w[11][0] = w[7][0] w[7][0] = w[3][0] w[3][0] = a0
a0 = w[15][1] w[15][1] = w[11][1] w[11][1] = w[7][1] w[7][1] = w[3][1] w[3][1] = a0
for n := uintptr(0); n < 2; n++ { w0 = w[0][n] w1 = w[1][n] w2 = w[2][n] w3 = w[3][n] a0 = w0 ^ w1 a1 = w1 ^ w2 a2 = w2 ^ w3 b0 = (((a0&uint64(0x8080808080808080))>>7)*27 ^ ((a0 & uint64(0x7F7F7F7F7F7F7F7F)) << 1)) b1 = (((a1&uint64(0x8080808080808080))>>7)*27 ^ ((a1 & uint64(0x7F7F7F7F7F7F7F7F)) << 1)) b2 = (((a2&uint64(0x8080808080808080))>>7)*27 ^ ((a2 & uint64(0x7F7F7F7F7F7F7F7F)) << 1)) w[0][n] = b0 ^ a1 ^ w3 w[1][n] = b1 ^ w0 ^ a2 w[2][n] = b2 ^ a0 ^ w3 w[3][n] = b0 ^ b1 ^ b2 ^ a0 ^ w2
w0 = w[4][n] w1 = w[5][n] w2 = w[6][n] w3 = w[7][n] a0 = w0 ^ w1 a1 = w1 ^ w2 a2 = w2 ^ w3 b0 = (((a0&uint64(0x8080808080808080))>>7)*27 ^ ((a0 & uint64(0x7F7F7F7F7F7F7F7F)) << 1)) b1 = (((a1&uint64(0x8080808080808080))>>7)*27 ^ ((a1 & uint64(0x7F7F7F7F7F7F7F7F)) << 1)) b2 = (((a2&uint64(0x8080808080808080))>>7)*27 ^ ((a2 & uint64(0x7F7F7F7F7F7F7F7F)) << 1)) w[4][n] = b0 ^ a1 ^ w3 w[5][n] = b1 ^ w0 ^ a2 w[6][n] = b2 ^ a0 ^ w3 w[7][n] = b0 ^ b1 ^ b2 ^ a0 ^ w2
w0 = w[8][n] w1 = w[9][n] w2 = w[10][n] w3 = w[11][n] a0 = w0 ^ w1 a1 = w1 ^ w2 a2 = w2 ^ w3 b0 = (((a0&uint64(0x8080808080808080))>>7)*27 ^ ((a0 & uint64(0x7F7F7F7F7F7F7F7F)) << 1)) b1 = (((a1&uint64(0x8080808080808080))>>7)*27 ^ ((a1 & uint64(0x7F7F7F7F7F7F7F7F)) << 1)) b2 = (((a2&uint64(0x8080808080808080))>>7)*27 ^ ((a2 & uint64(0x7F7F7F7F7F7F7F7F)) << 1)) w[8][n] = b0 ^ a1 ^ w3 w[9][n] = b1 ^ w0 ^ a2 w[10][n] = b2 ^ a0 ^ w3 w[11][n] = b0 ^ b1 ^ b2 ^ a0 ^ w2
w0 = w[12][n] w1 = w[13][n] w2 = w[14][n] w3 = w[15][n] a0 = w0 ^ w1 a1 = w1 ^ w2 a2 = w2 ^ w3 b0 = (((a0&uint64(0x8080808080808080))>>7)*27 ^ ((a0 & uint64(0x7F7F7F7F7F7F7F7F)) << 1)) b1 = (((a1&uint64(0x8080808080808080))>>7)*27 ^ ((a1 & uint64(0x7F7F7F7F7F7F7F7F)) << 1)) b2 = (((a2&uint64(0x8080808080808080))>>7)*27 ^ ((a2 & uint64(0x7F7F7F7F7F7F7F7F)) << 1)) w[12][n] = b0 ^ a1 ^ w3 w[13][n] = b1 ^ w0 ^ a2 w[14][n] = b2 ^ a0 ^ w3 w[15][n] = b0 ^ b1 ^ b2 ^ a0 ^ w2 } }
h := ref.h[:] for x := uintptr(0); x < 8; x++ { for y := uintptr(0); y < 2; y++ { h[x][y] ^= decUInt64le(ref.b[(((x*2)+y)*8):]) ^ w[x][y] ^ w[x+8][y] } } }
func decUInt64le(src []byte) uint64 { return (uint64(src[0]) | uint64(src[1])<<8 | uint64(src[2])<<16 | uint64(src[3])<<24 | uint64(src[4])<<32 | uint64(src[5])<<40 | uint64(src[6])<<48 | uint64(src[7])<<56) }
func encUInt16le(dst []byte, src uint16) { dst[0] = uint8(src) dst[1] = uint8(src >> 8) }
func encUInt32le(dst []uint8, src uint32) { dst[0] = uint8(src) dst[1] = uint8(src >> 8) dst[2] = uint8(src >> 16) dst[3] = uint8(src >> 24) }
func encUInt64le(dst []byte, src uint64) { dst[0] = uint8(src) dst[1] = uint8(src >> 8) dst[2] = uint8(src >> 16) dst[3] = uint8(src >> 24) dst[4] = uint8(src >> 32) dst[5] = uint8(src >> 40) dst[6] = uint8(src >> 48) dst[7] = uint8(src >> 56) }
|