-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathcrypto.py
70 lines (52 loc) · 1.85 KB
/
crypto.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import hashlib
from binascii import hexlify
def sha256(payload: bytes) -> bytes:
return hashlib.sha256(payload).digest()
def double_sha256(payload: bytes) -> bytes:
return sha256(sha256(payload))
def double_sha256_checksum(payload: bytes) -> bytes:
return double_sha256(payload)[:4]
def ripemd160_sha256(payload: bytes) -> bytes:
return hashlib.new('ripemd160', sha256(payload)).digest()
BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def b58_encode(payload: bytes) -> str:
pad = 0
for byte in payload:
if byte == 0:
pad += 1
else:
break
prefix = '1' * pad
num = int.from_bytes(payload, 'big')
result = ''
while num > 0:
num, remaining = divmod(num, 58)
result = BASE58_ALPHABET[remaining] + result
return prefix + result
def b58check_encode(payload: bytes) -> str:
return b58_encode(payload + double_sha256_checksum(payload))
def b58_decode(encoded: str) -> bytes:
pad = 0
for char in encoded:
if char == '1':
pad += 1
else:
break
prefix = b'\x00' * pad
num = 0
try:
for char in encoded:
num *= 58
num += BASE58_ALPHABET.index(char)
except KeyError:
raise ValueError(f'Invalid base58 encoded "{encoded}"')
# if num is 0 then (0).to_bytes will return b''
return prefix + num.to_bytes((num.bit_length() + 7) // 8, 'big')
def b58check_decode(encoded: str) -> bytes:
decoded = b58_decode(encoded)
payload = decoded[:-4]
decoded_checksum = decoded[-4:]
hash_checksum = double_sha256_checksum(payload)
if decoded_checksum != hash_checksum:
raise ValueError(f'Decoded checksum {hexlify(decoded_checksum)} from "{hexlify(decoded)}" is not equal to hash checksum {hexlify(hash_checksum)}')
return payload