]> Cypherpunks.ru repositories - pygost.git/blob - pygost/utils.py
fb0ccca49101ca9e43b3ddd0187a5dd1aee274a5
[pygost.git] / pygost / utils.py
1 # coding: utf-8
2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2020 Sergey Matveev <stargrave@stargrave.org>
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, version 3 of the License.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 from codecs import getdecoder
18 from codecs import getencoder
19 from sys import version_info
20
21
22 xrange = range if version_info[0] == 3 else xrange
23
24
25 def strxor(a, b):
26     """XOR of two strings
27
28     This function will process only shortest length of both strings,
29     ignoring remaining one.
30     """
31     mlen = min(len(a), len(b))
32     a, b, xor = bytearray(a), bytearray(b), bytearray(mlen)
33     for i in xrange(mlen):
34         xor[i] = a[i] ^ b[i]
35     return bytes(xor)
36
37
38 _hexdecoder = getdecoder("hex")
39 _hexencoder = getencoder("hex")
40
41
42 def hexdec(data):
43     """Decode hexadecimal
44     """
45     return _hexdecoder(data)[0]
46
47
48 def hexenc(data):
49     """Encode hexadecimal
50     """
51     return _hexencoder(data)[0].decode("ascii")
52
53
54 def bytes2long(raw):
55     """Deserialize big-endian bytes into long number
56
57     :param bytes raw: binary string
58     :returns: deserialized long number
59     :rtype: int
60     """
61     return int(hexenc(raw), 16)
62
63
64 def long2bytes(n, size=32):
65     """Serialize long number into big-endian bytestring
66
67     :param long n: long number
68     :returns: serialized bytestring
69     :rtype: bytes
70     """
71     res = hex(int(n))[2:].rstrip("L")
72     if len(res) % 2 != 0:
73         res = "0" + res
74     s = hexdec(res)
75     if len(s) != size:
76         s = (size - len(s)) * b"\x00" + s
77     return s
78
79
80 def modinvert(a, n):
81     """Modular multiplicative inverse
82
83     :returns: inverse number. -1 if it does not exist
84
85     Realization is taken from:
86     https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
87     """
88     if a < 0:
89         # k^-1 = p - (-k)^-1 mod p
90         return n - modinvert(-a, n)
91     t, newt = 0, 1
92     r, newr = n, a
93     while newr != 0:
94         quotinent = r // newr
95         t, newt = newt, t - quotinent * newt
96         r, newr = newr, r - quotinent * newr
97     if r > 1:
98         return -1
99     if t < 0:
100         t = t + n
101     return t