Skip to content
This repository was archived by the owner on May 23, 2023. It is now read-only.

Commit ffb4f27

Browse files
vubvub
authored andcommitted
Moved ecrecover and signing to a function in utils
1 parent 436bedc commit ffb4f27

File tree

5 files changed

+93
-84
lines changed

5 files changed

+93
-84
lines changed

ethereum/specials.py

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
# -*- coding: utf8 -*-
22
import bitcoin
33
from rlp.utils import ascii_chr
4-
try:
5-
from secp256k1 import PublicKey, ALL_FLAGS
6-
except:
7-
pass
84

95
from ethereum import utils, opcodes
106
from ethereum.utils import safe_ord, decode_hex
@@ -32,34 +28,11 @@ def proc_ecrecover(ext, msg):
3228

3329
if r >= bitcoin.N or s >= bitcoin.N or v < 27 or v > 28:
3430
return 1, msg.gas - opcodes.GECRECOVER, []
35-
3631
try:
37-
signature_bytes = [0] * 64
38-
msg.data.extract_copy(signature_bytes, 0, 64, 32)
39-
msg.data.extract_copy(signature_bytes, 32, 96, 32)
40-
signature = b''.join(map(ascii_chr, signature_bytes))
41-
42-
pk = PublicKey(flags=ALL_FLAGS)
43-
try:
44-
pk.public_key = pk.ecdsa_recover(
45-
message_hash,
46-
pk.ecdsa_recoverable_deserialize(
47-
signature,
48-
v - 27
49-
),
50-
raw=True
51-
)
52-
except Exception:
53-
# Recovery failed
54-
return 1, msg.gas - gas_cost, []
55-
56-
pub = pk.serialize(compressed=False)
32+
pub = utils.ecrecover_to_pub(message_hash, v, r, s)
5733
except:
58-
recovered_addr = bitcoin.ecdsa_raw_recover(message_hash, (v, r, s))
59-
if recovered_addr in (False, (0, 0)):
60-
return 1, msg.gas - gas_cost, []
61-
pub = bitcoin.encode_pubkey(recovered_addr, 'bin')
62-
o = [0] * 12 + [safe_ord(x) for x in utils.sha3(pub[1:])[-20:]]
34+
return 1, msg.gas - gas_cost, []
35+
o = [0] * 12 + [safe_ord(x) for x in utils.sha3(pub)[-20:]]
6336
return 1, msg.gas - gas_cost, o
6437

6538

ethereum/testutils.py

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
from ethereum.db import EphemDB
1111
from ethereum.utils import to_string, safe_ord, parse_int_or_hex, zpad
1212
from ethereum.utils import remove_0x_head, int_to_hex, normalize_address
13+
from ethereum.block import FakeHeader
1314
from ethereum.config import Env
15+
from ethereum.config import default_config
1416
from ethereum import state_transition
1517
from state import State
1618
import json
@@ -44,7 +46,7 @@
4446
check_vm_test = lambda params: run_vm_test(params, VERIFY)
4547
time_vm_test = lambda params: run_vm_test(params, TIME)
4648
fill_state_test = lambda params: run_state_test(params, FILL)
47-
check_state_test = lambda params: run_state_test(params, VERIFY)
49+
check_state_test = lambda params: run_state_test1(params, VERIFY)
4850
time_state_test = lambda params: run_state_test(params, TIME)
4951
fill_ethash_test = lambda params: run_ethash_test(params, FILL)
5052
check_ethash_test = lambda params: run_ethash_test(params, VERIFY)
@@ -60,7 +62,10 @@
6062

6163

6264
def normalize_hex(s):
63-
s = (s if len(s) > 2 else b'0x00')
65+
if s[:2] != '0x':
66+
s = '0x' + s
67+
if s == '0x':
68+
s = '0x00'
6469
if len(s) < 66:
6570
s = s[:2] + b'0' * (66 - len(s)) + s[2:]
6671
return s
@@ -278,12 +283,6 @@ def normalize_value(k, p):
278283
elif mode == TIME:
279284
return time_post - time_pre
280285

281-
282-
class FakeHeader():
283-
def __init__(self, h):
284-
self.hash = h
285-
self.uncles = []
286-
287286
fake_headers = {}
288287

289288
def mk_fake_header(blknum):
@@ -300,13 +299,16 @@ def run_state_test1(params, mode):
300299
'previousHash', 'currentCoinbase',
301300
'currentDifficulty', 'currentNumber'])
302301
assert len(env['currentCoinbase']) == 40
302+
303+
default_config['HOMESTEAD_FORK_BLKNUM'] = 1000000
303304

