-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathmeta.py
117 lines (92 loc) · 4.2 KB
/
meta.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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
from binascii import hexlify
from crypto import ripemd160_sha256, b58check_encode, b58check_decode, sha256, b58_encode
from ec_point_operation import curve
def int_to_varint(value: int) -> bytes:
if value <= 0xfc:
return value.to_bytes(1, 'little')
elif value <= 0xffff:
return b'\xfd' + value.to_bytes(2, 'little')
elif value <= 0xffffffff:
return b'\xfe' + value.to_bytes(4, 'little')
else:
return b'\xff' + value.to_bytes(8, 'little')
def serialize_public_key(public_key: tuple, compressed: bool = True) -> bytes:
"""Serialize public key point to compressed format (02 || x) or (03 || x), or uncompressed format (04 || x || y)"""
x, y = public_key
if compressed:
return (b'\x02' if y % 2 == 0 else b'\x03') + x.to_bytes(32, byteorder='big')
return b'\x04' + x.to_bytes(32, byteorder='big') + y.to_bytes(32, byteorder='big')
def public_key_hash(public_key: tuple, compressed: bool = True) -> bytes:
public_key_bytes = serialize_public_key(public_key, compressed)
return ripemd160_sha256(public_key_bytes)
def public_key_to_address(public_key: tuple, compressed: bool = True) -> str:
return b58check_encode(b'\x00' + public_key_hash(public_key, compressed))
def address_to_public_key_hash(address: str) -> bytes:
"""Decode p2pkh address to public key hash"""
decoded = b58check_decode(address)
assert decoded[:1] == b'\x00'
return decoded[1:]
OP_DUP = b'\x76'
OP_HASH160 = b'\xa9'
OP_PUSH_20 = b'\x14'
OP_EQUALVERIFY = b'\x88'
OP_CHECKSIG = b'\xac'
def build_locking_script(pkh: bytes) -> bytes:
"""Build p2pkh locking script for the given public key hash"""
script = OP_DUP + OP_HASH160 + OP_PUSH_20 + pkh + OP_EQUALVERIFY + OP_CHECKSIG
return int_to_varint(len(script)) + script
def serialize_signature(signature: tuple) -> bytes:
"""Serialize ECDSA signature (r, s) to bitcoin strict DER format."""
r, s = signature
# BIP-62, BIP-66
# Enforce low s value in signature
# Using (curve.n - s) if s > 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0
# https://en.bitcoin.it/wiki/Transaction_malleability
if s > curve.n // 2:
s = curve.n - s
# r
r_bytes = r.to_bytes(32, byteorder='big').lstrip(b'\x00')
if r_bytes[0] & 0x80:
r_bytes = b'\x00' + r_bytes
serialized = bytes([2, len(r_bytes)]) + r_bytes
# s
s_bytes = s.to_bytes(32, byteorder='big').lstrip(b'\x00')
if s_bytes[0] & 0x80:
s_bytes = b'\x00' + s_bytes
serialized += bytes([2, len(s_bytes)]) + s_bytes
return bytes([0x30, len(serialized)]) + serialized
def deserialize_signature(serialized: bytes) -> tuple:
"""Deserialize ECDSA bitcoin DER formatted signature to (r, s)"""
try:
assert serialized[0] == 0x30
assert int(serialized[1]) == len(serialized) - 2
# r
assert serialized[2] == 0x02
r_len = int(serialized[3])
r = int.from_bytes(serialized[4: 4 + r_len], byteorder='big')
# s
assert serialized[4 + r_len] == 0x02
s_len = int(serialized[5 + r_len])
s = int.from_bytes(serialized[-s_len:], byteorder='big')
return r, s
except Exception:
raise ValueError(f'Invalid DER encoded {hexlify(serialized)}.')
def private_key_to_wif(private_key: int, compressed: bool = True) -> str:
payload = b'\x80' + private_key.to_bytes(32, byteorder='big')
if compressed:
payload += b'\x01'
checksum = sha256(sha256(payload))[0:4]
return b58_encode(payload + checksum)
def wif_to_private_key(wif: str) -> int:
if not wif.startswith('5') and not wif.startswith('K') and not wif.startswith('L'):
raise ValueError(f'Invalid WIF {wif}')
payload = b58check_decode(wif)
if wif.startswith('K') or wif.startswith('L'):
payload = payload[:-1]
return int.from_bytes(payload[1:], byteorder='big')
if __name__ == '__main__':
sig = (114587593887127314608220924841831336233967095853165151956820984900193959037698, 24000727837347392504013031837120627225728348681623127776947626422811445180558)
serialized_sig = serialize_signature(sig)
print(hexlify(serialized_sig))
decoded_sig = deserialize_signature(serialized_sig)
print(decoded_sig == sig)