:param digest_size: hash digest size to compute
:type digest_size: 32 or 64 bytes
"""
- self.data = data
self._digest_size = digest_size
+ self.hsh = BLOCKSIZE * (b"\x01" if digest_size == 32 else b"\x00")
+ self.chk = bytearray(BLOCKSIZE * b"\x00")
+ self.n = 0
+ self.buf = b""
+ self.update(data)
def copy(self):
- return GOST34112012(copy(self.data), self.digest_size)
+ obj = GOST34112012()
+ obj._digest_size = self._digest_size
+ obj.hsh = self.hsh
+ obj.chk = copy(self.chk)
+ obj.n = self.n
+ obj.buf = self.buf
+ return obj
@property
def digest_size(self):
return self._digest_size
+ def _update_block(self, block):
+ self.hsh = g(self.n, self.hsh, block)
+ self.chk = add512bit(self.chk, block)
+ self.n += 512
+
def update(self, data):
- """Append data that has to be hashed
+ """Update state with the new data
"""
- self.data += data
+ if len(self.buf) > 0:
+ self.buf += data[:BLOCKSIZE - len(self.buf)]
+ data = data[BLOCKSIZE - len(self.buf):]
+ if len(self.buf) == BLOCKSIZE:
+ self._update_block(self.buf)
+ self.buf = b""
+ while len(data) >= BLOCKSIZE:
+ self._update_block(data[:BLOCKSIZE])
+ data = data[BLOCKSIZE:]
+ self.buf += data
def digest(self):
"""Get hash of the provided data
"""
- hsh = BLOCKSIZE * (b"\x01" if self.digest_size == 32 else b"\x00")
- chk = bytearray(BLOCKSIZE * b"\x00")
- n = 0
- data = self.data
- for i in xrange(0, len(data) // BLOCKSIZE * BLOCKSIZE, BLOCKSIZE):
- block = data[i:i + BLOCKSIZE]
- hsh = g(n, hsh, block)
- chk = add512bit(chk, block)
- n += 512
+ data = self.buf
# Padding
- padblock_size = len(data) * 8 - n
+ padblock_size = len(data) * 8
data += b"\x01"
- padlen = BLOCKSIZE - len(data) % BLOCKSIZE
+ padlen = BLOCKSIZE - len(data)
if padlen != BLOCKSIZE:
data += b"\x00" * padlen
- hsh = g(n, hsh, data[-BLOCKSIZE:])
- n += padblock_size
- chk = add512bit(chk, data[-BLOCKSIZE:])
+ hsh = g(self.n, self.hsh, data)
+ n = self.n + padblock_size
+ chk = add512bit(self.chk, data)
hsh = g(0, hsh, pack("<Q", n) + 56 * b"\x00")
hsh = g(0, hsh, chk)
return hsh[-self._digest_size:]