304305
state = State(db=db,
305306
prev_headers=[mk_fake_header(i) for i in range(parse_int_or_hex(env['currentNumber']) -1, max(-1, parse_int_or_hex(env['currentNumber']) -257), -1)],
306307
block_number=parse_int_or_hex(env['currentNumber']),
307308
block_coinbase=utils.normalize_address(env['currentCoinbase']),
308309
timestamp=parse_int_or_hex(env['currentTimestamp']),
309-
gas_limit=parse_int_or_hex(env['currentGasLimit']))
310+
gas_limit=parse_int_or_hex(env['currentGasLimit']),
311+
block_difficulty=parse_int_or_hex(env['currentDifficulty']))
310312
# setup state
311313
for address, h in list(pre.items()):
312314
assert len(address) == 40
@@ -342,6 +344,7 @@ def run_state_test1(params, mode):
342344
success, output = False, b''
343345
time_pre = time.time()
344346
time_post = time_pre
347+
state.commit()
345348
else:
346349
if 'secretKey' in exek:
347350
tx.sign(exek['secretKey'])
@@ -354,7 +357,6 @@ def run_state_test1(params, mode):
354357

355358
time_pre = time.time()
356359
state.commit()
357-
print state.to_dict()
358360
snapshot = state.snapshot()
359361
try:
360362
print('trying')
@@ -372,10 +374,41 @@ def run_state_test1(params, mode):
372374
pass
373375
time_post = time.time()
374376

377+
375378
if tx.to == b'':
376379
output = state.get_code(output) if output else b''
377380

378381

382+
params2 = copy.deepcopy(params)
383+
if success:
384+
params2['logs'] = [log.to_dict() for log in logs]
385+
386+
387+
params2['out'] = b'0x' + encode_hex(output)
388+
params2['post'] = copy.deepcopy(state.to_dict())
389+
params2['postStateRoot'] = encode_hex(state.trie.root_hash)
390+
391+
if mode == FILL:
392+
return params2
393+
elif mode == VERIFY:
394+
params1 = copy.deepcopy(params)
395+
shouldbe, reallyis = params1.get('post', None), params2.get('post', None)
396+
compare_post_states(shouldbe, reallyis)
397+
for k in ['pre', 'exec', 'env', 'callcreates',
398+
'out', 'gas', 'logs', 'postStateRoot']:
399+
_shouldbe = params1.get(k, None)
400+
_reallyis = params2.get(k, None)
401+
if _shouldbe != _reallyis:
402+
print 's', shouldbe
403+
print 'r', reallyis
404+
print state.trie.to_dict()
405+
raise Exception("Mismatch: " + k + ':\n shouldbe %r\n reallyis %r' %
406+
(_shouldbe, _reallyis))
407+
408+
elif mode == TIME:
409+
return time_post - time_pre
410+
411+
379412
# Fills up a vm test without post data, or runs the test
380413
def run_state_test(params, mode):
381414
pre = params['pre']

ethereum/transactions.py

Lines changed: 5 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,13 @@
33
from bitcoin import encode_pubkey, N, encode_privkey, ecdsa_raw_sign
44
from rlp.sedes import big_endian_int, binary
55
from rlp.utils import encode_hex, str_to_bytes, ascii_chr
6-
try:
7-
from secp256k1 import PublicKey, ALL_FLAGS, PrivateKey
8-
except:
9-
pass
106

117
from ethereum.exceptions import InvalidTransaction
128
from ethereum import bloom
139
from ethereum import opcodes
1410
from ethereum import utils
1511
from ethereum.slogging import get_logger
16-
from ethereum.utils import TT256, mk_contract_address, zpad, int_to_32bytearray, big_endian_to_int
12+
from ethereum.utils import TT256, mk_contract_address, zpad, int_to_32bytearray, big_endian_to_int, ecsign, ecrecover_to_pub
1713

1814

