Skip to content
This repository was archived by the owner on Jan 24, 2024. It is now read-only.

Commit c29c3ca

Browse files
authored
Merge pull request #67 from eosnewyork/release/2.1.x
Release/2.1.x
2 parents ed55d65 + 0310e29 commit c29c3ca

19 files changed

+844
-572
lines changed

eospy/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-

eospy/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '2.0.1'
1+
__version__ = '2.1.0'

eospy/cleos.py

Lines changed: 134 additions & 137 deletions
Large diffs are not rendered by default.

eospy/command_line.py

Lines changed: 79 additions & 74 deletions
Large diffs are not rendered by default.

eospy/dynamic_url.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,43 @@
33
#
44
import requests
55

6-
class DynamicUrl :
7-
#def __init__(self, url='http://localhost:8888', version='v1', cache=None) :
8-
def __init__(self, url='http://localhost:8888', version='v1', cache=None) :
6+
7+
class DynamicUrl:
8+
# def __init__(self, url='http://localhost:8888', version='v1', cache=None) :
9+
def __init__(self, url='http://localhost:8888', version='v1', cache=None):
910
self._cache = cache or []
1011
self._baseurl = url
1112
self._version = version
1213

13-
def __getattr__(self, name) :
14+
def __getattr__(self, name):
1415
return self._(name)
1516

16-
def __del__(self) :
17+
def __del__(self):
1718
pass
1819

19-
def _(self, name) :
20-
return DynamicUrl(url=self._baseurl, version=self._version, cache=self._cache+[name])
20+
def _(self, name):
21+
return DynamicUrl(url=self._baseurl, version=self._version, cache=self._cache + [name])
2122

22-
def method(self) :
23+
def method(self):
2324
return self._cache
24-
25+
2526
def create_url(self):
26-
url_str = '{0}/{1}'.format(self._baseurl,self._version)
27-
for obj in self.method() :
27+
url_str = '{0}/{1}'.format(self._baseurl, self._version)
28+
for obj in self.method():
2829
url_str = '{0}/{1}'.format(url_str, obj)
2930
return url_str
3031

31-
def get_url(self, url, params=None, json=None, timeout=30) :
32+
def get_url(self, url, params=None, json=None, timeout=30):
3233
# get request
33-
r = requests.get(url,params=params, json=json, timeout=timeout)
34+
r = requests.get(url, params=params, json=json, timeout=timeout)
3435
r.raise_for_status()
3536
return r.json()
3637

37-
def post_url(self, url, params=None, json=None, data=None, timeout=30) :
38+
def post_url(self, url, params=None, json=None, data=None, timeout=30):
3839
# post request
39-
r = requests.post(url,params=params, json=json, data=data, timeout=timeout)
40-
try :
40+
r = requests.post(url, params=params, json=json, data=data, timeout=timeout)
41+
try:
4142
r.raise_for_status()
42-
except :
43+
except:
4344
raise requests.exceptions.HTTPError('Error: {}'.format(r.json()))
4445
return r.json()

eospy/exceptions.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,47 @@ class InvalidKeyFile(Exception):
33
''' Raised when the key file format is invalid '''
44
pass
55

6+
67
class InvalidPermissionFormat(Exception):
78
''' Raised when the permission format is invalid'''
89
pass
910

11+
1012
class EOSKeyError(Exception):
1113
''' Raised when there is an EOSKey error '''
1214
pass
1315

16+
1417
class EOSMsigInvalidProposal(Exception):
1518
''' Raised when an invalid proposal is queried'''
1619
pass
1720

21+
1822
class EOSBufferInvalidType(Exception):
1923
''' Raised when trying to encode/decode an invalid type '''
2024
pass
2125

26+
2227
class EOSInvalidSchema(Exception):
2328
''' Raised when trying to process a schema '''
2429
pass
2530

31+
2632
class EOSUnknownObj(Exception):
2733
''' Raised when an object is not found in the ABI '''
2834
pass
2935

36+
3037
class EOSAbiProcessingError(Exception):
3138
''' Raised when the abi action cannot be processed '''
3239
pass
3340

41+
3442
class EOSSetSameCode(Exception):
3543
''' Raised when the code would not change on a set'''
3644
pass
3745

46+
3847
class EOSSetSameAbi(Exception):
3948
''' Raised when the abi would not change on a set'''
40-
pass
49+
pass

eospy/keys.py

Lines changed: 67 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
import ecdsa
44
import re
55
from binascii import hexlify, unhexlify
6-
from .utils import sha256, ripemd160, str_to_hex, hex_to_int
6+
from .utils import sha256, ripemd160
77
from .signer import Signer
88
import hashlib
9-
import time
109
import struct
1110
import array
1211

12+
def get_curve(key_type) :
13+
if key_type == 'R1' :
14+
return ecdsa.NIST256p
15+
return ecdsa.SECP256k1
16+
1317
def 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

Comments
 (0)