2021-03-17 15:34:51 +01:00
|
|
|
# standard imports
|
2020-08-04 23:41:31 +02:00
|
|
|
import logging
|
|
|
|
|
2021-03-17 15:34:51 +01:00
|
|
|
# external imports
|
|
|
|
import sha3
|
|
|
|
import coincurve
|
2021-03-27 15:32:05 +01:00
|
|
|
from hexathon import int_to_minbytes
|
|
|
|
|
|
|
|
# local imports
|
|
|
|
from crypto_dev_signer.eth.encoding import chain_id_to_v
|
2020-08-04 23:41:31 +02:00
|
|
|
|
2021-03-26 13:08:36 +01:00
|
|
|
logg = logging.getLogger().getChild(__name__)
|
2020-08-04 23:41:31 +02:00
|
|
|
|
|
|
|
|
|
|
|
class Signer:
|
|
|
|
|
2020-08-05 18:14:25 +02:00
|
|
|
|
2020-08-04 23:41:31 +02:00
|
|
|
def __init__(self, keyGetter):
|
|
|
|
self.keyGetter = keyGetter
|
|
|
|
|
2020-08-05 18:14:25 +02:00
|
|
|
|
2021-03-26 13:08:36 +01:00
|
|
|
def sign_transaction(self, tx, password=None):
|
|
|
|
return NotImplementedError
|
2020-08-04 23:41:31 +02:00
|
|
|
|
2020-08-05 18:14:25 +02:00
|
|
|
|
2020-08-04 23:41:31 +02:00
|
|
|
class ReferenceSigner(Signer):
|
2020-08-05 18:14:25 +02:00
|
|
|
|
|
|
|
|
2020-08-04 23:41:31 +02:00
|
|
|
def __init__(self, keyGetter):
|
|
|
|
super(ReferenceSigner, self).__init__(keyGetter)
|
|
|
|
|
|
|
|
|
2021-03-26 13:08:36 +01:00
|
|
|
def sign_transaction(self, tx, password=None):
|
2020-08-05 22:00:23 +02:00
|
|
|
s = tx.rlp_serialize()
|
2020-08-04 23:41:31 +02:00
|
|
|
h = sha3.keccak_256()
|
|
|
|
h.update(s)
|
2021-03-17 15:34:51 +01:00
|
|
|
message_to_sign = h.digest()
|
2021-03-27 15:32:05 +01:00
|
|
|
z = self.sign_pure(tx.sender, message_to_sign, password)
|
2021-03-03 18:10:15 +01:00
|
|
|
|
2021-03-27 15:32:05 +01:00
|
|
|
return z
|
2021-03-03 18:10:15 +01:00
|
|
|
|
|
|
|
|
2021-03-27 15:32:05 +01:00
|
|
|
def sign_transaction_to_rlp(self, tx, password=None):
|
|
|
|
chain_id = int.from_bytes(tx.v, byteorder='big')
|
|
|
|
sig = self.sign_transaction(tx, password)
|
|
|
|
tx.apply_signature(chain_id, sig)
|
|
|
|
return tx.rlp_serialize()
|
2020-12-19 08:47:21 +01:00
|
|
|
|
|
|
|
|
2021-03-26 13:08:36 +01:00
|
|
|
def sign_ethereum_message(self, address, message, password=None):
|
2021-03-17 15:34:51 +01:00
|
|
|
|
|
|
|
#k = keys.PrivateKey(self.keyGetter.get(address, password))
|
2020-12-19 08:47:21 +01:00
|
|
|
#z = keys.ecdsa_sign(message_hash=g, private_key=k)
|
2020-12-25 12:34:05 +01:00
|
|
|
if type(message).__name__ == 'str':
|
2020-12-25 12:53:16 +01:00
|
|
|
logg.debug('signing message in "str" format: {}'.format(message))
|
2021-03-17 15:34:51 +01:00
|
|
|
#z = k.sign_msg(bytes.fromhex(message))
|
|
|
|
message = bytes.fromhex(message)
|
2020-12-25 12:34:05 +01:00
|
|
|
elif type(message).__name__ == 'bytes':
|
2020-12-25 12:53:16 +01:00
|
|
|
logg.debug('signing message in "bytes" format: {}'.format(message.hex()))
|
2021-03-17 15:34:51 +01:00
|
|
|
#z = k.sign_msg(message)
|
2020-12-25 12:34:05 +01:00
|
|
|
else:
|
2021-03-17 15:34:51 +01:00
|
|
|
logg.debug('unhandled format {}'.format(type(message).__name__))
|
2020-12-25 12:34:05 +01:00
|
|
|
raise ValueError('message must be type str or bytes, received {}'.format(type(message).__name__))
|
2021-03-17 15:34:51 +01:00
|
|
|
|
|
|
|
ethereumed_message_header = b'\x19' + 'Ethereum Signed Message:\n{}'.format(len(message)).encode('utf-8')
|
|
|
|
h = sha3.keccak_256()
|
|
|
|
h.update(ethereumed_message_header + message)
|
|
|
|
message_to_sign = h.digest()
|
|
|
|
|
2021-03-27 15:32:05 +01:00
|
|
|
z = self.sign_pure(address, message_to_sign, password)
|
2020-12-19 08:47:21 +01:00
|
|
|
return z
|
|
|
|
|
2021-03-17 15:34:51 +01:00
|
|
|
|
2021-03-26 13:08:36 +01:00
|
|
|
# TODO: generic sign should be moved to non-eth context
|
2021-03-27 15:32:05 +01:00
|
|
|
def sign_pure(self, address, message, password=None):
|
2021-03-17 15:34:51 +01:00
|
|
|
pk = coincurve.PrivateKey(secret=self.keyGetter.get(address, password))
|
2021-03-17 17:09:42 +01:00
|
|
|
z = pk.sign_recoverable(hasher=None, message=message)
|
2021-03-17 15:34:51 +01:00
|
|
|
return z
|