// Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package blake 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(128) //////////////// type digest struct { ptr uintptr h [8]uint64 t [2]uint64 b [BlockSize]byte } // New returns a new digest compute a BLAKE512 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 copy(ref.h[:], kInit[:]) ref.t[0], ref.t[1] = 0, 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 { h := ref.h[:] t := ref.t[:] t[0] = t[0] + 1024 if t[0] < 1024 { t[1] += 1 } ptr = 0 var vec [16]uint64 vec[0x0] = h[0] vec[0x1] = h[1] vec[0x2] = h[2] vec[0x3] = h[3] vec[0x4] = h[4] vec[0x5] = h[5] vec[0x6] = h[6] vec[0x7] = h[7] vec[0x8] = kSpec[0] vec[0x9] = kSpec[1] vec[0xA] = kSpec[2] vec[0xB] = kSpec[3] vec[0xC] = t[0] ^ kSpec[4] vec[0xD] = t[0] ^ kSpec[5] vec[0xE] = t[1] ^ kSpec[6] vec[0xF] = t[1] ^ kSpec[7] var mat [16]uint64 mat[0x0] = decUInt64be(ref.b[0:]) mat[0x1] = decUInt64be(ref.b[8:]) mat[0x2] = decUInt64be(ref.b[16:]) mat[0x3] = decUInt64be(ref.b[24:]) mat[0x4] = decUInt64be(ref.b[32:]) mat[0x5] = decUInt64be(ref.b[40:]) mat[0x6] = decUInt64be(ref.b[48:]) mat[0x7] = decUInt64be(ref.b[56:]) mat[0x8] = decUInt64be(ref.b[64:]) mat[0x9] = decUInt64be(ref.b[72:]) mat[0xA] = decUInt64be(ref.b[80:]) mat[0xB] = decUInt64be(ref.b[88:]) mat[0xC] = decUInt64be(ref.b[96:]) mat[0xD] = decUInt64be(ref.b[104:]) mat[0xE] = decUInt64be(ref.b[112:]) mat[0xF] = decUInt64be(ref.b[120:]) var sig []uint8 for r := uint8(0); r < 16; r++ { sig = kSigma[r][:] vec[0x0] = (vec[0x0] + vec[0x4] + (mat[sig[0x0]] ^ kSpec[sig[0x1]])) vec[0xC] = (((vec[0xC] ^ vec[0x0]) << (32)) | ((vec[0xC] ^ vec[0x0]) >> 32)) vec[0x8] = (vec[0x8] + vec[0xC]) vec[0x4] = (((vec[0x4] ^ vec[0x8]) << (39)) | ((vec[0x4] ^ vec[0x8]) >> 25)) vec[0x0] = (vec[0x0] + vec[0x4] + (mat[sig[0x1]] ^ kSpec[sig[0x0]])) vec[0xC] = (((vec[0xC] ^ vec[0x0]) << (48)) | ((vec[0xC] ^ vec[0x0]) >> 16)) vec[0x8] = (vec[0x8] + vec[0xC]) vec[0x4] = (((vec[0x4] ^ vec[0x8]) << (53)) | ((vec[0x4] ^ vec[0x8]) >> 11)) vec[0x1] = (vec[0x1] + vec[0x5] + (mat[sig[0x2]] ^ kSpec[sig[0x3]])) vec[0xD] = (((vec[0xD] ^ vec[0x1]) << (32)) | ((vec[0xD] ^ vec[0x1]) >> 32)) vec[0x9] = (vec[0x9] + vec[0xD]) vec[0x5] = (((vec[0x5] ^ vec[0x9]) << (39)) | ((vec[0x5] ^ vec[0x9]) >> 25)) vec[0x1] = (vec[0x1] + vec[0x5] + (mat[sig[0x3]] ^ kSpec[sig[0x2]])) vec[0xD] = (((vec[0xD] ^ vec[0x1]) << (48)) | ((vec[0xD] ^ vec[0x1]) >> 16)) vec[0x9] = (vec[0x9] + vec[0xD]) vec[0x5] = (((vec[0x5] ^ vec[0x9]) << (53)) | ((vec[0x5] ^ vec[0x9]) >> 11)) vec[0x2] = (vec[0x2] + vec[0x6] + (mat[sig[0x4]] ^ kSpec[sig[0x5]])) vec[0xE] = (((vec[0xE] ^ vec[0x2]) << (32)) | ((vec[0xE] ^ vec[0x2]) >> 32)) vec[0xA] = (vec[0xA] + vec[0xE]) vec[0x6] = (((vec[0x6] ^ vec[0xA]) << (39)) | ((vec[0x6] ^ vec[0xA]) >> 25)) vec[0x2] = (vec[0x2] + vec[0x6] + (mat[sig[0x5]] ^ kSpec[sig[0x4]])) vec[0xE] = (((vec[0xE] ^ vec[0x2]) << (48)) | ((vec[0xE] ^ vec[0x2]) >> 16)) vec[0xA] = (vec[0xA] + vec[0xE]) vec[0x6] = (((vec[0x6] ^ vec[0xA]) << (53)) | ((vec[0x6] ^ vec[0xA]) >> 11)) vec[0x3] = (vec[0x3] + vec[0x7] + (mat[sig[0x6]] ^ kSpec[sig[0x7]])) vec[0xF] = (((vec[0xF] ^ vec[0x3]) << (32)) | ((vec[0xF] ^ vec[0x3]) >> 32)) vec[0xB] = (vec[0xB] + vec[0xF]) vec[0x7] = (((vec[0x7] ^ vec[0xB]) << (39)) | ((vec[0x7] ^ vec[0xB]) >> 25)) vec[0x3] = (vec[0x3] + vec[0x7] + (mat[sig[0x7]] ^ kSpec[sig[0x6]])) vec[0xF] = (((vec[0xF] ^ vec[0x3]) << (48)) | ((vec[0xF] ^ vec[0x3]) >> 16)) vec[0xB] = (vec[0xB] + vec[0xF]) vec[0x7] = (((vec[0x7] ^ vec[0xB]) << (53)) | ((vec[0x7] ^ vec[0xB]) >> 11)) vec[0x0] = (vec[0x0] + vec[0x5] + (mat[sig[0x8]] ^ kSpec[sig[0x9]])) vec[0xF] = (((vec[0xF] ^ vec[0x0]) << (32)) | ((vec[0xF] ^ vec[0x0]) >> 32)) vec[0xA] = (vec[0xA] + vec[0xF]) vec[0x5] = (((vec[0x5] ^ vec[0xA]) << (39)) | ((vec[0x5] ^ vec[0xA]) >> 25)) vec[0x0] = (vec[0x0] + vec[0x5] + (mat[sig[0x9]] ^ kSpec[sig[0x8]])) vec[0xF] = (((vec[0xF] ^ vec[0x0]) << (48)) | ((vec[0xF] ^ vec[0x0]) >> 16)) vec[0xA] = (vec[0xA] + vec[0xF]) vec[0x5] = (((vec[0x5] ^ vec[0xA]) << (53)) | ((vec[0x5] ^ vec[0xA]) >> 11)) vec[0x1] = (vec[0x1] + vec[0x6] + (mat[sig[0xA]] ^ kSpec[sig[0xB]])) vec[0xC] = (((vec[0xC] ^ vec[0x1]) << (32)) | ((vec[0xC] ^ vec[0x1]) >> 32)) vec[0xB] = (vec[0xB] + vec[0xC]) vec[0x6] = (((vec[0x6] ^ vec[0xB]) << (39)) | ((vec[0x6] ^ vec[0xB]) >> 25)) vec[0x1] = (vec[0x1] + vec[0x6] + (mat[sig[0xB]] ^ kSpec[sig[0xA]])) vec[0xC] = (((vec[0xC] ^ vec[0x1]) << (48)) | ((vec[0xC] ^ vec[0x1]) >> 16)) vec[0xB] = (vec[0xB] + vec[0xC]) vec[0x6] = (((vec[0x6] ^ vec[0xB]) << (53)) | ((vec[0x6] ^ vec[0xB]) >> 11)) vec[0x2] = (vec[0x2] + vec[0x7] + (mat[sig[0xC]] ^ kSpec[sig[0xD]])) vec[0xD] = (((vec[0xD] ^ vec[0x2]) << (32)) | ((vec[0xD] ^ vec[0x2]) >> 32)) vec[0x8] = (vec[0x8] + vec[0xD]) vec[0x7] = (((vec[0x7] ^ vec[0x8]) << (39)) | ((vec[0x7] ^ vec[0x8]) >> 25)) vec[0x2] = (vec[0x2] + vec[0x7] + (mat[sig[0xD]] ^ kSpec[sig[0xC]])) vec[0xD] = (((vec[0xD] ^ vec[0x2]) << (48)) | ((vec[0xD] ^ vec[0x2]) >> 16)) vec[0x8] = (vec[0x8] + vec[0xD]) vec[0x7] = (((vec[0x7] ^ vec[0x8]) << (53)) | ((vec[0x7] ^ vec[0x8]) >> 11)) vec[0x3] = (vec[0x3] + vec[0x4] + (mat[sig[0xE]] ^ kSpec[sig[0xF]])) vec[0xE] = (((vec[0xE] ^ vec[0x3]) << (32)) | ((vec[0xE] ^ vec[0x3]) >> 32)) vec[0x9] = (vec[0x9] + vec[0xE]) vec[0x4] = (((vec[0x4] ^ vec[0x9]) << (39)) | ((vec[0x4] ^ vec[0x9]) >> 25)) vec[0x3] = (vec[0x3] + vec[0x4] + (mat[sig[0xF]] ^ kSpec[sig[0xE]])) vec[0xE] = (((vec[0xE] ^ vec[0x3]) << (48)) | ((vec[0xE] ^ vec[0x3]) >> 16)) vec[0x9] = (vec[0x9] + vec[0xE]) vec[0x4] = (((vec[0x4] ^ vec[0x9]) << (53)) | ((vec[0x4] ^ vec[0x9]) >> 11)) } h[0] ^= vec[0x0] ^ vec[0x8] h[1] ^= vec[0x1] ^ vec[0x9] h[2] ^= vec[0x2] ^ vec[0xA] h[3] ^= vec[0x3] ^ vec[0xB] h[4] ^= vec[0x4] ^ vec[0xC] h[5] ^= vec[0x5] ^ vec[0xD] h[6] ^= vec[0x6] ^ vec[0xE] h[7] ^= vec[0x7] ^ vec[0xF] } } 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("Blake Close: dst min length: %d, got %d", HashSize, ln) } ptr := ref.ptr bln := uint64((ref.ptr << 3) + uintptr(bcnt)) tpl := ref.t[0] + bln tph := ref.t[1] var buf [BlockSize]uint8 { off := uint8(0x80) >> bcnt buf[ptr] = uint8((bits & -off) | off) } if ptr == 0 && bcnt == 0 { ref.t[0] = uint64(0xFFFFFFFFFFFFFC00) ref.t[1] = uint64(0xFFFFFFFFFFFFFFFF) } else if ref.t[0] == 0 { ref.t[0] = uint64(0xFFFFFFFFFFFFFC00) + bln ref.t[1] = uint64(ref.t[1] - 1) } else { ref.t[0] -= 1024 - bln } if bln <= 894 { buf[111] |= 1 encUInt64be(buf[112:], tph) encUInt64be(buf[120:], tpl) ref.Write(buf[ptr:]) } else { ref.Write(buf[ptr:]) ref.t[0] = uint64(0xFFFFFFFFFFFFFC00) ref.t[1] = uint64(0xFFFFFFFFFFFFFFFF) memset(buf[:112], 0) buf[111] = 1 encUInt64be(buf[112:], tph) encUInt64be(buf[120:], tpl) ref.Write(buf[:]) } for k := uintptr(0); k < 8; k++ { encUInt64be(dst[(k<<3):], ref.h[k]) } ref.Reset() return nil } // Size returns the number of bytes Sum will return. func (*digest) Size() int { return HashSize } // BlockSize returns the block size of the hash. func (*digest) BlockSize() int { return int(BlockSize) } //////////////// func memset(dst []byte, src byte) { for i := range dst { dst[i] = src } } func decUInt64be(src []byte) uint64 { return (uint64(src[0])<<56 | uint64(src[1])<<48 | uint64(src[2])<<40 | uint64(src[3])<<32 | uint64(src[4])<<24 | uint64(src[5])<<16 | uint64(src[6])<<8 | uint64(src[7])) } func encUInt64be(dst []byte, src uint64) { dst[0] = uint8(src >> 56) dst[1] = uint8(src >> 48) dst[2] = uint8(src >> 40) dst[3] = uint8(src >> 32) dst[4] = uint8(src >> 24) dst[5] = uint8(src >> 16) dst[6] = uint8(src >> 8) dst[7] = uint8(src) } //////////////// var kInit = [8]uint64{ uint64(0x6A09E667F3BCC908), uint64(0xBB67AE8584CAA73B), uint64(0x3C6EF372FE94F82B), uint64(0xA54FF53A5F1D36F1), uint64(0x510E527FADE682D1), uint64(0x9B05688C2B3E6C1F), uint64(0x1F83D9ABFB41BD6B), uint64(0x5BE0CD19137E2179), } var kSpec = [16]uint64{ uint64(0x243F6A8885A308D3), uint64(0x13198A2E03707344), uint64(0xA4093822299F31D0), uint64(0x082EFA98EC4E6C89), uint64(0x452821E638D01377), uint64(0xBE5466CF34E90C6C), uint64(0xC0AC29B7C97C50DD), uint64(0x3F84D5B5B5470917), uint64(0x9216D5D98979FB1B), uint64(0xD1310BA698DFB5AC), uint64(0x2FFD72DBD01ADFB7), uint64(0xB8E1AFED6A267E96), uint64(0xBA7C9045F12C7F99), uint64(0x24A19947B3916CF7), uint64(0x0801F2E2858EFC16), uint64(0x636920D871574E69), } var kSigma = [16][16]uint8{ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, }