// Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package keccak import ( "fmt" "gitlab.com/nitya-sattva/go-x11/hash" ) // HashSize holds the size of a hash in bytes. const HashSize = int(64) // BlockSize holds the size of a block in bytes. const BlockSize = uintptr(72) //////////////// type digest struct { ptr uintptr cnt uintptr h [25]uint64 b [144]byte } // New returns a new digest compute a KECCAK512 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.cnt = 200 - (512 >> 2) h := ref.h[:] h[0] = uint64(0x0) h[1] = uint64(0xFFFFFFFFFFFFFFFF) h[2] = uint64(0xFFFFFFFFFFFFFFFF) h[3] = uint64(0x0) h[4] = uint64(0x0) h[5] = uint64(0x0) h[6] = uint64(0x0) h[7] = uint64(0x0) h[8] = uint64(0xFFFFFFFFFFFFFFFF) h[9] = uint64(0x0) h[10] = uint64(0x0) h[11] = uint64(0x0) h[12] = uint64(0xFFFFFFFFFFFFFFFF) h[13] = uint64(0x0) h[14] = uint64(0x0) h[15] = uint64(0x0) h[16] = uint64(0x0) h[17] = uint64(0xFFFFFFFFFFFFFFFF) h[18] = uint64(0x0) h[19] = uint64(0x0) h[20] = uint64(0xFFFFFFFFFFFFFFFF) h[21] = uint64(0x0) h[22] = uint64(0x0) h[23] = uint64(0x0) h[24] = uint64(0x0) } // 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 buf := ref.b[:] sta := ref.h[:] 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 { sta[0] ^= decUInt64le(buf[0:]) sta[1] ^= decUInt64le(buf[8:]) sta[2] ^= decUInt64le(buf[16:]) sta[3] ^= decUInt64le(buf[24:]) sta[4] ^= decUInt64le(buf[32:]) sta[5] ^= decUInt64le(buf[40:]) sta[6] ^= decUInt64le(buf[48:]) sta[7] ^= decUInt64le(buf[56:]) sta[8] ^= decUInt64le(buf[64:]) for j := uintptr(0); j < 24; j++ { var t0, t1, t2, t3, t4, tp uint64 { var tt0, tt1, tt2, tt3 uint64 tt0 = sta[1] ^ sta[6] tt1 = sta[11] ^ sta[16] tt0 = tt0 ^ sta[21] tt0 = tt0 ^ tt1 tt0 = (tt0 << 1) | (tt0 >> (64 - 1)) tt2 = sta[4] ^ sta[9] tt3 = sta[14] ^ sta[19] tt0 = tt0 ^ sta[24] tt2 = tt2 ^ tt3 t0 = tt0 ^ tt2 tt0 = sta[2] ^ sta[7] tt1 = sta[12] ^ sta[17] tt0 = tt0 ^ sta[22] tt0 = tt0 ^ tt1 tt0 = (tt0 << 1) | (tt0 >> (64 - 1)) tt2 = sta[0] ^ sta[5] tt3 = sta[10] ^ sta[15] tt0 = tt0 ^ sta[20] tt2 = tt2 ^ tt3 t1 = tt0 ^ tt2 tt0 = sta[3] ^ sta[8] tt1 = sta[13] ^ sta[18] tt0 = tt0 ^ sta[23] tt0 = tt0 ^ tt1 tt0 = (tt0 << 1) | (tt0 >> (64 - 1)) tt2 = sta[1] ^ sta[6] tt3 = sta[11] ^ sta[16] tt0 = tt0 ^ sta[21] tt2 = tt2 ^ tt3 t2 = tt0 ^ tt2 tt0 = sta[4] ^ sta[9] tt1 = sta[14] ^ sta[19] tt0 = tt0 ^ sta[24] tt0 = tt0 ^ tt1 tt0 = (tt0 << 1) | (tt0 >> (64 - 1)) tt2 = sta[2] ^ sta[7] tt3 = sta[12] ^ sta[17] tt0 = tt0 ^ sta[22] tt2 = tt2 ^ tt3 t3 = tt0 ^ tt2 tt0 = sta[0] ^ sta[5] tt1 = sta[10] ^ sta[15] tt0 = tt0 ^ sta[20] tt0 = tt0 ^ tt1 tt0 = (tt0 << 1) | (tt0 >> (64 - 1)) tt2 = sta[3] ^ sta[8] tt3 = sta[13] ^ sta[18] tt0 = tt0 ^ sta[23] tt2 = tt2 ^ tt3 t4 = tt0 ^ tt2 } sta[0] = sta[0] ^ t0 sta[1] = sta[1] ^ t1 sta[2] = sta[2] ^ t2 sta[3] = sta[3] ^ t3 sta[4] = sta[4] ^ t4 sta[5] = sta[5] ^ t0 sta[6] = sta[6] ^ t1 sta[7] = sta[7] ^ t2 sta[8] = sta[8] ^ t3 sta[9] = sta[9] ^ t4 sta[10] = sta[10] ^ t0 sta[11] = sta[11] ^ t1 sta[12] = sta[12] ^ t2 sta[13] = sta[13] ^ t3 sta[14] = sta[14] ^ t4 sta[15] = sta[15] ^ t0 sta[16] = sta[16] ^ t1 sta[17] = sta[17] ^ t2 sta[18] = sta[18] ^ t3 sta[23] = sta[23] ^ t3 sta[19] = sta[19] ^ t4 sta[20] = sta[20] ^ t0 sta[22] = sta[22] ^ t2 sta[21] = sta[21] ^ t1 sta[24] = sta[24] ^ t4 sta[1] = (sta[1] << 1) | (sta[1] >> (64 - 1)) sta[2] = (sta[2] << 62) | (sta[2] >> (64 - 62)) sta[3] = (sta[3] << 28) | (sta[3] >> (64 - 28)) sta[4] = (sta[4] << 27) | (sta[4] >> (64 - 27)) sta[5] = (sta[5] << 36) | (sta[5] >> (64 - 36)) sta[6] = (sta[6] << 44) | (sta[6] >> (64 - 44)) sta[7] = (sta[7] << 6) | (sta[7] >> (64 - 6)) sta[8] = (sta[8] << 55) | (sta[8] >> (64 - 55)) sta[9] = (sta[9] << 20) | (sta[9] >> (64 - 20)) sta[10] = (sta[10] << 3) | (sta[10] >> (64 - 3)) sta[11] = (sta[11] << 10) | (sta[11] >> (64 - 10)) sta[12] = (sta[12] << 43) | (sta[12] >> (64 - 43)) sta[13] = (sta[13] << 25) | (sta[13] >> (64 - 25)) sta[14] = (sta[14] << 39) | (sta[14] >> (64 - 39)) sta[15] = (sta[15] << 41) | (sta[15] >> (64 - 41)) sta[16] = (sta[16] << 45) | (sta[16] >> (64 - 45)) sta[17] = (sta[17] << 15) | (sta[17] >> (64 - 15)) sta[18] = (sta[18] << 21) | (sta[18] >> (64 - 21)) sta[19] = (sta[19] << 8) | (sta[19] >> (64 - 8)) sta[20] = (sta[20] << 18) | (sta[20] >> (64 - 18)) sta[21] = (sta[21] << 2) | (sta[21] >> (64 - 2)) sta[22] = (sta[22] << 61) | (sta[22] >> (64 - 61)) sta[23] = (sta[23] << 56) | (sta[23] >> (64 - 56)) sta[24] = (sta[24] << 14) | (sta[24] >> (64 - 14)) tp = ^sta[12] t0 = sta[6] | sta[12] t0 = sta[0] ^ t0 t1 = tp | sta[18] t1 = sta[6] ^ t1 t2 = sta[18] & sta[24] t2 = sta[12] ^ t2 t3 = sta[24] | sta[0] t3 = sta[18] ^ t3 t4 = sta[0] & sta[6] t4 = sta[24] ^ t4 sta[0] = t0 sta[6] = t1 sta[12] = t2 sta[18] = t3 sta[24] = t4 tp = ^sta[22] t0 = sta[9] | sta[10] t0 = sta[3] ^ t0 t1 = sta[10] & sta[16] t1 = sta[9] ^ t1 t2 = sta[16] | tp t2 = sta[10] ^ t2 t3 = sta[22] | sta[3] t3 = sta[16] ^ t3 t4 = sta[3] & sta[9] t4 = sta[22] ^ t4 sta[3] = t0 sta[9] = t1 sta[10] = t2 sta[16] = t3 sta[22] = t4 tp = ^sta[19] t0 = sta[7] | sta[13] t0 = sta[1] ^ t0 t1 = sta[13] & sta[19] t1 = sta[7] ^ t1 t2 = tp & sta[20] t2 = sta[13] ^ t2 t3 = sta[20] | sta[1] t3 = tp ^ t3 t4 = sta[1] & sta[7] t4 = sta[20] ^ t4 sta[1] = t0 sta[7] = t1 sta[13] = t2 sta[19] = t3 sta[20] = t4 tp = ^sta[17] t0 = sta[5] & sta[11] t0 = sta[4] ^ t0 t1 = sta[11] | sta[17] t1 = sta[5] ^ t1 t2 = tp | sta[23] t2 = sta[11] ^ t2 t3 = sta[23] & sta[4] t3 = tp ^ t3 t4 = sta[4] | sta[5] t4 = sta[23] ^ t4 sta[4] = t0 sta[5] = t1 sta[11] = t2 sta[17] = t3 sta[23] = t4 tp = ^sta[8] t0 = tp & sta[14] t0 = sta[2] ^ t0 t1 = sta[14] | sta[15] t1 = tp ^ t1 t2 = sta[15] & sta[21] t2 = sta[14] ^ t2 t3 = sta[21] | sta[2] t3 = sta[15] ^ t3 t4 = sta[2] & sta[8] t4 = sta[21] ^ t4 sta[2] = t0 sta[8] = t1 sta[14] = t2 sta[15] = t3 sta[21] = t4 sta[0] = sta[0] ^ kSpec[j+0] t0 = sta[5] sta[5] = sta[3] sta[3] = sta[18] sta[18] = sta[17] sta[17] = sta[11] sta[11] = sta[7] sta[7] = sta[10] sta[10] = sta[1] sta[1] = sta[6] sta[6] = sta[9] sta[9] = sta[22] sta[22] = sta[14] sta[14] = sta[20] sta[20] = sta[2] sta[2] = sta[12] sta[12] = sta[13] sta[13] = sta[19] sta[19] = sta[23] sta[23] = sta[15] sta[15] = sta[4] sta[4] = sta[24] sta[24] = sta[21] sta[21] = sta[8] sta[8] = sta[16] sta[16] = t0 } 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 > ln { return fmt.Errorf("Keccak Close: dst min length: %d, got %d", HashSize, ln) } var tln uintptr var tmp [73]uint8 off := uint8((uint16(0x100) | uint16(bits&0xFF)) >> (8 - bcnt)) if ref.ptr == (72 - 1) { if bcnt == 7 { tmp[0] = off tmp[72] = 0x80 tln = 1 + 72 } else { tmp[0] = uint8(off | 0x80) tln = 1 } } else { tln = 72 - ref.ptr tmp[0] = off tmp[tln-1] = 0x80 } ref.Write(tmp[:tln]) ref.h[1] = ^ref.h[1] ref.h[2] = ^ref.h[2] ref.h[8] = ^ref.h[8] ref.h[12] = ^ref.h[12] ref.h[17] = ^ref.h[17] ref.h[20] = ^ref.h[20] for u := uintptr(0); u < 64; u += 8 { encUInt64le(dst[u:], ref.h[(u>>3)]) } ref.Reset() return nil } // Size returns the number of bytes required to store the hash. func (*digest) Size() int { return HashSize } // BlockSize returns the block size of the hash. func (*digest) BlockSize() int { return int(BlockSize) } //////////////// 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 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) } //////////////// var kSpec = []uint64{ uint64(0x0000000000000001), uint64(0x0000000000008082), uint64(0x800000000000808A), uint64(0x8000000080008000), uint64(0x000000000000808B), uint64(0x0000000080000001), uint64(0x8000000080008081), uint64(0x8000000000008009), uint64(0x000000000000008A), uint64(0x0000000000000088), uint64(0x0000000080008009), uint64(0x000000008000000A), uint64(0x000000008000808B), uint64(0x800000000000008B), uint64(0x8000000000008089), uint64(0x8000000000008003), uint64(0x8000000000008002), uint64(0x8000000000000080), uint64(0x000000000000800A), uint64(0x800000008000000A), uint64(0x8000000080008081), uint64(0x8000000000008080), uint64(0x0000000080000001), uint64(0x8000000080008008), }