def deserialize(self): if self._msg_bytes is None or len( self._msg_bytes ) < eth_common_constants.MDC_LEN + eth_common_constants.SIGNATURE_LEN: raise ValueError("Message bytes empty or too short.") mdc = self._memory_view[:eth_common_constants.MDC_LEN].tobytes() if mdc != eth_common_utils.keccak_hash( self._memory_view[eth_common_constants.MDC_LEN:].tobytes()): raise WrongMACError("Message hash does not match MDC") mdc_sig_len = eth_common_constants.MDC_LEN + eth_common_constants.SIGNATURE_LEN signature = self._memory_view[eth_common_constants. MDC_LEN:mdc_sig_len].tobytes() self._msg_type = rlp_utils.safe_ord(self._memory_view[mdc_sig_len]) encoded_data = self._memory_view[mdc_sig_len:].tobytes() signed_data = eth_common_utils.keccak_hash(encoded_data) remote_pubkey = crypto_utils.recover_public_key(signed_data, signature) self._public_key = remote_pubkey if not crypto_utils.verify_signature(remote_pubkey, signature, signed_data): raise InvalidSignatureError( "Message signature does not match public key") encoded_payload = self._memory_view[mdc_sig_len + eth_common_constants. MSG_TYPE_LEN:].tobytes() self._deserialize_rlp_payload(encoded_payload) self._is_deserialized = True
def test_recover_public_key(self): dummy_private_key = crypto_utils.make_private_key( helpers.generate_bytearray(111)) public_key = crypto_utils.private_to_public_key(dummy_private_key) msg = helpers.generate_bytearray(222) msg_hash = eth_common_utils.keccak_hash(msg) signature = crypto_utils.sign(msg_hash, dummy_private_key) recovered_pub_key = crypto_utils.recover_public_key( msg_hash, signature) self.assertEqual(recovered_pub_key, public_key)
def verify_eth_transaction_signature(transaction: Transaction) -> bool: """ checks eth transaction signature :param transaction: :return: if signature matches public key """ try: signature = transaction.signature() unsigned_msg = transaction.get_unsigned() public_key = crypto_utils.recover_public_key(unsigned_msg, signature, keccak_hash) return crypto_utils.verify_signature(public_key, signature, keccak_hash(memoryview(unsigned_msg))) # pylint: disable=broad-except except Exception: return False
def to_json(self) -> Dict[str, Any]: """ Serializes data to be close to Ethereum RPC spec for publishing to the transaction feed. see https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionbyhash Some fields are excluded, since they will never be populated by bxgateway. (mainly fields related to the block the transaction gets included in) - blockHash - blockNumber - transactionIndex """ message_hash = self.hash() input_data = convert.bytes_to_hex(self.data) if not input_data: input_data = "0x" else: input_data = f"0x{input_data}" signature = crypto_utils.encode_signature(self.v, self.r, self.s) from_key = crypto_utils.recover_public_key( self.get_unsigned(), signature, eth_common_utils.keccak_hash ) from_address = crypto_utils.public_key_to_address(from_key) serialized_output = { "from": convert.bytes_to_hex_string_format(from_address), "gas": hex(self.start_gas), "gas_price": hex(self.gas_price), "hash": f"0x{str(message_hash)}", "input": input_data, "nonce": hex(self.nonce), "value": hex(self.value), "v": hex(self.v), "r": hex(self.r), "s": hex(self.s) } to = self.to if to is not None: serialized_output["to"] = convert.bytes_to_hex_string_format(to) return serialized_output
def parse_auth_message(self, message): assert not self._is_initiator if self._is_eip8_auth: (signature, pubkey, nonce, version) = self.parse_eip8_auth_message(message) else: (signature, pubkey, nonce, version) = self.parse_plain_auth_message(message) token = self._ecc.get_ecdh_key(pubkey) remote_ephemeral_pubkey = crypto_utils.recover_public_key( crypto_utils.string_xor(token, nonce), signature) if not self._ecc.is_valid_key(remote_ephemeral_pubkey): raise InvalidKeyError("Invalid remote ephemeral pubkey") self._remote_ephemeral_pubkey = remote_ephemeral_pubkey self._initiator_nonce = nonce self._remote_pubkey = pubkey self._remote_version = eth_common_constants.P2P_PROTOCOL_VERSION
def from_address(self) -> str: from_key = crypto_utils.recover_public_key( self.get_unsigned(), self.signature(), eth_common_utils.keccak_hash) from_address = crypto_utils.public_key_to_address(from_key) return convert.bytes_to_hex_string_format(from_address)