X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=internal%2Fgost34112012%2Fhash.go;h=21aed6f27cbdb67fda938922d1da5fe6ad4aa520;hb=5fc90f4d05f0515cc91dd9feceb813e2b753cbb7;hp=2c8fa3a072be6fb20823a0d63d88c5a4158bff58;hpb=e8c6bfbddd607aecd1494bca674d08d03249bd6b;p=gogost.git diff --git a/internal/gost34112012/hash.go b/internal/gost34112012/hash.go index 2c8fa3a..21aed6f 100644 --- a/internal/gost34112012/hash.go +++ b/internal/gost34112012/hash.go @@ -1,5 +1,5 @@ // GoGOST -- Pure Go GOST cryptographic functions library -// Copyright (C) 2015-2021 Sergey Matveev +// Copyright (C) 2015-2022 Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -198,6 +198,8 @@ var ( }, } a [64]uint64 // It is filled in init() + + cache [8][256]uint64 ) func init() { @@ -270,15 +272,34 @@ func init() { for i := 0; i < 64; i++ { a[i] = binary.BigEndian.Uint64(as[i]) } + for byteN := 0; byteN < 8; byteN++ { + for byteValN := 0; byteValN < 256; byteValN++ { + val := byte(byteValN) + res64 := uint64(0) + for bitN := 0; bitN < 8; bitN++ { + if val&0x80 > 0 { + res64 ^= a[(7-byteN)*8+bitN] + } + val <<= 1 + } + cache[byteN][byteValN] = res64 + } + } } type Hash struct { - size int - buf []byte - n uint64 - hsh *[BlockSize]byte - chk *[BlockSize]byte - tmp *[BlockSize]byte + size int + buf []byte + n uint64 + hsh []byte + chk []byte + tmp []byte + psBuf []byte + eMsgBuf []byte + eKBuf []byte + eXorBuf []byte + gBuf []byte + addBuf []byte } // Create new hash object with specified size digest size. @@ -287,10 +308,16 @@ func New(size int) *Hash { panic("size must be either 32 or 64") } h := Hash{ - size: size, - hsh: new([BlockSize]byte), - chk: new([BlockSize]byte), - tmp: new([BlockSize]byte), + size: size, + hsh: make([]byte, BlockSize), + chk: make([]byte, BlockSize), + tmp: make([]byte, BlockSize), + psBuf: make([]byte, BlockSize), + eMsgBuf: make([]byte, BlockSize), + eKBuf: make([]byte, BlockSize), + eXorBuf: make([]byte, BlockSize), + gBuf: make([]byte, BlockSize), + addBuf: make([]byte, BlockSize), } h.Reset() return &h @@ -320,9 +347,9 @@ func (h *Hash) Size() int { func (h *Hash) Write(data []byte) (int, error) { h.buf = append(h.buf, data...) for len(h.buf) >= BlockSize { - copy(h.tmp[:], h.buf[:BlockSize]) - h.hsh = g(h.n, h.hsh, h.tmp) - h.chk = add512bit(h.chk, h.tmp) + copy(h.tmp, h.buf[:BlockSize]) + copy(h.hsh, h.g(h.n, h.hsh, h.tmp)) + copy(h.chk, h.add512bit(h.chk, h.tmp)) h.n += BlockSize * 8 h.buf = h.buf[BlockSize:] } @@ -330,104 +357,100 @@ func (h *Hash) Write(data []byte) (int, error) { } func (h *Hash) Sum(in []byte) []byte { - buf := new([BlockSize]byte) - copy(h.tmp[:], buf[:]) - copy(buf[:], h.buf[:]) + buf := make([]byte, BlockSize) + hsh := make([]byte, BlockSize) + copy(h.tmp, buf) + copy(buf, h.buf) buf[len(h.buf)] = 1 - hsh := g(h.n, h.hsh, buf) - binary.LittleEndian.PutUint64(h.tmp[:], h.n+uint64(len(h.buf))*8) - hsh = g(0, hsh, h.tmp) - hsh = g(0, hsh, add512bit(h.chk, buf)) + copy(hsh, h.g(h.n, h.hsh, buf)) + binary.LittleEndian.PutUint64(h.tmp, h.n+uint64(len(h.buf))*8) + copy(hsh, h.g(0, hsh, h.tmp)) + copy(hsh, h.g(0, hsh, h.add512bit(h.chk, buf))) if h.size == 32 { return append(in, hsh[BlockSize/2:]...) } - return append(in, hsh[:]...) + return append(in, hsh...) } -func add512bit(chk, data *[BlockSize]byte) *[BlockSize]byte { +func (h *Hash) add512bit(chk, data []byte) []byte { var ss uint16 - r := new([BlockSize]byte) for i := 0; i < BlockSize; i++ { ss = uint16(chk[i]) + uint16(data[i]) + (ss >> 8) - r[i] = byte(0xFF & ss) + h.addBuf[i] = byte(0xFF & ss) } - return r + return h.addBuf } -func g(n uint64, hsh, data *[BlockSize]byte) *[BlockSize]byte { - ns := make([]byte, 8) - binary.LittleEndian.PutUint64(ns, n) - r := new([BlockSize]byte) - for i := 0; i < 8; i++ { - r[i] = hsh[i] ^ ns[i] - } - copy(r[8:], hsh[8:]) - return blockXor(blockXor(e(l(ps(r)), data), hsh), data) +func (h *Hash) g(n uint64, hsh, data []byte) []byte { + out := h.gBuf + copy(out, hsh) + out[0] ^= byte((n >> 0) & 0xFF) + out[1] ^= byte((n >> 8) & 0xFF) + out[2] ^= byte((n >> 16) & 0xFF) + out[3] ^= byte((n >> 24) & 0xFF) + out[4] ^= byte((n >> 32) & 0xFF) + out[5] ^= byte((n >> 40) & 0xFF) + out[6] ^= byte((n >> 48) & 0xFF) + out[7] ^= byte((n >> 56) & 0xFF) + return blockXor(out, blockXor(out, h.e(l(out, h.ps(out)), data), hsh), data) } -func e(k, msg *[BlockSize]byte) *[BlockSize]byte { +func (h *Hash) e(k, msg []byte) []byte { for i := 0; i < 12; i++ { - msg = l(ps(blockXor(k, msg))) - k = l(ps(blockXor(k, &c[i]))) + msg = l(h.eMsgBuf, h.ps(blockXor(h.eXorBuf, k, msg))) + k = l(h.eKBuf, h.ps(blockXor(h.eXorBuf, k, c[i][:]))) } - return blockXor(k, msg) + return blockXor(h.eXorBuf, k, msg) } -func blockXor(x, y *[BlockSize]byte) *[BlockSize]byte { - r := new([BlockSize]byte) +func blockXor(dst, x, y []byte) []byte { for i := 0; i < BlockSize; i++ { - r[i] = x[i] ^ y[i] + dst[i] = x[i] ^ y[i] } - return r + return dst } -func ps(data *[BlockSize]byte) *[BlockSize]byte { - r := new([BlockSize]byte) +func (h *Hash) ps(data []byte) []byte { for i := 0; i < BlockSize; i++ { - r[tau[i]] = pi[int(data[i])] + h.psBuf[tau[i]] = pi[int(data[i])] } - return r + return h.psBuf } -func l(data *[BlockSize]byte) *[BlockSize]byte { - var val uint64 - var res64 uint64 - var j int - r := new([BlockSize]byte) +func l(out, data []byte) []byte { for i := 0; i < 8; i++ { - val = binary.LittleEndian.Uint64(data[i*8 : i*8+8]) - res64 = 0 - for j = 0; j < BlockSize; j++ { - if val&0x8000000000000000 > 0 { - res64 ^= a[j] - } - val <<= 1 - } - binary.LittleEndian.PutUint64(r[i*8:i*8+8], res64) + res64 := uint64(0) + res64 ^= cache[0][data[8*i+0]] + res64 ^= cache[1][data[8*i+1]] + res64 ^= cache[2][data[8*i+2]] + res64 ^= cache[3][data[8*i+3]] + res64 ^= cache[4][data[8*i+4]] + res64 ^= cache[5][data[8*i+5]] + res64 ^= cache[6][data[8*i+6]] + res64 ^= cache[7][data[8*i+7]] + binary.LittleEndian.PutUint64(out[i*8:i*8+8], res64) } - return r + return out } func (h *Hash) MarshalBinary() (data []byte, err error) { - data = make([]byte, len(MarshaledName)+1+8+3*BlockSize+len(h.buf)) + data = make([]byte, len(MarshaledName)+1+8+2*BlockSize+len(h.buf)) copy(data, []byte(MarshaledName)) idx := len(MarshaledName) data[idx] = byte(h.size) idx += 1 binary.BigEndian.PutUint64(data[idx:idx+8], h.n) idx += 8 - copy(data[idx:], h.hsh[:]) + copy(data[idx:], h.hsh) idx += BlockSize - copy(data[idx:], h.chk[:]) - idx += BlockSize - copy(data[idx:], h.tmp[:]) + copy(data[idx:], h.chk) idx += BlockSize copy(data[idx:], h.buf) return } func (h *Hash) UnmarshalBinary(data []byte) error { - expectedLen := len(MarshaledName) + 1 + 8 + 3*BlockSize + expectedLen := len(MarshaledName) + 1 + 8 + 2*BlockSize if len(data) < expectedLen { return fmt.Errorf("gogost/internal/gost34112012: len(data) != %d", expectedLen) } @@ -439,11 +462,9 @@ func (h *Hash) UnmarshalBinary(data []byte) error { idx += 1 h.n = binary.BigEndian.Uint64(data[idx : idx+8]) idx += 8 - copy(h.hsh[:], data[idx:]) - idx += BlockSize - copy(h.chk[:], data[idx:]) + copy(h.hsh, data[idx:]) idx += BlockSize - copy(h.tmp[:], data[idx:]) + copy(h.chk, data[idx:]) idx += BlockSize h.buf = data[idx:] return nil