33import ecdsa
44import re
55from binascii import hexlify , unhexlify
6- from .utils import sha256 , ripemd160 , str_to_hex , hex_to_int
6+ from .utils import sha256 , ripemd160
77from .signer import Signer
88import hashlib
9- import time
109import struct
1110import array
1211
12+ def get_curve (key_type ) :
13+ if key_type == 'R1' :
14+ return ecdsa .NIST256p
15+ return ecdsa .SECP256k1
16+
1317def check_wif (key ) :
1418 if isinstance (key , str ) :
1519 try :
@@ -19,89 +23,93 @@ def check_wif(key) :
1923 pass
2024 return False
2125
22- class EOSKey (Signer ) :
23- def __init__ (self , private_str = '' ) :
26+
27+ class EOSKey (Signer ):
28+ def __init__ (self , private_str = '' ):
2429 ''' '''
25- if private_str :
30+ if private_str :
2631 private_key , format , key_type = self ._parse_key (private_str )
27- self ._sk = ecdsa .SigningKey .from_string (unhexlify (private_key ), curve = ecdsa .SECP256k1 )
32+ self ._key_type = key_type
33+ self ._curve = get_curve (key_type )
34+ self ._sk = ecdsa .SigningKey .from_string (unhexlify (private_key ), curve = self ._curve )
2835 else :
2936 prng = self ._create_entropy ()
30- self ._sk = ecdsa .SigningKey .generate (curve = ecdsa .SECP256k1 , entropy = prng )
37+ self ._key_type = 'K1'
38+ self ._curve = get_curve (self ._key_type )
39+ self ._sk = ecdsa .SigningKey .generate (curve = self ._curve , entropy = prng )
3140 self ._vk = self ._sk .get_verifying_key ()
3241
33- def __str__ (self ) :
42+ def __str__ (self ):
3443 return self .to_public ()
35-
36- def _parse_key (self , private_str ) :
44+
45+ def _parse_key (self , private_str ):
3746 ''' '''
3847 match = re .search ('^PVT_([A-Za-z0-9]+)_([A-Za-z0-9]+)$' , private_str )
39- if not match :
40- # legacy WIF - format
48+ if not match :
49+ # legacy WIF - format
4150 version_key = self ._check_decode (private_str , 'sha256x2' )
4251 # ensure first 2 chars == 0x80
43- version = int (version_key [0 :2 ],16 )
44- if not version == 0x80 :
52+ version = int (version_key [0 :2 ], 16 )
53+ if not version == 0x80 :
4554 raise ValueError ('Expected version 0x80, instead got {0}' , version )
4655 private_key = version_key [2 :]
4756 key_type = 'K1'
4857 format = 'WIF'
49- else :
58+ else :
5059 key_type , key_string = match .groups ()
5160 private_key = self ._check_decode (key_string , key_type )
5261 format = 'PVT'
5362 return (private_key , format , key_type )
5463
55- def _create_entropy (self ) :
64+ def _create_entropy (self ):
5665 ''' '''
5766 ba = bytearray (os .urandom (32 ))
5867 seed = sha256 (ba )
5968 return ecdsa .util .PRNG (seed )
6069
61- def _check_encode (self , key_buffer , key_type = None ) :
70+ def _check_encode (self , key_buffer , key_type = None ):
6271 ''' '''
63- if isinstance (key_buffer , bytes ) :
72+ if isinstance (key_buffer , bytes ):
6473 key_buffer = key_buffer .decode ()
6574 check = key_buffer
66- if key_type == 'sha256x2' :
75+ if key_type == 'sha256x2' :
6776 first_sha = sha256 (unhexlify (check ))
6877 chksum = sha256 (unhexlify (first_sha ))[:8 ]
69- else :
70- if key_type :
71- check += hexlify (bytearray (key_type ,'utf-8' )).decode ()
78+ else :
79+ if key_type :
80+ check += hexlify (bytearray (key_type , 'utf-8' )).decode ()
7281 chksum = ripemd160 (unhexlify (check ))[:8 ]
73- return base58 .b58encode (unhexlify (key_buffer + chksum ))
74-
75- def _check_decode (self , key_string , key_type = None ) :
82+ return base58 .b58encode (unhexlify (key_buffer + chksum ))
83+
84+ def _check_decode (self , key_string , key_type = None ):
7685 ''' '''
7786 buffer = hexlify (base58 .b58decode (key_string )).decode ()
7887 chksum = buffer [- 8 :]
7988 key = buffer [:- 8 ]
80- if key_type == 'sha256x2' :
89+ if key_type == 'sha256x2' :
8190 # legacy
8291 first_sha = sha256 (unhexlify (key ))
8392 newChk = sha256 (unhexlify (first_sha ))[:8 ]
84- else :
93+ else :
8594 check = key
86- if key_type :
95+ if key_type :
8796 check += hexlify (bytearray (key_type , 'utf-8' )).decode ()
8897 newChk = ripemd160 (unhexlify (check ))[:8 ]
8998 #print('newChk: '+newChk)
90- if chksum != newChk :
99+ if chksum != newChk :
91100 raise ValueError ('checksums do not match: {0} != {1}' .format (chksum , newChk ))
92101 return key
93102
94-
95- def _recover_key (self , digest , signature , i ) :
103+ def _recover_key (self , digest , signature , i ):
96104 ''' Recover the public key from the sig
97105 http://www.secg.org/sec1-v2.pdf
98106 '''
99- curve = ecdsa . SECP256k1 .curve
100- G = ecdsa . SECP256k1 .generator
101- order = ecdsa . SECP256k1 .order
107+ curve = self . _curve .curve
108+ G = self . _curve .generator
109+ order = self . _curve .order
102110 yp = (i % 2 )
103111 r , s = ecdsa .util .sigdecode_string (signature , order )
104- x = r + (i // 2 ) * order
112+ x = r + (i // 2 ) * order
105113 alpha = ((x * x * x ) + (curve .a () * x ) + curve .b ()) % curve .p ()
106114 beta = ecdsa .numbertheory .square_root_mod_prime (alpha , curve .p ())
107115 y = beta if (beta - yp ) % 2 == 0 else curve .p () - beta
@@ -111,21 +119,21 @@ def _recover_key(self, digest, signature, i) :
111119 # compute Q
112120 Q = ecdsa .numbertheory .inverse_mod (r , order ) * (s * R + (- e % order ) * G )
113121 # verify message
114- if not ecdsa .VerifyingKey .from_public_point (Q , curve = ecdsa . SECP256k1 ).verify_digest (signature , digest ,
122+ if not ecdsa .VerifyingKey .from_public_point (Q , curve = self . _curve ).verify_digest (signature , digest ,
115123 sigdecode = ecdsa .util .sigdecode_string ) :
116124 return None
117- return ecdsa .VerifyingKey .from_public_point (Q , curve = ecdsa . SECP256k1 )
125+ return ecdsa .VerifyingKey .from_public_point (Q , curve = self . _curve )
118126
119127 def _recovery_pubkey_param (self , digest , signature ) :
120128 ''' Use to derive a number that will allow for the easy recovery
121129 of the public key from the signature
122130 '''
123- for i in range (0 ,4 ) :
131+ for i in range (0 , 4 ) :
124132 p = self ._recover_key (digest , signature , i )
125- if (p .to_string () == self ._vk .to_string ()) :
133+ if (p .to_string () == self ._vk .to_string ()):
126134 return i
127135
128- def _compress_pubkey (self ) :
136+ def _compress_pubkey (self ):
129137 ''' '''
130138 order = self ._sk .curve .generator .order ()
131139 p = self ._vk .pubkey .point
@@ -142,12 +150,12 @@ def _is_canonical(self, sig):
142150 t4 = not (sig [33 ] == 0 and ((sig [34 ] & 0x80 ) == 0 ))
143151 return t1 and t2 and t3 and t4
144152
145- def to_public (self ) :
153+ def to_public (self ):
146154 ''' '''
147155 cmp = self ._compress_pubkey ()
148156 return 'EOS' + self ._check_encode (cmp ).decode ()
149-
150- def to_wif (self ) :
157+
158+ def to_wif (self ):
151159 ''' '''
152160 pri_key = '80' + hexlify (self ._sk .to_string ()).decode ()
153161 return self ._check_encode (pri_key , 'sha256x2' ).decode ()
@@ -157,25 +165,25 @@ def sign_string(self, data, encoding="utf-8"):
157165 digest = sha256 (bytearray (data , encoding ))
158166 return self .sign (digest )
159167
160- def sign (self , digest ) :
168+ def sign (self , digest ):
161169 ''' '''
162170 cnt = 0
163171 # convert digest to hex string
164172 digest = unhexlify (digest )
165- if len (digest ) != 32 :
173+ if len (digest ) != 32 :
166174 raise ValueError ("32 byte buffer required" )
167- while 1 :
175+ while 1 :
168176 # get deterministic k
169177 if cnt :
170178 sha_digest = hashlib .sha256 (digest + bytearray (cnt )).digest ()
171- else :
179+ else :
172180 sha_digest = hashlib .sha256 (digest ).digest ()
173- k = ecdsa .rfc6979 .generate_k ( self ._sk .curve .generator .order (),
174- self ._sk .privkey .secret_multiplier ,
175- hashlib .sha256 ,
176- # hashlib.sha256(digest + struct.pack('d', time.time())).digest() # use time to randomize
177- sha_digest
178- )
181+ k = ecdsa .rfc6979 .generate_k (self ._sk .curve .generator .order (),
182+ self ._sk .privkey .secret_multiplier ,
183+ hashlib .sha256 ,
184+ # hashlib.sha256(digest + struct.pack('d', time.time())).digest() # use time to randomize
185+ sha_digest
186+ )
179187 # sign the message
180188 sigder = self ._sk .sign_digest (digest , sigencode = ecdsa .util .sigencode_der , k = k )
181189
@@ -187,7 +195,7 @@ def sign(self, digest) :
187195 # ensure signature is canonical
188196 lenR = sigder [3 ]
189197 lenS = sigder [5 + lenR ]
190-
198+
191199 if lenR == 32 and lenS == 32 :
192200 # derive recover parameter
193201 i = self ._recovery_pubkey_param (digest , sig )
@@ -199,19 +207,19 @@ def sign(self, digest) :
199207 break
200208 # if self._is_canonical(sigstr):
201209 # break
202- cnt += 1
210+ cnt += 1
203211 if not cnt % 10 :
204212 print ('Still searching for a signature. Tried {} times.' .format (cnt ))
205213 # encode
206- return 'SIG_K1_ ' + self ._check_encode (hexlify (sigstr ), 'K1' ).decode ()
214+ return 'SIG_ ' + self ._key_type + '_' + self . _check_encode (hexlify (sigstr ), self . _key_type ).decode ()
207215
208- def verify (self , encoded_sig , digest ) :
216+ def verify (self , encoded_sig , digest ):
209217 ''' '''
210218 # remove SIG_ prefix
211219 encoded_sig = encoded_sig [4 :]
212220 # remove curve prefix
213221 curvePre = encoded_sig [:3 ].strip ('_' )
214- if curvePre != 'K1' :
222+ if curvePre != self . _key_type :
215223 raise TypeError ('Unsupported curve prefix {}' .format (curvePre ))
216224
217225 decoded_sig = self ._check_decode (encoded_sig [3 :], curvePre )
@@ -221,11 +229,10 @@ def verify(self, encoded_sig, digest) :
221229 sig = decoded_sig [2 :]
222230 # verify sig by recovering the key and comparing to self._vk
223231 # p = self._recover_key(unhexlify(digest), unhexlify(sig), recover_param)
224- #return self._vk.verify_digest(unhexlify(sig), unhexlify(digest), sigdecode=ecdsa.util.sigdecode_string)
232+ # return self._vk.verify_digest(unhexlify(sig), unhexlify(digest), sigdecode=ecdsa.util.sigdecode_string)
225233 # return p.to_string() == self._vk.to_string()
226234 try :
227235 self ._vk .verify_digest (unhexlify (sig ), unhexlify (digest ), sigdecode = ecdsa .util .sigdecode_string )
228236 except ecdsa .keys .BadSignatureError :
229237 return False
230238 return True
231-
0 commit comments