]> Cypherpunks.ru repositories - pygost.git/blobdiff - pygost/gost34112012.py
Auto fill Streebog's cache
[pygost.git] / pygost / gost34112012.py
index b753274243688664da794930434e8f552bbb6421..ae7627bf23703cb4b8903385b32abb61d521bb67 100644 (file)
@@ -1,11 +1,10 @@
 # coding: utf-8
 # PyGOST -- Pure Python GOST cryptographic functions library
-# Copyright (C) 2015-2019 Sergey Matveev <stargrave@stargrave.org>
+# Copyright (C) 2015-2021 Sergey Matveev <stargrave@stargrave.org>
 #
 # 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
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# the Free Software Foundation, version 3 of the License.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -14,7 +13,7 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
-""" GOST R 34.11-2012 (Streebog) hash function common files
+"""GOST R 34.11-2012 (Streebog) hash function common files
 
 This is implementation of :rfc:`6986`. Most function and variable names are
 taken according to specification's terminology.
@@ -27,11 +26,10 @@ from struct import unpack
 from pygost.iface import PEP247
 from pygost.utils import hexdec
 from pygost.utils import strxor
-from pygost.utils import xrange  # pylint: disable=redefined-builtin
+from pygost.utils import xrange
 
 
 BLOCKSIZE = 64
-# pylint: disable=bad-whitespace,bad-continuation
 Pi = bytearray((
     252, 238, 221,  17, 207, 110,  49,  22, 251, 196, 250,
     218,  35, 197,   4,  77, 233, 119, 240, 219, 147,  46,
@@ -88,7 +86,6 @@ Tau = (
     6, 14, 22, 30, 38, 46, 54, 62,
     7, 15, 23, 31, 39, 47, 55, 63,
 )
-# pylint: disable=bad-whitespace,bad-continuation
 
 C = [hexdec("".join(s))[::-1] for s in (
     (
@@ -166,8 +163,28 @@ C = [hexdec("".join(s))[::-1] for s in (
 )]
 
 
+def _lcache():
+    cache = []
+    for byteN in xrange(8):
+        cache.append([0 for _ in xrange(256)])
+    for byteN in xrange(8):
+        for byteVal in xrange(256):
+            res64 = 0
+            val = byteVal
+            for bitN in xrange(8):
+                if val & 0x80 > 0:
+                    res64 ^= A[(7 - byteN) * 8 + bitN]
+                val <<= 1
+            cache[byteN][byteVal] = res64
+    return cache
+
+
+# Trade memory for CPU for part of L() calculations
+LCache = _lcache()
+
+
 def add512bit(a, b):
-    """ Add two 512 integers
+    """Add two 512 integers
     """
     a = bytearray(a)
     b = bytearray(b)
@@ -205,18 +222,15 @@ def PS(data):
 def L(data):
     res = []
     for i in range(8):
-        val = unpack("<Q", data[i * 8:i * 8 + 8])[0]
         res64 = 0
-        for j in range(BLOCKSIZE):
-            if val & 0x8000000000000000:
-                res64 ^= A[j]
-            val <<= 1
+        for j in range(8):
+            res64 ^= LCache[j][data[8 * i + j]]
         res.append(pack("<Q", res64))
     return b"".join(res)
 
 
 class GOST34112012(PEP247):
-    """ GOST 34.11-2012 big-endian hash
+    """GOST 34.11-2012 big-endian hash
 
     >>> m = GOST34112012(digest_size=32)
     >>> m.update("foo")
@@ -242,12 +256,12 @@ class GOST34112012(PEP247):
         return self._digest_size
 
     def update(self, data):
-        """ Append data that has to be hashed
+        """Append data that has to be hashed
         """
         self.data += data
 
     def digest(self):
-        """ Get hash of the provided data
+        """Get hash of the provided data
         """
         hsh = BLOCKSIZE * (b"\x01" if self.digest_size == 32 else b"\x00")
         chk = bytearray(BLOCKSIZE * b"\x00")