class IcxSigner(object): """ ICX Signature utility class. """ def __init__(self, data: object = None, raw: object = None) -> object: """ :param data bytes or der (object): :param raw: (bool) True(bytes) False(der) """ self.__private_key = PrivateKey(data, raw) @property def private_key_bytes(self): return self.__private_key.private_key @private_key_bytes.setter def private_key(self, data): self.__private_key.set_raw_privkey(data) @property def public_key_bytes(self): return self.__private_key.pubkey.serialize(compressed=False) @property def address(self): public_key_bytes = self.public_key_bytes return hashlib.sha3_256(public_key_bytes[1:]).digest()[-20:] def sign(self, msg_hash): """Make a signature using the hash value of msg. :param msg_hash: Result of sha3_256(msg) type(bytes) :return: Signature. type(bytes) """ private_key_object = self.__private_key signature = private_key_object.ecdsa_sign(msg_hash, raw=True) return private_key_object.ecdsa_serialize(signature) def sign_recoverable(self, msg_hash): """Make a recoverable signature using message hash data. We can extract public key from recoverable signature. :param msg_hash: Hash data of message. type(bytes) :return: type(tuple) type(bytes): 65 bytes data , type(int): recovery id """ private_key_object = self.__private_key recoverable_signature = private_key_object.ecdsa_sign_recoverable( msg_hash, raw=True) return private_key_object.ecdsa_recoverable_serialize( recoverable_signature) @staticmethod def from_bytes(data): return IcxSigner(data, raw=True) @staticmethod def from_der(data): return IcxSigner(data, raw=False)
class Secp256k1_compact(object): def __init__(self): self.priv_key = PrivateKey() self.pub_key = PublicKey(pubkey=None, raw=False, flags=secp256k1.ALL_FLAGS) def ecdsa_compact_sign(self, msg32, privkey): if type(privkey) == unicode: privkey = privkey.encode('utf-8') self.priv_key.set_raw_privkey(privkey) sig = self.priv_key.ecdsa_sign_recoverable(msg32, raw=True) return self.priv_key.ecdsa_recoverable_serialize(sig) def ecdsa_compact_recover(self, msg32, sign): if not len(sign) == 2: sign = (sign[:64], ord(sign[64])) assert len(sign) == 2 deserialized_sig = self.pub_key.ecdsa_recoverable_deserialize(sign[0], sign[1]) self.pub_key.public_key = self.pub_key.ecdsa_recover(msg32, deserialized_sig, raw=True) return self.pub_key.serialize(compressed=False) def ecdsa_compact_verify(self, msg32, sign, pub): # Check if pubkey has been bin_electrum encoded. # If so, append \04 to the front of the key, to make sure the length is 65 if len(pub) == 64: pub = '\04'+pub pub_k = PublicKey().deserialize(pub) pub_key = PublicKey(pub_k, raw=False, flags=secp256k1.ALL_FLAGS) der_sig = pub_key.ecdsa_recoverable_deserialize(sign[0], sign[1]) raw_sig = pub_key.ecdsa_recoverable_convert(der_sig) return pub_key.ecdsa_verify(msg32, raw_sig, raw=True)
def test_eth_sign(web3, skip_if_testrpc): skip_if_testrpc(web3) private_key_hex = '0x5e95384d8050109aab08c1922d3c230739bc16976553c317e5d0b87b59371f2a' private_key = decode_hex(private_key_hex) # This imports the private key into the running geth instance and unlocks # the account so that it can sign things. # `0xa5df35f30ba0ce878b1061ae086289adff3ba1e0` address = web3.personal.importRawKey(private_key, "password") web3.personal.unlockAccount(address, "password") assert add_0x_prefix(encode_hex(privtoaddr(private_key))) == add_0x_prefix(address) assert address == '0xa5df35f30ba0ce878b1061ae086289adff3ba1e0' # the data to be signed data = b'1234567890abcdefghijklmnopqrstuvwxyz' # the hash of the data `0x089c33d56ed10bd8b571a0f493cedb28db1ae0f40c6cd266243001528c06eab3` data_hash = web3.sha3(data, encoding=None) data_hash_bytes = decode_hex(data_hash) assert force_bytes(data_hash) == sha3(data) priv_key = PrivateKey(flags=ALL_FLAGS) priv_key.set_raw_privkey(private_key) # sanit check the extract_ecdsa_signer function works as expected. vector_sig = priv_key.ecdsa_sign_recoverable(data_hash_bytes, raw=True, digest=sha3_256) vector_sig_bytes, rec_id = priv_key.ecdsa_recoverable_serialize(vector_sig) vector_sig_bytes_full = vector_sig_bytes + force_bytes(chr(rec_id)) vector_address = force_text(extract_ecdsa_signer(data_hash_bytes, vector_sig_bytes_full)) assert vector_address == address # Now have geth sign some data. signature_hex = web3.eth.sign(address, data) signature_bytes = decode_hex(signature_hex) actual_signer = extract_ecdsa_signer(data_hash_bytes, signature_bytes) assert actual_signer == address # Verify the signature against the public key derived from the # original private key. It fails. rec_id = signature_bytes[64] if is_string(rec_id): rec_id = ord(rec_id) recoverable_signature = priv_key.ecdsa_recoverable_deserialize( signature_bytes[:64], rec_id, ) signature = priv_key.ecdsa_recoverable_convert(recoverable_signature) is_valid = priv_key.pubkey.ecdsa_verify( msg=data, raw_sig=signature, digest=sha3_256, ) assert is_valid
def _inner_sign(account, data_to_sign): signature_hash_hex = web3.sha3(encode_hex(data_to_sign)) signature_hash_bytes = decode_hex(signature_hash_hex) private_key = tester.keys[tester.accounts.index(decode_hex(account))] priv_key = PrivateKey(flags=ALL_FLAGS) priv_key.set_raw_privkey(private_key) signature_raw = priv_key.ecdsa_sign_recoverable( signature_hash_bytes, raw=True, digest=sha3_256, ) signature_bytes, rec_id = priv_key.ecdsa_recoverable_serialize(signature_raw) signature = signature_bytes + force_bytes(chr(rec_id)) # Sanity check that the signature is valid. signer_address = force_text(extract_ecdsa_signer( signature_hash_bytes, signature, )) assert signer_address == account return signature
def test_eth_sign(web3, skip_if_testrpc): skip_if_testrpc(web3) private_key_hex = '0x5e95384d8050109aab08c1922d3c230739bc16976553c317e5d0b87b59371f2a' private_key = decode_hex(private_key_hex) # This imports the private key into the running geth instance and unlocks # the account so that it can sign things. # address = '0xa5df35f30ba0ce878b1061ae086289adff3ba1e0' address = web3.personal.importRawKey(private_key, "password") web3.personal.unlockAccount(address, "password") assert add_0x_prefix(encode_hex( privtoaddr(private_key))) == add_0x_prefix(address) assert address == '0xa5df35f30ba0ce878b1061ae086289adff3ba1e0' # the data to be signed data = b'1234567890abcdefghijklmnopqrstuvwxyz' # the hash of the data `0x089c33d56ed10bd8b571a0f493cedb28db1ae0f40c6cd266243001528c06eab3` data_hash = web3.sha3(data, encoding=None) data_hash_bytes = decode_hex(data_hash) assert force_bytes(data_hash) == sha3(data) priv_key = PrivateKey(flags=ALL_FLAGS) priv_key.set_raw_privkey(private_key) # sanit check the extract_ecdsa_signer function works as expected. vector_sig = priv_key.ecdsa_sign_recoverable(data_hash_bytes, raw=True, digest=hashlib.sha3_256) vector_sig_bytes, rec_id = priv_key.ecdsa_recoverable_serialize(vector_sig) vector_sig_bytes_full = vector_sig_bytes + force_bytes(chr(rec_id)) vector_address = force_text( extract_ecdsa_signer(data_hash_bytes, vector_sig_bytes_full)) assert vector_address == address # Now have geth sign some data. signature_hex = web3.eth.sign(address, data) signature_bytes = decode_hex(signature_hex) # geth prefix message before signing geth_prefix_data = eth_message_prefix_hash(web3, data.decode()) actual_signer = extract_ecdsa_signer(force_bytes(geth_prefix_data), signature_bytes) assert actual_signer == address # Verify the signature against the public key derived from the # original private key. It fails. rec_id = signature_bytes[64] if is_string(rec_id): rec_id = ord(rec_id) recoverable_signature = priv_key.ecdsa_recoverable_deserialize( signature_bytes[:64], rec_id, ) signature = priv_key.ecdsa_recoverable_convert(recoverable_signature) is_valid = priv_key.pubkey.ecdsa_verify( msg=data, raw_sig=signature, digest=hashlib.sha3_256, ) assert is_valid