Add separate signer with rlp output
This commit is contained in:
parent
c669ed829f
commit
1bbd2c8790
@ -4,6 +4,10 @@ import logging
|
|||||||
# external imports
|
# external imports
|
||||||
import sha3
|
import sha3
|
||||||
import coincurve
|
import coincurve
|
||||||
|
from hexathon import int_to_minbytes
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from crypto_dev_signer.eth.encoding import chain_id_to_v
|
||||||
|
|
||||||
logg = logging.getLogger().getChild(__name__)
|
logg = logging.getLogger().getChild(__name__)
|
||||||
|
|
||||||
@ -31,28 +35,18 @@ class ReferenceSigner(Signer):
|
|||||||
h = sha3.keccak_256()
|
h = sha3.keccak_256()
|
||||||
h.update(s)
|
h.update(s)
|
||||||
message_to_sign = h.digest()
|
message_to_sign = h.digest()
|
||||||
z = self.sign(tx.sender, message_to_sign, password)
|
z = self.sign_pure(tx.sender, message_to_sign, password)
|
||||||
|
|
||||||
vnum = int.from_bytes(tx.v, 'big')
|
|
||||||
v = (vnum * 2) + 35 + z[64]
|
|
||||||
byts = ((v.bit_length()-1)/8)+1
|
|
||||||
tx.v = v.to_bytes(int(byts), 'big')
|
|
||||||
tx.r = z[:32]
|
|
||||||
tx.s = z[32:64]
|
|
||||||
|
|
||||||
for i in range(len(tx.r)):
|
|
||||||
if tx.r[i] > 0:
|
|
||||||
tx.r = tx.r[i:]
|
|
||||||
break
|
|
||||||
|
|
||||||
for i in range(len(tx.s)):
|
|
||||||
if tx.s[i] > 0:
|
|
||||||
tx.s = tx.s[i:]
|
|
||||||
break
|
|
||||||
|
|
||||||
return z
|
return z
|
||||||
|
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
|
||||||
def sign_ethereum_message(self, address, message, password=None):
|
def sign_ethereum_message(self, address, message, password=None):
|
||||||
|
|
||||||
#k = keys.PrivateKey(self.keyGetter.get(address, password))
|
#k = keys.PrivateKey(self.keyGetter.get(address, password))
|
||||||
@ -73,12 +67,12 @@ class ReferenceSigner(Signer):
|
|||||||
h.update(ethereumed_message_header + message)
|
h.update(ethereumed_message_header + message)
|
||||||
message_to_sign = h.digest()
|
message_to_sign = h.digest()
|
||||||
|
|
||||||
z = self.sign(address, message_to_sign, password)
|
z = self.sign_pure(address, message_to_sign, password)
|
||||||
return z
|
return z
|
||||||
|
|
||||||
|
|
||||||
# TODO: generic sign should be moved to non-eth context
|
# TODO: generic sign should be moved to non-eth context
|
||||||
def sign(self, address, message, password=None):
|
def sign_pure(self, address, message, password=None):
|
||||||
pk = coincurve.PrivateKey(secret=self.keyGetter.get(address, password))
|
pk = coincurve.PrivateKey(secret=self.keyGetter.get(address, password))
|
||||||
z = pk.sign_recoverable(hasher=None, message=message)
|
z = pk.sign_recoverable(hasher=None, message=message)
|
||||||
return z
|
return z
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
# standard imports
|
# standard imports
|
||||||
import logging
|
import logging
|
||||||
import binascii
|
import binascii
|
||||||
|
import re
|
||||||
|
|
||||||
# external imports
|
# external imports
|
||||||
from rlp import encode as rlp_encode
|
from rlp import encode as rlp_encode
|
||||||
from hexathon import (
|
from hexathon import (
|
||||||
strip_0x,
|
strip_0x,
|
||||||
add_0x,
|
add_0x,
|
||||||
|
int_to_minbytes,
|
||||||
)
|
)
|
||||||
|
|
||||||
logg = logging.getLogger(__name__)
|
# local imports
|
||||||
|
from crypto_dev_signer.eth.encoding import chain_id_to_v
|
||||||
|
|
||||||
|
logg = logging.getLogger().getChild(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Transaction:
|
class Transaction:
|
||||||
@ -23,54 +28,55 @@ class Transaction:
|
|||||||
|
|
||||||
class EIP155Transaction:
|
class EIP155Transaction:
|
||||||
|
|
||||||
def __init__(self, tx, nonce, chainId=1):
|
def __init__(self, tx, nonce_in, chainId_in=1):
|
||||||
to = None
|
to = b''
|
||||||
data = None
|
data = b''
|
||||||
if tx['to'] != None:
|
if tx.get('to') != None:
|
||||||
#to = binascii.unhexlify(strip_0x(tx['to'], allow_empty=True))
|
|
||||||
to = bytes.fromhex(strip_0x(tx['to'], allow_empty=True))
|
to = bytes.fromhex(strip_0x(tx['to'], allow_empty=True))
|
||||||
if tx['data'] != None:
|
if tx.get('data') != None:
|
||||||
#data = binascii.unhexlify(strip_0x(tx['data'], allow_empty=True))
|
|
||||||
data = bytes.fromhex(strip_0x(tx['data'], allow_empty=True))
|
data = bytes.fromhex(strip_0x(tx['data'], allow_empty=True))
|
||||||
|
|
||||||
gas_price = None
|
gas_price = None
|
||||||
start_gas = None
|
start_gas = None
|
||||||
value = None
|
value = None
|
||||||
|
nonce = None
|
||||||
|
chainId = None
|
||||||
|
|
||||||
|
# TODO: go directly from hex to bytes
|
||||||
try:
|
try:
|
||||||
gas_price = int(tx['gasPrice'])
|
gas_price = int(tx['gasPrice'])
|
||||||
except ValueError:
|
|
||||||
gas_price = int(tx['gasPrice'], 16)
|
|
||||||
byts = ((gas_price.bit_length()-1)/8)+1
|
byts = ((gas_price.bit_length()-1)/8)+1
|
||||||
gas_price = gas_price.to_bytes(int(byts), 'big')
|
gas_price = gas_price.to_bytes(int(byts), 'big')
|
||||||
|
except ValueError:
|
||||||
|
gas_price = bytes.fromhex(strip_0x(tx['gasPrice'], allow_empty=True))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
start_gas = int(tx['gas'])
|
start_gas = int(tx['gas'])
|
||||||
except ValueError:
|
|
||||||
start_gas = int(tx['gas'], 16)
|
|
||||||
byts = ((start_gas.bit_length()-1)/8)+1
|
byts = ((start_gas.bit_length()-1)/8)+1
|
||||||
start_gas = start_gas.to_bytes(int(byts), 'big')
|
start_gas = start_gas.to_bytes(int(byts), 'big')
|
||||||
|
except ValueError:
|
||||||
|
start_gas = bytes.fromhex(strip_0x(tx['gas'], allow_empty=True))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
value = int(tx['value'])
|
value = int(tx['value'])
|
||||||
except ValueError:
|
|
||||||
value = int(tx['value'], 16)
|
|
||||||
byts = ((value.bit_length()-1)/8)+1
|
byts = ((value.bit_length()-1)/8)+1
|
||||||
value = value.to_bytes(int(byts), 'big')
|
value = value.to_bytes(int(byts), 'big')
|
||||||
|
except ValueError:
|
||||||
|
value = bytes.fromhex(strip_0x(tx['value'], allow_empty=True))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
nonce = int(nonce)
|
nonce = int(nonce_in)
|
||||||
except ValueError:
|
|
||||||
nonce = int(nonce, 16)
|
|
||||||
byts = ((nonce.bit_length()-1)/8)+1
|
byts = ((nonce.bit_length()-1)/8)+1
|
||||||
nonce = nonce.to_bytes(int(byts), 'big')
|
nonce = nonce.to_bytes(int(byts), 'big')
|
||||||
|
except ValueError:
|
||||||
|
nonce = bytes.fromhex(strip_0x(nonce_in, allow_empty=True))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
chainId = int(chainId)
|
chainId = int(chainId_in)
|
||||||
except ValueError:
|
|
||||||
chainId = int(chainId, 16)
|
|
||||||
byts = ((chainId.bit_length()-1)/8)+1
|
byts = ((chainId.bit_length()-1)/8)+1
|
||||||
chainId = chainId.to_bytes(int(byts), 'big')
|
chainId = chainId.to_bytes(int(byts), 'big')
|
||||||
|
except ValueError:
|
||||||
|
chainId = bytes.fromhex(strip_0x(chainId_in, allow_empty=True))
|
||||||
|
|
||||||
self.nonce = nonce
|
self.nonce = nonce
|
||||||
self.gas_price = gas_price
|
self.gas_price = gas_price
|
||||||
@ -120,7 +126,7 @@ class EIP155Transaction:
|
|||||||
'gas': add_0x(self.start_gas.hex()),
|
'gas': add_0x(self.start_gas.hex()),
|
||||||
'to': add_0x(self.to.hex()),
|
'to': add_0x(self.to.hex()),
|
||||||
'value': add_0x(self.value.hex(), allow_empty=True),
|
'value': add_0x(self.value.hex(), allow_empty=True),
|
||||||
'data': add_0x(self.data.hex()),
|
'data': add_0x(self.data.hex(), allow_empty=True),
|
||||||
'v': add_0x(self.v.hex(), allow_empty=True),
|
'v': add_0x(self.v.hex(), allow_empty=True),
|
||||||
'r': add_0x(self.r.hex(), allow_empty=True),
|
'r': add_0x(self.r.hex(), allow_empty=True),
|
||||||
's': add_0x(self.s.hex(), allow_empty=True),
|
's': add_0x(self.s.hex(), allow_empty=True),
|
||||||
@ -135,3 +141,24 @@ class EIP155Transaction:
|
|||||||
tx['nonce'] = '0x00'
|
tx['nonce'] = '0x00'
|
||||||
|
|
||||||
return tx
|
return tx
|
||||||
|
|
||||||
|
|
||||||
|
def apply_signature(self, chain_id, signature):
|
||||||
|
if len(self.r + self.s) > 0:
|
||||||
|
raise AttributeError('signature already set')
|
||||||
|
if len(signature) < 65:
|
||||||
|
raise ValueError('invalid signature length')
|
||||||
|
v = chain_id_to_v(chain_id, signature)
|
||||||
|
self.v = int_to_minbytes(v)
|
||||||
|
self.r = signature[:32]
|
||||||
|
self.s = signature[32:64]
|
||||||
|
|
||||||
|
for i in range(len(self.r)):
|
||||||
|
if self.r[i] > 0:
|
||||||
|
self.r = self.r[i:]
|
||||||
|
break
|
||||||
|
|
||||||
|
for i in range(len(self.s)):
|
||||||
|
if self.s[i] > 0:
|
||||||
|
self.s = self.s[i:]
|
||||||
|
break
|
||||||
|
@ -102,12 +102,13 @@ def personal_new_account(p):
|
|||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def personal_sign_transaction(p):
|
def personal_signTransaction(p):
|
||||||
logg.debug('got {} to sign'.format(p[0]))
|
logg.debug('got {} to sign'.format(p[0]))
|
||||||
#t = EIP155Transaction(p[0], p[0]['nonce'], 8995)
|
#t = EIP155Transaction(p[0], p[0]['nonce'], 8995)
|
||||||
t = EIP155Transaction(p[0], p[0]['nonce'], int(p[0]['chainId']))
|
t = EIP155Transaction(p[0], p[0]['nonce'], int(p[0]['chainId']))
|
||||||
z = signer.sign_transaction(t, p[1])
|
# z = signer.sign_transaction(t, p[1])
|
||||||
raw_signed_tx = t.rlp_serialize()
|
# raw_signed_tx = t.rlp_serialize()
|
||||||
|
raw_signed_tx = signer.sign_transaction_to_rlp(t, p[1])
|
||||||
o = {
|
o = {
|
||||||
'raw': '0x' + raw_signed_tx.hex(),
|
'raw': '0x' + raw_signed_tx.hex(),
|
||||||
'tx': t.serialize(),
|
'tx': t.serialize(),
|
||||||
@ -116,9 +117,9 @@ def personal_sign_transaction(p):
|
|||||||
return o
|
return o
|
||||||
|
|
||||||
|
|
||||||
# TODO: temporary workaround for platform, since personal_sign_transaction is missing from web3.py
|
# TODO: temporary workaround for platform, since personal_signTransaction is missing from web3.py
|
||||||
def eth_sign_transaction(tx):
|
def eth_signTransaction(tx):
|
||||||
return personal_sign_transaction([tx[0], ''])
|
return personal_signTransaction([tx[0], ''])
|
||||||
|
|
||||||
|
|
||||||
def eth_sign(p):
|
def eth_sign(p):
|
||||||
@ -132,8 +133,8 @@ def eth_sign(p):
|
|||||||
|
|
||||||
methods = {
|
methods = {
|
||||||
'personal_newAccount': personal_new_account,
|
'personal_newAccount': personal_new_account,
|
||||||
'personal_sign_transaction': personal_sign_transaction,
|
'personal_signTransaction': personal_signTransaction,
|
||||||
'eth_sign_transaction': eth_sign_transaction,
|
'eth_signTransaction': eth_signTransaction,
|
||||||
'eth_sign': eth_sign,
|
'eth_sign': eth_sign,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,10 @@ cryptography==3.2.1
|
|||||||
pysha3==1.0.2
|
pysha3==1.0.2
|
||||||
#simple-rlp==0.1.2
|
#simple-rlp==0.1.2
|
||||||
rlp==2.0.1
|
rlp==2.0.1
|
||||||
|
eth-utils==1.10.0
|
||||||
json-rpc==1.13.0
|
json-rpc==1.13.0
|
||||||
confini~=0.3.6a3
|
confini~=0.3.6a3
|
||||||
sqlalchemy==1.3.20
|
sqlalchemy==1.3.20
|
||||||
coincurve==15.0.0
|
coincurve==15.0.0
|
||||||
pycrypto==2.6.1
|
pycrypto==2.6.1
|
||||||
hexathon~=0.0.1a5
|
hexathon~=0.0.1a6
|
||||||
|
2
setup.py
2
setup.py
@ -24,7 +24,7 @@ f.close()
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="crypto-dev-signer",
|
name="crypto-dev-signer",
|
||||||
version="0.4.14a10",
|
version="0.4.14a14",
|
||||||
description="A signer and keystore daemon and library for cryptocurrency software development",
|
description="A signer and keystore daemon and library for cryptocurrency software development",
|
||||||
author="Louis Holbrook",
|
author="Louis Holbrook",
|
||||||
author_email="dev@holbrook.no",
|
author_email="dev@holbrook.no",
|
||||||
|
Loading…
Reference in New Issue
Block a user