-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPrivateKey.py
85 lines (73 loc) · 3 KB
/
PrivateKey.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
import hashlib
import hmac
from random import randint
from unittest import TestCase
from AddressCoder import encode_base58_checksum
from S256Point import SECP_256K1_G, SECP_256K1_N, Signature
class PrivateKey:
def __init__(self, secret):
self.secret = secret
self.point = secret * SECP_256K1_G
def hex(self):
return '{:x}'.format(self.secret).zfill(64)
def sign(self, z):
k = self.deterministic_k(z)
r = (k * SECP_256K1_G).x.num
k_inv = pow(k, (SECP_256K1_N - 2), SECP_256K1_N)
s = (z + r * self.secret) * k_inv % SECP_256K1_N
if s > SECP_256K1_N / 2:
s = SECP_256K1_N - s
return Signature(r, s)
def deterministic_k(self, z):
"""
RFC 6979
IMPORTANT: every signature must has a deterministic unique k.
"""
k = b'\x00' * 32
v = b'\x01' * 32
if z > SECP_256K1_N:
z -= SECP_256K1_N
z_bytes = z.to_bytes(32, 'big')
secret_bytes = self.secret.to_bytes(32, 'big')
s256 = hashlib.sha256
k = hmac.new(k, v + b'\x00' + secret_bytes + z_bytes, s256).digest()
v = hmac.new(k, v, s256).digest()
k = hmac.new(k, v + b'\x01' + secret_bytes + z_bytes, s256).digest()
v = hmac.new(k, v, s256).digest()
while True:
v = hmac.new(k, v, s256).digest()
candidate = int.from_bytes(v, 'big')
if 1 <= candidate < SECP_256K1_N:
return candidate
k = hmac.new(k, v + b'\x00', s256).digest()
v = hmac.new(k, v, s256).digest()
def wif(self, compressed=True, testnet=False):
secret_bytes = self.secret.to_bytes(32, 'big')
if testnet:
prefix = b'\xef'
else:
prefix = b'\x80'
if compressed:
suffix = b'\x01'
else:
suffix = b''
return encode_base58_checksum(prefix + secret_bytes + suffix)
class PrivateKeyTest(TestCase):
def test_sign(self):
pk = PrivateKey(randint(0, SECP_256K1_N))
z = randint(0, 2**256)
sig = pk.sign(z)
self.assertTrue(pk.point.verify(z, sig))
def test_wif(self):
pk = PrivateKey(2**256 - 2**199)
expected = 'L5oLkpV3aqBJ4BgssVAsax1iRa77G5CVYnv9adQ6Z87te7TyUdSC'
self.assertEqual(pk.wif(compressed=True, testnet=False), expected)
pk = PrivateKey(2**256 - 2**201)
expected = '93XfLeifX7Jx7n7ELGMAf1SUR6f9kgQs8Xke8WStMwUtrDucMzn'
self.assertEqual(pk.wif(compressed=False, testnet=True), expected)
pk = PrivateKey(0x0dba685b4511dbd3d368e5c4358a1277de9486447af7b3604a69b8d9d8b7889d)
expected = '5HvLFPDVgFZRK9cd4C5jcWki5Skz6fmKqi1GQJf5ZoMofid2Dty'
self.assertEqual(pk.wif(compressed=False, testnet=False), expected)
pk = PrivateKey(0x1cca23de92fd1862fb5b76e5f4f50eb082165e5191e116c18ed1a6b24be6a53f)
expected = 'cNYfWuhDpbNM1JWc3c6JTrtrFVxU4AGhUKgw5f93NP2QaBqmxKkg'
self.assertEqual(pk.wif(compressed=True, testnet=True), expected)