diff --git a/ape_aws_kms/accounts.py b/ape_aws_kms/accounts.py index eafe5c2..f070e8b 100644 --- a/ape_aws_kms/accounts.py +++ b/ape_aws_kms/accounts.py @@ -1,10 +1,13 @@ import boto3 -from hashlib import sha256 +import json from datetime import datetime +from hashlib import sha256 from typing import Any, Iterator, List, Optional -from eth_account.messages import encode_defunct +from eth_account import Account +from eth_account.messages import _hash_eip191_message, SignableMessage +from eth_pydantic_types import HexBytes from eth_utils import keccak, to_checksum_address from pydantic import BaseModel, Field @@ -73,17 +76,67 @@ def public_key(self): def address(self) -> AddressType: return to_checksum_address(keccak(self.public_key)[:20]) - def sign_message(self, msg: Any, **signer_options) -> Optional[MessageSignature]: - message = sha256(msg.encode()).digest() + def sign_raw_msghash(self, msghash: HexBytes) -> Optional[MessageSignature]: + """ + follow: https://github.com/ApeWorX/ape/pull/1966/files#diff-c308960cdf9376a4c05b2bb028a5a79e22c8a12b4c99633580062ec04ab613e2R60 + + AccountAPI has check_message to do a round trip check to make sure sig is correct and + that the address is returning what we want + """ response = self.kms_client.sign( KeyId=self.key_id, - Message=message, + Message=msghash, MessageType='DIGEST', SigningAlgorithm='ECDSA_SHA_256', ) return response + def sign_message(self, msg: Any, **signer_options) -> Optional[MessageSignature]: + message = None + if isinstance(msg, str): + message = sha256(msg.encode()).digest() + elif isinstance(msg, dict): + message = sha256(json.dumps(msg).encode('utf-8')).digest() + elif isinstance(msg, bytes): + message = sha256(msg).digest() + elif isinstance(msg, int): + message = sha256( + msg.to_bytes((msg.bit_length() + 7) // 8, byteorder='big') + ).digest() + if message: + signable_message = SignableMessage( + version=(0x00).to_bytes(1, byteorder='big'), + header=self.address.encode('utf-8'), + body=message, + ) + eip_message = _hash_eip191_message(signable_message) + response = self.sign_raw_msghash(eip_message) + signature = response['Signature'] + r = signature[-64:-32] + s = signature[-32:] + for v in [27, 28]: + # WORK IN PROGRESS HERE + vrs = int(v).to_bytes(1, 'big') + r + s + message_signature = MessageSignature.from_vrs(vrs) + breakpoint() + try: + if self.check_signature(msg, message_signature): + return response + except: + continue + + raise ValueError("Signature failed to verify") + raise ValueError("Invalid message type") + def sign_transaction(self, txn: TransactionAPI, **signer_options) -> Optional[TransactionAPI]: """ To be implemented + EIP-191 -> Describing a text based message to sign + + EIP-712 -> Subclass of EIP-191 messages. First byte is a specific value + implemented in the EIP712 Package + + Break EIP-712 down further into a raw hash + + Through EthAccount? """ diff --git a/setup.py b/setup.py index 399ba5a..c858fc2 100644 --- a/setup.py +++ b/setup.py @@ -55,7 +55,7 @@ install_requires=[ "importlib-metadata ; python_version<'3.8'", "boto3>=1.34.79,<2", - "eth-ape>=0.1.0b3", + "eth-ape>=0.7.0", "eth-utils>=2.3.1,<3", "pydantic>=2.5.2,<3", ], # NOTE: Add 3rd party libraries here