]> Cypherpunks.ru repositories - pygost.git/commitdiff
Streaming 34.11-2012
authorSergey Matveev <stargrave@stargrave.org>
Wed, 23 Mar 2022 12:33:04 +0000 (15:33 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Wed, 23 Mar 2022 12:33:04 +0000 (15:33 +0300)
news.texi
pygost/__init__.py
pygost/gost34112012.py

index eeacd5567185920cfd590053c128c2079471b2e4..ed7795dc2fdd3a9ca6fb2d46c626b9ece153de29 100644 (file)
--- a/news.texi
+++ b/news.texi
@@ -3,6 +3,11 @@
 
 @table @strong
 
+@anchor{Release 5.11}
+@item 5.11
+@code{gost34112012}'s @code{update()}/@code{digest()} methods are
+streaming now -- they do not store the whole data in memory.
+
 @anchor{Release 5.10}
 @item 5.10
 Added ISO 10126 @code{pygost.gost3413.(un)pad_iso10126} padding support.
index 38d8dbe3c7a5a5c4d29dec94e850ce514a819166..54bee02b49c87621769e4740a73d59b85285db9f 100644 (file)
@@ -3,4 +3,4 @@
 PyGOST is free software: see the file COPYING for copying conditions.
 """
 
-__version__ = "5.10"
+__version__ = "5.11"
index f680eeeac0d83cd69fc1564f2ef655302a655212..f1a7acc84a9dc9f1e28377d2ad46548136b3f168 100644 (file)
@@ -245,44 +245,60 @@ class GOST34112012(PEP247):
         :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:]