1915
log = get_logger('eth.chain.tx')
@@ -84,33 +80,10 @@ def sender(self):
8480
log.debug('recovering sender')
8581
rlpdata = rlp.encode(self, UnsignedTransaction)
8682
rawhash = utils.sha3(rlpdata)
87-
88-
try:
89-
pk = PublicKey(flags=ALL_FLAGS)
90-
using_pk = 1
91-
except:
92-
pk, using_pk = None, 0
93-
if not using_pk:
94-
recovered_addr = bitcoin.ecdsa_raw_recover(rawhash, (self.v, self.r, self.s))
95-
pub = bitcoin.encode_pubkey(recovered_addr, 'bin')
96-
else:
97-
try:
98-
pk.public_key = pk.ecdsa_recover(
99-
rawhash,
100-
pk.ecdsa_recoverable_deserialize(
101-
zpad(utils.bytearray_to_bytestr(int_to_32bytearray(self.r)), 32) + zpad(utils.bytearray_to_bytestr(int_to_32bytearray(self.s)), 32),
102-
self.v - 27
103-
),
104-
raw=True
105-
)
106-
pub = pk.serialize(compressed=False)
107-
except Exception:
108-
raise InvalidTransaction("Invalid signature values (x^3+7 is non-residue)")
109-
110-
if pub[1:] == b"\x00" * 32:
83+
pub = ecrecover_to_pub(rawhash, self.v, self.r, self.s)
84+
if pub == b"\x00" * 64:
11185
raise InvalidTransaction("Invalid signature (zero privkey cannot sign)")
112-
pub = encode_pubkey(pub, 'bin')
113-
self._sender = utils.sha3(pub[1:])[-20:]
86+
self._sender = utils.sha3(pub)[-20:]
11487
assert self.sender == self._sender
11588
else:
11689
self._sender = 0
@@ -133,17 +106,7 @@ def sign(self, key):
133106
# we need a binary key
134107
key = encode_privkey(key, 'bin')
135108

136-
try:
137-
pk = PrivateKey(key, raw=True)
138-
signature = pk.ecdsa_recoverable_serialize(
139-
pk.ecdsa_sign_recoverable(rawhash, raw=True)
140-
)
141-
signature = signature[0] + utils.bytearray_to_bytestr([signature[1]])
142-
self.v = utils.safe_ord(signature[64]) + 27
143-
self.r = big_endian_to_int(signature[0:32])
144-
self.s = big_endian_to_int(signature[32:64])
145-
except:
146-
self.v, self.r, self.s = ecdsa_raw_sign(rawhash, key)
109+
self.v, self.r, self.s = ecsign(rawhash, key)
147110

148111
self.sender = utils.privtoaddr(key)
149112
return self

ethereum/utils.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@
44
except:
55
import sha3 as _sha3
66
sha3_256 = lambda x: _sha3.sha3_256(x).digest()
7-
from bitcoin import privtopub
7+
from bitcoin import privtopub, ecdsa_raw_sign, ecdsa_raw_recover, encode_pubkey
88
import sys
99
import rlp
1010
from rlp.sedes import big_endian_int, BigEndianInt, Binary
1111
from rlp.utils import decode_hex, encode_hex, ascii_chr, str_to_bytes
1212
import random
1313

14+
try:
15+
from secp256k1 import PublicKey, ALL_FLAGS, PrivateKey
16+
except:
17+
pass
18+
1419
big_endian_to_int = lambda x: big_endian_int.deserialize(str_to_bytes(x).lstrip(b'\x00'))
1520
int_to_big_endian = lambda x: big_endian_int.serialize(x)
1621

@@ -65,6 +70,41 @@ def bytearray_to_bytestr(value):
6570
isnumeric = is_numeric
6671

6772

73+
def ecrecover_to_pub(rawhash, v, r, s):
74+
try:
75+
pk = PublicKey(flags=ALL_FLAGS)
76+
using_pk = 1
77+
pk.public_key = pk.ecdsa_recover(
78+
rawhash,
79+
pk.ecdsa_recoverable_deserialize(
80+
zpad(utils.bytearray_to_bytestr(int_to_32bytearray(r)), 32) + zpad(utils.bytearray_to_bytestr(int_to_32bytearray(s)), 32),
81+
v - 27
82+
),
83+
raw=True
84+
)
85+
pub = pk.serialize(compressed=False)[1:]
86+
except:
87+
recovered_addr = ecdsa_raw_recover(rawhash, (v, r, s))
88+
pub = encode_pubkey(recovered_addr, 'bin_electrum')
89+
assert len(pub) == 64
90+
return pub
91+
92+
93+
def ecsign(rawhash, key):
94+
try:
95+
pk = PrivateKey(key, raw=True)
96+
signature = pk.ecdsa_recoverable_serialize(
97+
pk.ecdsa_sign_recoverable(rawhash, raw=True)
98+
)
99+
signature = signature[0] + utils.bytearray_to_bytestr([signature[1]])
100+
v = utils.safe_ord(signature[64]) + 27
101+
r = big_endian_to_int(signature[0:32])
102+
s = big_endian_to_int(signature[32:64])
103+
except:
104+
v, r, s = ecdsa_raw_sign(rawhash, key)
105+
return v, r, s
106+
107+
68108
def mk_contract_address(sender, nonce):
69109
return sha3(rlp.encode([normalize_address(sender), nonce]))[12:]
70110

fixtures

Submodule fixtures updated 66 files

0 commit comments

Comments
 (0)