From fbef30d920a78a606632d6d05e5411bb5211fa4e Mon Sep 17 00:00:00 2001 From: mhh Date: Sat, 12 Aug 2023 14:38:39 +0200 Subject: [PATCH 01/17] implement sign_raw for ETH and SOL --- src/aleph/sdk/chains/common.py | 15 ++++++++++++++- src/aleph/sdk/chains/ethereum.py | 14 +++++--------- src/aleph/sdk/chains/sol.py | 7 ++++++- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/aleph/sdk/chains/common.py b/src/aleph/sdk/chains/common.py index ddda3f04..140f5c2d 100644 --- a/src/aleph/sdk/chains/common.py +++ b/src/aleph/sdk/chains/common.py @@ -71,7 +71,20 @@ async def sign_message(self, message: Dict) -> Dict: Returns: Dict: Signed message """ - raise NotImplementedError + message = self._setup_sender(message) + sig = await self.sign_raw(get_verification_buffer(message)) + message["signature"] = sig.hex() + return message + + async def sign_raw(self, buffer: bytes) -> bytes: + """ + Returns a signed message from a raw buffer. + Args: + buffer: Buffer to sign + Returns: + bytes: Signed buffer + """ + @abstractmethod def get_address(self) -> str: diff --git a/src/aleph/sdk/chains/ethereum.py b/src/aleph/sdk/chains/ethereum.py index 5e3ff9f6..a6e516f6 100644 --- a/src/aleph/sdk/chains/ethereum.py +++ b/src/aleph/sdk/chains/ethereum.py @@ -23,16 +23,12 @@ class ETHAccount(BaseAccount): def __init__(self, private_key: bytes): self.private_key = private_key self._account = Account.from_key(self.private_key) - - async def sign_message(self, message: Dict) -> Dict: - """Sign a message inplace.""" - message = self._setup_sender(message) - - msghash = encode_defunct(text=get_verification_buffer(message).decode("utf-8")) + + async def sign_raw(self, buffer: bytes) -> bytes: + """Sign a raw buffer.""" + msghash = encode_defunct(text=buffer.decode("utf-8")) sig = self._account.sign_message(msghash) - - message["signature"] = sig["signature"].hex() - return message + return sig["signature"] def get_address(self) -> str: return self._account.address diff --git a/src/aleph/sdk/chains/sol.py b/src/aleph/sdk/chains/sol.py index ca5ff736..cc5a2cfa 100644 --- a/src/aleph/sdk/chains/sol.py +++ b/src/aleph/sdk/chains/sol.py @@ -32,11 +32,16 @@ async def sign_message(self, message: Dict) -> Dict: verif = get_verification_buffer(message) sig = { "publicKey": self.get_address(), - "signature": encode(self._signing_key.sign(verif).signature), + "signature": encode(self.sign_raw(verif)), } message["signature"] = json.dumps(sig) return message + async def sign_raw(self, buffer: bytes) -> bytes: + """Sign a raw buffer.""" + sig = self._signing_key.sign(buffer) + return sig.signature + def get_address(self) -> str: return encode(self._signing_key.verify_key) From e10d3813736da96023660ccaa0d0705747d9fcda Mon Sep 17 00:00:00 2001 From: mhh Date: Sat, 12 Aug 2023 15:06:38 +0200 Subject: [PATCH 02/17] implement sign_raw for all other chains, fix formatting and imports --- src/aleph/sdk/chains/common.py | 13 ++++++------- src/aleph/sdk/chains/cosmos.py | 20 ++++++++++---------- src/aleph/sdk/chains/ethereum.py | 9 ++++----- src/aleph/sdk/chains/nuls1.py | 4 ++++ src/aleph/sdk/chains/nuls2.py | 14 +++----------- src/aleph/sdk/chains/remote.py | 3 +++ src/aleph/sdk/chains/sol.py | 6 +++--- src/aleph/sdk/chains/substrate.py | 4 ++++ src/aleph/sdk/chains/tezos.py | 5 ++++- 9 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/aleph/sdk/chains/common.py b/src/aleph/sdk/chains/common.py index 140f5c2d..8113bd3a 100644 --- a/src/aleph/sdk/chains/common.py +++ b/src/aleph/sdk/chains/common.py @@ -62,7 +62,6 @@ def _setup_sender(self, message: Dict) -> Dict: else: raise ValueError("Message sender does not match the account's public key.") - @abstractmethod async def sign_message(self, message: Dict) -> Dict: """ Returns a signed message from an Aleph message. @@ -72,19 +71,19 @@ async def sign_message(self, message: Dict) -> Dict: Dict: Signed message """ message = self._setup_sender(message) - sig = await self.sign_raw(get_verification_buffer(message)) - message["signature"] = sig.hex() + message["signature"] = await self.sign_raw(get_verification_buffer(message)) return message - - async def sign_raw(self, buffer: bytes) -> bytes: + + @abstractmethod + async def sign_raw(self, buffer: bytes) -> str: """ Returns a signed message from a raw buffer. Args: buffer: Buffer to sign Returns: - bytes: Signed buffer + str: Signature in preferred format """ - + raise NotImplementedError @abstractmethod def get_address(self) -> str: diff --git a/src/aleph/sdk/chains/cosmos.py b/src/aleph/sdk/chains/cosmos.py index c1e29d5b..7fadd133 100644 --- a/src/aleph/sdk/chains/cosmos.py +++ b/src/aleph/sdk/chains/cosmos.py @@ -51,20 +51,11 @@ def __init__(self, private_key=None, hrp=DEFAULT_HRP): async def sign_message(self, message): message = self._setup_sender(message) - verif = get_verification_string(message) - - privkey = ecdsa.SigningKey.from_string(self.private_key, curve=ecdsa.SECP256k1) - signature_compact = privkey.sign_deterministic( - verif.encode("utf-8"), - hashfunc=hashlib.sha256, - sigencode=ecdsa.util.sigencode_string_canonize, - ) - signature_base64_str = base64.b64encode(signature_compact).decode("utf-8") base64_pubkey = base64.b64encode(self.get_public_key().encode()).decode("utf-8") sig = { - "signature": signature_base64_str, + "signature": self.sign_raw(verif.encode("utf-8")), "pub_key": {"type": "tendermint/PubKeySecp256k1", "value": base64_pubkey}, "account_number": str(0), "sequence": str(0), @@ -72,6 +63,15 @@ async def sign_message(self, message): message["signature"] = json.dumps(sig) return message + async def sign_raw(self, buffer: bytes) -> str: + privkey = ecdsa.SigningKey.from_string(self.private_key, curve=ecdsa.SECP256k1) + signature_compact = privkey.sign_deterministic( + buffer, + hashfunc=hashlib.sha256, + sigencode=ecdsa.util.sigencode_string_canonize, + ) + return base64.b64encode(signature_compact).decode("utf-8") + def get_address(self) -> str: return privkey_to_address(self.private_key) diff --git a/src/aleph/sdk/chains/ethereum.py b/src/aleph/sdk/chains/ethereum.py index a6e516f6..40ee2003 100644 --- a/src/aleph/sdk/chains/ethereum.py +++ b/src/aleph/sdk/chains/ethereum.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Dict, Optional, Union +from typing import Optional, Union from eth_account import Account from eth_account.messages import encode_defunct @@ -11,7 +11,6 @@ BaseAccount, get_fallback_private_key, get_public_key, - get_verification_buffer, ) @@ -23,12 +22,12 @@ class ETHAccount(BaseAccount): def __init__(self, private_key: bytes): self.private_key = private_key self._account = Account.from_key(self.private_key) - - async def sign_raw(self, buffer: bytes) -> bytes: + + async def sign_raw(self, buffer: bytes) -> str: """Sign a raw buffer.""" msghash = encode_defunct(text=buffer.decode("utf-8")) sig = self._account.sign_message(msghash) - return sig["signature"] + return sig["signature"].hex() def get_address(self) -> str: return self._account.address diff --git a/src/aleph/sdk/chains/nuls1.py b/src/aleph/sdk/chains/nuls1.py index c5629fb7..12ffaa37 100644 --- a/src/aleph/sdk/chains/nuls1.py +++ b/src/aleph/sdk/chains/nuls1.py @@ -315,6 +315,10 @@ async def sign_message(self, message): message["signature"] = sig.serialize().hex() return message + async def sign_raw(self, buffer: bytes) -> str: + sig = NulsSignature.sign_data(self.private_key, buffer) + return sig.serialize().hex() + def get_address(self): return address_from_hash( public_key_to_hash(self.get_public_key(), chain_id=self.chain_id) diff --git a/src/aleph/sdk/chains/nuls2.py b/src/aleph/sdk/chains/nuls2.py index ec1a367d..7618a02a 100644 --- a/src/aleph/sdk/chains/nuls2.py +++ b/src/aleph/sdk/chains/nuls2.py @@ -12,7 +12,6 @@ BaseAccount, get_fallback_private_key, get_public_key, - get_verification_buffer, ) @@ -37,16 +36,9 @@ def __init__(self, private_key=None, chain_id=1, prefix=None): else: self.prefix = prefix - async def sign_message(self, message): - # sig = NulsSignature.sign_message(self.private_key, - # get_verification_buffer(message)) - message = self._setup_sender(message) - - sig = sign_recoverable_message( - self.private_key, get_verification_buffer(message) - ) - message["signature"] = base64.b64encode(sig).decode() - return message + async def sign_raw(self, buffer: bytes) -> str: + sig = sign_recoverable_message(self.private_key, buffer) + return base64.b64encode(sig).decode() def get_address(self): return address_from_hash( diff --git a/src/aleph/sdk/chains/remote.py b/src/aleph/sdk/chains/remote.py index 8b27e615..250fcc62 100644 --- a/src/aleph/sdk/chains/remote.py +++ b/src/aleph/sdk/chains/remote.py @@ -77,6 +77,9 @@ async def sign_message(self, message: Dict) -> Dict: response.raise_for_status() return await response.json() + async def sign_raw(self, buffer: bytes) -> str: + raise NotImplementedError() + def get_address(self) -> str: return self._address diff --git a/src/aleph/sdk/chains/sol.py b/src/aleph/sdk/chains/sol.py index cc5a2cfa..96e4b2bf 100644 --- a/src/aleph/sdk/chains/sol.py +++ b/src/aleph/sdk/chains/sol.py @@ -32,15 +32,15 @@ async def sign_message(self, message: Dict) -> Dict: verif = get_verification_buffer(message) sig = { "publicKey": self.get_address(), - "signature": encode(self.sign_raw(verif)), + "signature": self.sign_raw(verif), } message["signature"] = json.dumps(sig) return message - async def sign_raw(self, buffer: bytes) -> bytes: + async def sign_raw(self, buffer: bytes) -> str: """Sign a raw buffer.""" sig = self._signing_key.sign(buffer) - return sig.signature + return encode(sig.signature) def get_address(self) -> str: return encode(self._signing_key.verify_key) diff --git a/src/aleph/sdk/chains/substrate.py b/src/aleph/sdk/chains/substrate.py index cc73a8b0..0f49c70e 100644 --- a/src/aleph/sdk/chains/substrate.py +++ b/src/aleph/sdk/chains/substrate.py @@ -25,6 +25,10 @@ async def sign_message(self, message): message["signature"] = json.dumps(sig) return message + async def sign_raw(self, buffer: bytes) -> str: + sig = self._account.sign(buffer) + return sig.hex() + def get_address(self): return self._account.ss58_address diff --git a/src/aleph/sdk/chains/tezos.py b/src/aleph/sdk/chains/tezos.py index af870c35..d31e2f8c 100644 --- a/src/aleph/sdk/chains/tezos.py +++ b/src/aleph/sdk/chains/tezos.py @@ -27,12 +27,15 @@ async def sign_message(self, message: Dict) -> Dict: verif = get_verification_buffer(message) sig = { "publicKey": self.get_public_key(), - "signature": self._account.sign(verif), + "signature": self.sign_raw(verif), } message["signature"] = json.dumps(sig) return message + async def sign_raw(self, buffer: bytes) -> str: + return self._account.sign(buffer) + def get_address(self) -> str: return self._account.public_key_hash() From fb033b346f79668bd688e410de1c1cb7b11627ab Mon Sep 17 00:00:00 2001 From: mhh Date: Sat, 12 Aug 2023 15:12:21 +0200 Subject: [PATCH 03/17] further formatting fixes --- src/aleph/sdk/chains/ethereum.py | 6 +----- src/aleph/sdk/chains/nuls2.py | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/aleph/sdk/chains/ethereum.py b/src/aleph/sdk/chains/ethereum.py index 40ee2003..10442c49 100644 --- a/src/aleph/sdk/chains/ethereum.py +++ b/src/aleph/sdk/chains/ethereum.py @@ -7,11 +7,7 @@ from eth_keys.exceptions import BadSignature as EthBadSignatureError from ..exceptions import BadSignatureError -from .common import ( - BaseAccount, - get_fallback_private_key, - get_public_key, -) +from .common import BaseAccount, get_fallback_private_key, get_public_key class ETHAccount(BaseAccount): diff --git a/src/aleph/sdk/chains/nuls2.py b/src/aleph/sdk/chains/nuls2.py index 7618a02a..4ef1d5a3 100644 --- a/src/aleph/sdk/chains/nuls2.py +++ b/src/aleph/sdk/chains/nuls2.py @@ -8,11 +8,7 @@ sign_recoverable_message, ) -from .common import ( - BaseAccount, - get_fallback_private_key, - get_public_key, -) +from .common import BaseAccount, get_fallback_private_key, get_public_key def get_address(public_key=None, private_key=None, chain_id=1, prefix="NULS"): From 25055aa84a99cb6def3d4e8ef3f3a70660b2c6aa Mon Sep 17 00:00:00 2001 From: mhh Date: Sat, 12 Aug 2023 15:57:57 +0200 Subject: [PATCH 04/17] fix missing await --- src/aleph/sdk/chains/sol.py | 2 +- src/aleph/sdk/chains/tezos.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aleph/sdk/chains/sol.py b/src/aleph/sdk/chains/sol.py index 96e4b2bf..d2980fd8 100644 --- a/src/aleph/sdk/chains/sol.py +++ b/src/aleph/sdk/chains/sol.py @@ -32,7 +32,7 @@ async def sign_message(self, message: Dict) -> Dict: verif = get_verification_buffer(message) sig = { "publicKey": self.get_address(), - "signature": self.sign_raw(verif), + "signature": await self.sign_raw(verif), } message["signature"] = json.dumps(sig) return message diff --git a/src/aleph/sdk/chains/tezos.py b/src/aleph/sdk/chains/tezos.py index d31e2f8c..69e379ae 100644 --- a/src/aleph/sdk/chains/tezos.py +++ b/src/aleph/sdk/chains/tezos.py @@ -27,7 +27,7 @@ async def sign_message(self, message: Dict) -> Dict: verif = get_verification_buffer(message) sig = { "publicKey": self.get_public_key(), - "signature": self.sign_raw(verif), + "signature": await self.sign_raw(verif), } message["signature"] = json.dumps(sig) From 42701e13cff579f0e7d7d7f96b13403a6d664694 Mon Sep 17 00:00:00 2001 From: mhh Date: Thu, 17 Aug 2023 11:50:53 +0200 Subject: [PATCH 05/17] add test_sign_raw() --- tests/unit/test_chain_ethereum.py | 10 ++++++++++ tests/unit/test_chain_solana.py | 10 ++++++++++ tests/unit/test_chain_tezos.py | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/tests/unit/test_chain_ethereum.py b/tests/unit/test_chain_ethereum.py index 62e941ec..8154aa24 100644 --- a/tests/unit/test_chain_ethereum.py +++ b/tests/unit/test_chain_ethereum.py @@ -138,3 +138,13 @@ async def test_verify_signature_wrong_public_key(ethereum_account): verify_signature( message["signature"], wrong_public_key, get_verification_buffer(message) ) + + +@pytest.mark.asyncio +async def test_sign_raw(ethereum_account): + buffer = b"SomeBuffer" + signature = await ethereum_account.sign_raw(buffer) + assert signature + assert isinstance(signature, str) + + verify_signature(signature, ethereum_account.get_address(), buffer.decode("utf-8")) diff --git a/tests/unit/test_chain_solana.py b/tests/unit/test_chain_solana.py index 7384229f..b339aa4f 100644 --- a/tests/unit/test_chain_solana.py +++ b/tests/unit/test_chain_solana.py @@ -119,3 +119,13 @@ async def test_verify_signature_with_forged_signature(solana_account): with pytest.raises(BadSignatureError): verify_signature(forged, message["sender"], get_verification_buffer(message)) + + +@pytest.mark.asyncio +async def test_sign_raw(solana_account): + buffer = b"SomeBuffer" + signature = await solana_account.sign_raw(buffer) + assert signature + assert isinstance(signature, str) + + verify_signature(signature, solana_account.get_address(), buffer.decode("utf-8")) diff --git a/tests/unit/test_chain_tezos.py b/tests/unit/test_chain_tezos.py index 15985972..163aa53f 100644 --- a/tests/unit/test_chain_tezos.py +++ b/tests/unit/test_chain_tezos.py @@ -71,3 +71,13 @@ async def test_decrypt_secp256k1(tezos_account: TezosAccount): decrypted = await tezos_account.decrypt(encrypted) assert isinstance(decrypted, bytes) assert content == decrypted + + +@pytest.mark.asyncio +async def test_sign_raw(tezos_account): + buffer = b"SomeBuffer" + signature = await tezos_account.sign_raw(buffer) + assert signature + assert isinstance(signature, str) + + verify_signature(signature, tezos_account.get_public_key(), buffer.decode("utf-8")) From eb91ef6db0c3da73a68a5af4003bd8437cbb85f3 Mon Sep 17 00:00:00 2001 From: mhh Date: Thu, 17 Aug 2023 13:40:18 +0200 Subject: [PATCH 06/17] rework sign_raw to return bytes --- src/aleph/sdk/chains/common.py | 7 ++++--- src/aleph/sdk/chains/cosmos.py | 7 ++++--- src/aleph/sdk/chains/ethereum.py | 10 +++++----- src/aleph/sdk/chains/nuls2.py | 21 +++++++++++++++++---- src/aleph/sdk/chains/remote.py | 2 +- src/aleph/sdk/chains/sol.py | 7 ++++--- src/aleph/sdk/chains/substrate.py | 8 ++++---- src/aleph/sdk/chains/tezos.py | 7 ++++--- tests/unit/test_chain_ethereum.py | 8 ++++---- tests/unit/test_chain_solana.py | 4 ++-- tests/unit/test_chain_tezos.py | 4 ++-- 11 files changed, 51 insertions(+), 34 deletions(-) diff --git a/src/aleph/sdk/chains/common.py b/src/aleph/sdk/chains/common.py index 8113bd3a..ff467ac3 100644 --- a/src/aleph/sdk/chains/common.py +++ b/src/aleph/sdk/chains/common.py @@ -71,17 +71,18 @@ async def sign_message(self, message: Dict) -> Dict: Dict: Signed message """ message = self._setup_sender(message) - message["signature"] = await self.sign_raw(get_verification_buffer(message)) + signature = await self.sign_raw(get_verification_buffer(message)) + message["signature"] = signature.hex() return message @abstractmethod - async def sign_raw(self, buffer: bytes) -> str: + async def sign_raw(self, buffer: bytes) -> bytes: """ Returns a signed message from a raw buffer. Args: buffer: Buffer to sign Returns: - str: Signature in preferred format + bytes: Signature in preferred format """ raise NotImplementedError diff --git a/src/aleph/sdk/chains/cosmos.py b/src/aleph/sdk/chains/cosmos.py index 7fadd133..2e5dd50a 100644 --- a/src/aleph/sdk/chains/cosmos.py +++ b/src/aleph/sdk/chains/cosmos.py @@ -53,9 +53,10 @@ async def sign_message(self, message): message = self._setup_sender(message) verif = get_verification_string(message) base64_pubkey = base64.b64encode(self.get_public_key().encode()).decode("utf-8") + signature = await self.sign_raw(verif.encode("utf-8")) sig = { - "signature": self.sign_raw(verif.encode("utf-8")), + "signature": signature.decode("utf-8"), "pub_key": {"type": "tendermint/PubKeySecp256k1", "value": base64_pubkey}, "account_number": str(0), "sequence": str(0), @@ -63,14 +64,14 @@ async def sign_message(self, message): message["signature"] = json.dumps(sig) return message - async def sign_raw(self, buffer: bytes) -> str: + async def sign_raw(self, buffer: bytes) -> bytes: privkey = ecdsa.SigningKey.from_string(self.private_key, curve=ecdsa.SECP256k1) signature_compact = privkey.sign_deterministic( buffer, hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_string_canonize, ) - return base64.b64encode(signature_compact).decode("utf-8") + return base64.b64encode(signature_compact) def get_address(self) -> str: return privkey_to_address(self.private_key) diff --git a/src/aleph/sdk/chains/ethereum.py b/src/aleph/sdk/chains/ethereum.py index 10442c49..85a77e9f 100644 --- a/src/aleph/sdk/chains/ethereum.py +++ b/src/aleph/sdk/chains/ethereum.py @@ -19,11 +19,11 @@ def __init__(self, private_key: bytes): self.private_key = private_key self._account = Account.from_key(self.private_key) - async def sign_raw(self, buffer: bytes) -> str: + async def sign_raw(self, buffer: bytes) -> bytes: """Sign a raw buffer.""" msghash = encode_defunct(text=buffer.decode("utf-8")) sig = self._account.sign_message(msghash) - return sig["signature"].hex() + return sig["signature"] def get_address(self) -> str: return self._account.address @@ -57,13 +57,13 @@ def verify_signature( else: if signature.startswith(b"0x"): signature = signature[2:] - signature = bytes.fromhex(signature.decode("utf-8")) if isinstance(public_key, bytes): public_key = "0x" + public_key.hex() if isinstance(message, bytes): - message = message.decode("utf-8") + message_hash = encode_defunct(primitive=message) + else: + message_hash = encode_defunct(text=message) - message_hash = encode_defunct(text=message) try: address = Account.recover_message(message_hash, signature=signature) if address.casefold() != public_key.casefold(): diff --git a/src/aleph/sdk/chains/nuls2.py b/src/aleph/sdk/chains/nuls2.py index 4ef1d5a3..cf9a379a 100644 --- a/src/aleph/sdk/chains/nuls2.py +++ b/src/aleph/sdk/chains/nuls2.py @@ -1,5 +1,5 @@ import base64 -from typing import Union +from typing import Union, Dict from nuls2.model.data import ( NETWORKS, @@ -8,7 +8,7 @@ sign_recoverable_message, ) -from .common import BaseAccount, get_fallback_private_key, get_public_key +from .common import BaseAccount, get_fallback_private_key, get_public_key, get_verification_buffer def get_address(public_key=None, private_key=None, chain_id=1, prefix="NULS"): @@ -32,9 +32,22 @@ def __init__(self, private_key=None, chain_id=1, prefix=None): else: self.prefix = prefix - async def sign_raw(self, buffer: bytes) -> str: + async def sign_message(self, message: Dict) -> Dict: + """ + Returns a signed message from an Aleph message. + Args: + message: Message to sign + Returns: + Dict: Signed message + """ + message = self._setup_sender(message) + signature = await self.sign_raw(get_verification_buffer(message)) + message["signature"] = signature.decode() + return message + + async def sign_raw(self, buffer: bytes) -> bytes: sig = sign_recoverable_message(self.private_key, buffer) - return base64.b64encode(sig).decode() + return base64.b64encode(sig) def get_address(self): return address_from_hash( diff --git a/src/aleph/sdk/chains/remote.py b/src/aleph/sdk/chains/remote.py index 250fcc62..b36036ac 100644 --- a/src/aleph/sdk/chains/remote.py +++ b/src/aleph/sdk/chains/remote.py @@ -77,7 +77,7 @@ async def sign_message(self, message: Dict) -> Dict: response.raise_for_status() return await response.json() - async def sign_raw(self, buffer: bytes) -> str: + async def sign_raw(self, buffer: bytes) -> bytes: raise NotImplementedError() def get_address(self) -> str: diff --git a/src/aleph/sdk/chains/sol.py b/src/aleph/sdk/chains/sol.py index d2980fd8..ff870a4d 100644 --- a/src/aleph/sdk/chains/sol.py +++ b/src/aleph/sdk/chains/sol.py @@ -30,17 +30,18 @@ async def sign_message(self, message: Dict) -> Dict: """Sign a message inplace.""" message = self._setup_sender(message) verif = get_verification_buffer(message) + signature = await self.sign_raw(verif) sig = { "publicKey": self.get_address(), - "signature": await self.sign_raw(verif), + "signature": encode(signature), } message["signature"] = json.dumps(sig) return message - async def sign_raw(self, buffer: bytes) -> str: + async def sign_raw(self, buffer: bytes) -> bytes: """Sign a raw buffer.""" sig = self._signing_key.sign(buffer) - return encode(sig.signature) + return sig.signature def get_address(self) -> str: return encode(self._signing_key.verify_key) diff --git a/src/aleph/sdk/chains/substrate.py b/src/aleph/sdk/chains/substrate.py index 0f49c70e..b52c954e 100644 --- a/src/aleph/sdk/chains/substrate.py +++ b/src/aleph/sdk/chains/substrate.py @@ -21,13 +21,13 @@ def __init__(self, mnemonics=None, address_type=42): async def sign_message(self, message): message = self._setup_sender(message) verif = get_verification_buffer(message).decode("utf-8") - sig = {"curve": self.CURVE, "data": self._account.sign(verif)} + signature = await self.sign_raw(verif.encode("utf-8")) + sig = {"curve": self.CURVE, "data": signature.hex()} message["signature"] = json.dumps(sig) return message - async def sign_raw(self, buffer: bytes) -> str: - sig = self._account.sign(buffer) - return sig.hex() + async def sign_raw(self, buffer: bytes) -> bytes: + return self._account.sign(buffer) def get_address(self): return self._account.ss58_address diff --git a/src/aleph/sdk/chains/tezos.py b/src/aleph/sdk/chains/tezos.py index 69e379ae..cffa3e78 100644 --- a/src/aleph/sdk/chains/tezos.py +++ b/src/aleph/sdk/chains/tezos.py @@ -25,16 +25,17 @@ async def sign_message(self, message: Dict) -> Dict: message = self._setup_sender(message) verif = get_verification_buffer(message) + signature = await self.sign_raw(verif) sig = { "publicKey": self.get_public_key(), - "signature": await self.sign_raw(verif), + "signature": signature.decode(), } message["signature"] = json.dumps(sig) return message - async def sign_raw(self, buffer: bytes) -> str: - return self._account.sign(buffer) + async def sign_raw(self, buffer: bytes) -> bytes: + return self._account.sign(buffer).encode() def get_address(self) -> str: return self._account.public_key_hash() diff --git a/tests/unit/test_chain_ethereum.py b/tests/unit/test_chain_ethereum.py index 8154aa24..fcf7382c 100644 --- a/tests/unit/test_chain_ethereum.py +++ b/tests/unit/test_chain_ethereum.py @@ -70,12 +70,12 @@ async def test_verify_signature(ethereum_account): get_verification_buffer(message), ) verify_signature( - bytes(message["signature"], "utf-8"), + message["signature"], bytes.fromhex(message["sender"][2:]), get_verification_buffer(message).decode("utf-8"), ) verify_signature( - bytes(message["signature"], "utf-8")[2:], + message["signature"], message["sender"], get_verification_buffer(message), ) @@ -145,6 +145,6 @@ async def test_sign_raw(ethereum_account): buffer = b"SomeBuffer" signature = await ethereum_account.sign_raw(buffer) assert signature - assert isinstance(signature, str) + assert isinstance(signature, bytes) - verify_signature(signature, ethereum_account.get_address(), buffer.decode("utf-8")) + verify_signature(signature, ethereum_account.get_address(), buffer) diff --git a/tests/unit/test_chain_solana.py b/tests/unit/test_chain_solana.py index b339aa4f..8115563f 100644 --- a/tests/unit/test_chain_solana.py +++ b/tests/unit/test_chain_solana.py @@ -126,6 +126,6 @@ async def test_sign_raw(solana_account): buffer = b"SomeBuffer" signature = await solana_account.sign_raw(buffer) assert signature - assert isinstance(signature, str) + assert isinstance(signature, bytes) - verify_signature(signature, solana_account.get_address(), buffer.decode("utf-8")) + verify_signature(signature, solana_account.get_address(), buffer) diff --git a/tests/unit/test_chain_tezos.py b/tests/unit/test_chain_tezos.py index 163aa53f..0beaffc9 100644 --- a/tests/unit/test_chain_tezos.py +++ b/tests/unit/test_chain_tezos.py @@ -78,6 +78,6 @@ async def test_sign_raw(tezos_account): buffer = b"SomeBuffer" signature = await tezos_account.sign_raw(buffer) assert signature - assert isinstance(signature, str) + assert isinstance(signature, bytes) - verify_signature(signature, tezos_account.get_public_key(), buffer.decode("utf-8")) + verify_signature(signature, tezos_account.get_public_key(), buffer) From e6e839147ae3ce84ec5ca3887996c253aed2654c Mon Sep 17 00:00:00 2001 From: mhh Date: Sat, 19 Aug 2023 13:19:28 +0200 Subject: [PATCH 07/17] add substrate tests; update substrate implementation and add PRIVATE_MNEMONIC_FILE to settings --- src/aleph/sdk/chains/nuls1.py | 4 +- src/aleph/sdk/chains/nuls2.py | 9 +- src/aleph/sdk/chains/substrate.py | 79 ++++++++++++---- src/aleph/sdk/conf.py | 10 ++ tests/unit/conftest.py | 8 ++ tests/unit/test_chain_substrate.py | 145 +++++++++++++++++++++++++++++ 6 files changed, 235 insertions(+), 20 deletions(-) create mode 100644 tests/unit/test_chain_substrate.py diff --git a/src/aleph/sdk/chains/nuls1.py b/src/aleph/sdk/chains/nuls1.py index 12ffaa37..645a8fda 100644 --- a/src/aleph/sdk/chains/nuls1.py +++ b/src/aleph/sdk/chains/nuls1.py @@ -315,9 +315,9 @@ async def sign_message(self, message): message["signature"] = sig.serialize().hex() return message - async def sign_raw(self, buffer: bytes) -> str: + async def sign_raw(self, buffer: bytes) -> bytes: sig = NulsSignature.sign_data(self.private_key, buffer) - return sig.serialize().hex() + return sig.serialize() def get_address(self): return address_from_hash( diff --git a/src/aleph/sdk/chains/nuls2.py b/src/aleph/sdk/chains/nuls2.py index cf9a379a..4ad65f19 100644 --- a/src/aleph/sdk/chains/nuls2.py +++ b/src/aleph/sdk/chains/nuls2.py @@ -1,5 +1,5 @@ import base64 -from typing import Union, Dict +from typing import Dict, Union from nuls2.model.data import ( NETWORKS, @@ -8,7 +8,12 @@ sign_recoverable_message, ) -from .common import BaseAccount, get_fallback_private_key, get_public_key, get_verification_buffer +from .common import ( + BaseAccount, + get_fallback_private_key, + get_public_key, + get_verification_buffer, +) def get_address(public_key=None, private_key=None, chain_id=1, prefix="NULS"): diff --git a/src/aleph/sdk/chains/substrate.py b/src/aleph/sdk/chains/substrate.py index b52c954e..397e8c16 100644 --- a/src/aleph/sdk/chains/substrate.py +++ b/src/aleph/sdk/chains/substrate.py @@ -1,21 +1,28 @@ import json -from typing import Union +import logging +from pathlib import Path +from typing import Optional, Union +from sr25519 import verify from substrateinterface import Keypair +from substrateinterface.utils.ss58 import ss58_decode from ..conf import settings +from ..exceptions import BadSignatureError from .common import BaseAccount, get_verification_buffer +logger = logging.getLogger(__name__) + class DOTAccount(BaseAccount): CHAIN = "DOT" CURVE = "sr25519" - def __init__(self, mnemonics=None, address_type=42): + def __init__(self, mnemonics: str, address_type=42): self.mnemonics = mnemonics self.address_type = address_type self._account = Keypair.create_from_mnemonic( - self.mnemonics, address_type=address_type + self.mnemonics, ss58_format=address_type ) async def sign_message(self, message): @@ -29,23 +36,38 @@ async def sign_message(self, message): async def sign_raw(self, buffer: bytes) -> bytes: return self._account.sign(buffer) - def get_address(self): + def get_address(self) -> str: return self._account.ss58_address - def get_public_key(self): - return self._account.public_key + def get_public_key(self) -> str: + return "0x" + self._account.public_key.hex() -def get_fallback_account(): - return DOTAccount(mnemonics=get_fallback_mnemonics()) +def get_fallback_account(path: Optional[Path] = None) -> DOTAccount: + return DOTAccount(mnemonics=get_fallback_mnemonics(path)) -def get_fallback_mnemonics(): - try: - mnemonic = settings.PRIVATE_KEY_FILE.read_text() - except OSError: +def get_fallback_mnemonics(path: Optional[Path] = None) -> str: + path = path or settings.PRIVATE_MNEMONIC_FILE + if path.exists() and path.stat().st_size > 0: + mnemonic = path.read_text() + else: mnemonic = Keypair.generate_mnemonic() - settings.PRIVATE_KEY_FILE.write_text(mnemonic) + path.parent.mkdir(exist_ok=True, parents=True) + path.write_text(mnemonic) + default_mnemonic_path = path.parent / "default.mnemonic" + + # If the symlink exists but does not point to a file, delete it. + if ( + default_mnemonic_path.is_symlink() + and not default_mnemonic_path.resolve().exists() + ): + default_mnemonic_path.unlink() + logger.warning("The symlink to the mnemonic is broken") + + # Create a symlink to use this mnemonic by default + if not default_mnemonic_path.exists(): + default_mnemonic_path.symlink_to(path) return mnemonic @@ -54,6 +76,31 @@ def verify_signature( signature: Union[bytes, str], public_key: Union[bytes, str], message: Union[bytes, str], -) -> bool: - """TODO: Implement this""" - raise NotImplementedError("Not implemented yet") +) -> None: + if isinstance(signature, str): + if signature.startswith("0x"): + signature = signature[2:] + signature = bytes.fromhex(signature) + if isinstance(public_key, str): + if public_key.startswith("0x"): + public_key = public_key[2:] + public_key = bytes.fromhex(public_key) + if isinstance(message, str): + message = message.encode() + + try: + verified = verify(signature, message, public_key) + if not verified: + # Another attempt with the data wrapped, as discussed in https://github.com/polkadot-js/extension/pull/743 + verified = verify(signature, b"" + message + b"", public_key) + if not verified: + raise BadSignatureError + except Exception as e: + raise BadSignatureError from e + + +def verify_signature_with_ss58_address( + signature: Union[bytes, str], address: str, message: Union[bytes, str] +) -> None: + address_bytes = ss58_decode(address) + return verify_signature(signature, address_bytes, message) diff --git a/src/aleph/sdk/conf.py b/src/aleph/sdk/conf.py index 264c8c9f..784b4ade 100644 --- a/src/aleph/sdk/conf.py +++ b/src/aleph/sdk/conf.py @@ -16,6 +16,11 @@ class Settings(BaseSettings): description="Path to the private key used to sign messages", ) + PRIVATE_MNEMONIC_FILE: Path = Field( + default=Path("substrate.mnemonic"), + description="Path to the mnemonic used to create Substrate keypairs", + ) + PRIVATE_KEY_STRING: Optional[str] = None API_HOST: str = "https://api2.aleph.im" MAX_INLINE_SIZE: int = 50000 @@ -57,3 +62,8 @@ class Config: settings.PRIVATE_KEY_FILE = Path( settings.CONFIG_HOME, "private-keys", "ethereum.key" ) + +if str(settings.PRIVATE_MNEMONIC_FILE) == "substrate.mnemonic": + settings.PRIVATE_MNEMONIC_FILE = Path( + settings.CONFIG_HOME, "private-keys", "substrate.mnemonic" + ) diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 9952f847..79e6d922 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -5,6 +5,7 @@ import aleph.sdk.chains.ethereum as ethereum import aleph.sdk.chains.sol as solana +import aleph.sdk.chains.substrate as substrate import aleph.sdk.chains.tezos as tezos from aleph.sdk.chains.common import get_fallback_private_key @@ -34,3 +35,10 @@ def tezos_account() -> tezos.TezosAccount: with NamedTemporaryFile(delete=False) as private_key_file: private_key_file.close() yield tezos.get_fallback_account(path=Path(private_key_file.name)) + + +@pytest.fixture +def substrate_account() -> substrate.DOTAccount: + with NamedTemporaryFile(delete=False) as private_key_file: + private_key_file.close() + yield substrate.get_fallback_account(path=Path(private_key_file.name)) diff --git a/tests/unit/test_chain_substrate.py b/tests/unit/test_chain_substrate.py new file mode 100644 index 00000000..5e5778e3 --- /dev/null +++ b/tests/unit/test_chain_substrate.py @@ -0,0 +1,145 @@ +import json +from dataclasses import asdict, dataclass +from pathlib import Path +from tempfile import NamedTemporaryFile + +import pytest + +from aleph.sdk.chains.common import get_verification_buffer +from aleph.sdk.chains.substrate import ( + get_fallback_account, + verify_signature, + verify_signature_with_ss58_address, +) +from aleph.sdk.exceptions import BadSignatureError + + +@dataclass +class Message: + chain: str + sender: str + type: str + item_hash: str + + +def test_get_fallback_account(): + with NamedTemporaryFile() as private_key_file: + account = get_fallback_account(path=Path(private_key_file.name)) + assert account.CHAIN == "DOT" + assert account.CURVE == "sr25519" + assert account._account.ss58_address + + +@pytest.mark.asyncio +async def test_DOTAccount(substrate_account): + account = substrate_account + + message = Message("DOT", account.get_address(), "SomeType", "ItemHash") + signed = await account.sign_message(asdict(message)) + assert signed["signature"] + assert len(signed["signature"]) == 160 + + address = account.get_address() + assert address + assert isinstance(address, str) + assert len(address) == 48 + + pubkey = account.get_public_key() + assert isinstance(pubkey, str) + assert len(pubkey) == 66 + + +@pytest.mark.asyncio +async def test_verify_signature(substrate_account): + account = substrate_account + + message = asdict( + Message( + "DOT", + account.get_address(), + "POST", + "SomeHash", + ) + ) + await account.sign_message(message) + assert message["signature"] + signature = json.loads(message["signature"])["data"] + + verify_signature_with_ss58_address( + signature, message["sender"], get_verification_buffer(message) + ) + + verify_signature_with_ss58_address( + signature, + message["sender"], + get_verification_buffer(message).decode(), + ) + + verify_signature( + signature, account.get_public_key(), get_verification_buffer(message) + ) + verify_signature( + signature, + bytes.fromhex(account.get_public_key()[2:]), + get_verification_buffer(message), + ) + + +@pytest.mark.asyncio +async def test_verify_signature_with_forged_signature(substrate_account): + account = substrate_account + + message = asdict( + Message( + "DOT", + account.get_address(), + "POST", + "SomeHash", + ) + ) + await account.sign_message(message) + assert message["signature"] + + forged_signature = "deadbeef" * 16 + + with pytest.raises(BadSignatureError): + verify_signature_with_ss58_address( + forged_signature, message["sender"], get_verification_buffer(message) + ) + + +@pytest.mark.asyncio +async def test_verify_signature_wrong_public_key(substrate_account): + account = substrate_account + + message = asdict( + Message( + "DOT", + account.get_address(), + "POST", + "SomeHash", + ) + ) + + await account.sign_message(message) + assert message["signature"] + sig = json.loads(message["signature"]) + + wrong_public_key: str = "0x" + "0" * 64 + with pytest.raises(BadSignatureError): + verify_signature( + sig["data"], wrong_public_key, get_verification_buffer(message) + ) + + +@pytest.mark.asyncio +async def test_sign_raw(substrate_account): + buffer = b"SomeBuffer" + signature = await substrate_account.sign_raw(buffer) + assert signature + assert isinstance(signature, bytes) + + verify_signature(signature, substrate_account.get_public_key(), buffer) + verify_signature_with_ss58_address( + signature, substrate_account.get_address(), buffer + ) From 7a8758158e95705699a7323769c29a1c3d9d3c01 Mon Sep 17 00:00:00 2001 From: mhh Date: Sat, 19 Aug 2023 13:36:34 +0200 Subject: [PATCH 08/17] update dependencies --- setup.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 48eb7f9b..59bf1a1d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -90,7 +90,8 @@ ethereum = # Required to fix a dependency issue with parsimonious and Python3.11 eth_abi==4.0.0b2; python_version>="3.11" polkadot = - substrate-interface==1.3.4 + substrate-interface + sr25519 cosmos = cosmospy solana = From a72fea3bf7fd37e144a06b65fbdd364b06d3e131 Mon Sep 17 00:00:00 2001 From: mhh Date: Sat, 19 Aug 2023 13:54:29 +0200 Subject: [PATCH 09/17] update dependencies for tests --- setup.cfg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.cfg b/setup.cfg index 59bf1a1d..7fa3ec7d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -79,6 +79,8 @@ testing = black isort flake8 + substrate-interface + sr25519 mqtt = aiomqtt<=0.1.3 certifi From c53b56910407e64ee2070c97e94021df716235b2 Mon Sep 17 00:00:00 2001 From: mhh Date: Sat, 19 Aug 2023 14:06:51 +0200 Subject: [PATCH 10/17] update dependencies for tests (again) --- setup.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index 7fa3ec7d..e926e128 100644 --- a/setup.cfg +++ b/setup.cfg @@ -80,7 +80,7 @@ testing = isort flake8 substrate-interface - sr25519 + py-sr25519-bindings mqtt = aiomqtt<=0.1.3 certifi @@ -93,7 +93,7 @@ ethereum = eth_abi==4.0.0b2; python_version>="3.11" polkadot = substrate-interface - sr25519 + py-sr25519-bindings cosmos = cosmospy solana = From 0afcc6543e797a4d0652708a7191b132782629c9 Mon Sep 17 00:00:00 2001 From: mhh Date: Sat, 19 Aug 2023 14:17:18 +0200 Subject: [PATCH 11/17] warn about ripemd160 deprecation --- src/aleph/sdk/chains/cosmos.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/aleph/sdk/chains/cosmos.py b/src/aleph/sdk/chains/cosmos.py index 2e5dd50a..d6bba627 100644 --- a/src/aleph/sdk/chains/cosmos.py +++ b/src/aleph/sdk/chains/cosmos.py @@ -74,6 +74,7 @@ async def sign_raw(self, buffer: bytes) -> bytes: return base64.b64encode(signature_compact) def get_address(self) -> str: + # WARNING: Fails with OpenSSL >= 3.2.0 due to deprecation of ripemd160 return privkey_to_address(self.private_key) def get_public_key(self) -> str: From 4318ae3d5f698e37ec5815daee5e8e6599aae522 Mon Sep 17 00:00:00 2001 From: mhh Date: Mon, 28 Aug 2023 22:46:03 +0200 Subject: [PATCH 12/17] dedup code into bytes_from_hex method --- src/aleph/sdk/chains/common.py | 7 +++++++ src/aleph/sdk/chains/ethereum.py | 9 ++------- src/aleph/sdk/chains/substrate.py | 10 +++------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/aleph/sdk/chains/common.py b/src/aleph/sdk/chains/common.py index ff467ac3..e811ce3f 100644 --- a/src/aleph/sdk/chains/common.py +++ b/src/aleph/sdk/chains/common.py @@ -156,3 +156,10 @@ def get_fallback_private_key(path: Optional[Path] = None) -> bytes: if not default_key_path.exists(): default_key_path.symlink_to(path) return private_key + + +def bytes_from_hex(hex_string: str) -> bytes: + if hex_string.startswith("0x"): + hex_string = hex_string[2:] + hex_string = bytes.fromhex(hex_string) + return hex_string diff --git a/src/aleph/sdk/chains/ethereum.py b/src/aleph/sdk/chains/ethereum.py index 85a77e9f..04b59d07 100644 --- a/src/aleph/sdk/chains/ethereum.py +++ b/src/aleph/sdk/chains/ethereum.py @@ -7,7 +7,7 @@ from eth_keys.exceptions import BadSignature as EthBadSignatureError from ..exceptions import BadSignatureError -from .common import BaseAccount, get_fallback_private_key, get_public_key +from .common import BaseAccount, get_fallback_private_key, get_public_key, bytes_from_hex class ETHAccount(BaseAccount): @@ -51,12 +51,7 @@ def verify_signature( BadSignatureError: If the signature is invalid. """ if isinstance(signature, str): - if signature.startswith("0x"): - signature = signature[2:] - signature = bytes.fromhex(signature) - else: - if signature.startswith(b"0x"): - signature = signature[2:] + signature = bytes_from_hex(signature) if isinstance(public_key, bytes): public_key = "0x" + public_key.hex() if isinstance(message, bytes): diff --git a/src/aleph/sdk/chains/substrate.py b/src/aleph/sdk/chains/substrate.py index 397e8c16..4bd32b85 100644 --- a/src/aleph/sdk/chains/substrate.py +++ b/src/aleph/sdk/chains/substrate.py @@ -9,7 +9,7 @@ from ..conf import settings from ..exceptions import BadSignatureError -from .common import BaseAccount, get_verification_buffer +from .common import BaseAccount, get_verification_buffer, bytes_from_hex logger = logging.getLogger(__name__) @@ -78,13 +78,9 @@ def verify_signature( message: Union[bytes, str], ) -> None: if isinstance(signature, str): - if signature.startswith("0x"): - signature = signature[2:] - signature = bytes.fromhex(signature) + signature = bytes_from_hex(signature) if isinstance(public_key, str): - if public_key.startswith("0x"): - public_key = public_key[2:] - public_key = bytes.fromhex(public_key) + public_key = bytes_from_hex(public_key) if isinstance(message, str): message = message.encode() From fd6b06f75d9b456ff0624c93dc7d89e92909ecea Mon Sep 17 00:00:00 2001 From: mhh Date: Mon, 28 Aug 2023 22:50:48 +0200 Subject: [PATCH 13/17] fix format and refactor --- src/aleph/sdk/chains/ethereum.py | 7 ++++++- src/aleph/sdk/chains/substrate.py | 11 +++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/aleph/sdk/chains/ethereum.py b/src/aleph/sdk/chains/ethereum.py index 04b59d07..4f00cd7e 100644 --- a/src/aleph/sdk/chains/ethereum.py +++ b/src/aleph/sdk/chains/ethereum.py @@ -7,7 +7,12 @@ from eth_keys.exceptions import BadSignature as EthBadSignatureError from ..exceptions import BadSignatureError -from .common import BaseAccount, get_fallback_private_key, get_public_key, bytes_from_hex +from .common import ( + BaseAccount, + bytes_from_hex, + get_fallback_private_key, + get_public_key, +) class ETHAccount(BaseAccount): diff --git a/src/aleph/sdk/chains/substrate.py b/src/aleph/sdk/chains/substrate.py index 4bd32b85..13795568 100644 --- a/src/aleph/sdk/chains/substrate.py +++ b/src/aleph/sdk/chains/substrate.py @@ -9,7 +9,7 @@ from ..conf import settings from ..exceptions import BadSignatureError -from .common import BaseAccount, get_verification_buffer, bytes_from_hex +from .common import BaseAccount, bytes_from_hex, get_verification_buffer logger = logging.getLogger(__name__) @@ -85,11 +85,10 @@ def verify_signature( message = message.encode() try: - verified = verify(signature, message, public_key) - if not verified: - # Another attempt with the data wrapped, as discussed in https://github.com/polkadot-js/extension/pull/743 - verified = verify(signature, b"" + message + b"", public_key) - if not verified: + # Another attempt with the data wrapped, as discussed in https://github.com/polkadot-js/extension/pull/743 + if not verify(signature, message, public_key) or verify( + signature, b"" + message + b"", public_key + ): raise BadSignatureError except Exception as e: raise BadSignatureError from e From bd6a17011c369bcb82286b88c85a5b6dff8a1af0 Mon Sep 17 00:00:00 2001 From: mhh Date: Mon, 28 Aug 2023 22:51:09 +0200 Subject: [PATCH 14/17] fix missing sign_raw() on LedgerETHAccount --- src/aleph/sdk/wallets/ledger/ethereum.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/aleph/sdk/wallets/ledger/ethereum.py b/src/aleph/sdk/wallets/ledger/ethereum.py index 392a68d4..2ecdc5d3 100644 --- a/src/aleph/sdk/wallets/ledger/ethereum.py +++ b/src/aleph/sdk/wallets/ledger/ethereum.py @@ -9,7 +9,7 @@ from ledgereth.messages import sign_message from ledgereth.objects import LedgerAccount, SignedMessage -from ...chains.common import BaseAccount, get_verification_buffer +from ...chains.common import BaseAccount, bytes_from_hex, get_verification_buffer class LedgerETHAccount(BaseAccount): @@ -74,6 +74,12 @@ async def sign_message(self, message: Dict) -> Dict: message["signature"] = signature return message + async def sign_raw(self, buffer: bytes) -> bytes: + """Sign a raw buffer.""" + sig: SignedMessage = sign_message(buffer, dongle=self._device) + signature: HexStr = sig.signature + return bytes_from_hex(signature) + def get_address(self) -> str: return self._account.address From ec513eed3836632269651d4c2f0dc32d4925bd53 Mon Sep 17 00:00:00 2001 From: mhh Date: Tue, 5 Sep 2023 16:31:44 +0200 Subject: [PATCH 15/17] add hardcoded messages to test verify_signature --- tests/unit/conftest.py | 7 ++++ tests/unit/messages.json | 67 +++++++++++++++++++++++++++++++ tests/unit/test_chain_ethereum.py | 8 ++++ tests/unit/test_chain_solana.py | 10 +++++ 4 files changed, 92 insertions(+) create mode 100644 tests/unit/messages.json diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 79e6d922..c8c0defb 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -1,3 +1,4 @@ +import json from pathlib import Path from tempfile import NamedTemporaryFile @@ -42,3 +43,9 @@ def substrate_account() -> substrate.DOTAccount: with NamedTemporaryFile(delete=False) as private_key_file: private_key_file.close() yield substrate.get_fallback_account(path=Path(private_key_file.name)) + + +@pytest.fixture +def messages(): + with open("./messages.json") as f: + return json.load(f) diff --git a/tests/unit/messages.json b/tests/unit/messages.json new file mode 100644 index 00000000..5b7931e1 --- /dev/null +++ b/tests/unit/messages.json @@ -0,0 +1,67 @@ +[ + { + "item_hash": "24717e60ba577b17c1f47796a4c4e3de887cbf99ce3276157fe7015857d1ba47", + "type": "POST", + "chain": "SOL", + "sender": "fishbsxxtW2iRwBgihKZEWGv4EMZ47G6ypx3P22Nhqx", + "signature": "{\"signature\":\"53uHLe8nGgHG5Pub2ZpGk2WSTNmspu8hoK7vRM1Lz1gBbaN5t6LLLDix585pJR3LpotinEMtYYrcyZsw4QfY2nf1\",\"publicKey\":\"fishbsxxtW2iRwBgihKZEWGv4EMZ47G6ypx3P22Nhqx\"}", + "item_type": "inline", + "item_content": "{\"type\":\"Permission\",\"address\":\"fishbsxxtW2iRwBgihKZEWGv4EMZ47G6ypx3P22Nhqx\",\"content\":{\"datasetID\":\"55998e1e21ac4d9fbd7612194fc175407320eb2e53c4e02719850a6ccfac4f26\",\"authorizer\":\"8zWzM8NVDrgqZMqcKhESsTumo1JTyhLjRDpBMZBCy394\",\"status\":\"GRANTED\",\"requestor\":\"FseBmSzpvpTTNiVyvTxSiVpyhQ5ChgViwCuvYNsfFqCS\",\"tags\":[\"FseBmSzpvpTTNiVyvTxSiVpyhQ5ChgViwCuvYNsfFqCS\",\"2JCJXePWQgBWZz4d7UuHFYhBwaPkuEhMrb4EEqf94qyu\"],\"executionCount\":0,\"maxExecutionCount\":1},\"time\":1693749978.337}", + "content": { + "time": 1693749978.337, + "type": "Permission", + "address": "fishbsxxtW2iRwBgihKZEWGv4EMZ47G6ypx3P22Nhqx", + "content": { + "tags": [ + "FseBmSzpvpTTNiVyvTxSiVpyhQ5ChgViwCuvYNsfFqCS", + "2JCJXePWQgBWZz4d7UuHFYhBwaPkuEhMrb4EEqf94qyu" + ], + "status": "GRANTED", + "datasetID": "55998e1e21ac4d9fbd7612194fc175407320eb2e53c4e02719850a6ccfac4f26", + "requestor": "FseBmSzpvpTTNiVyvTxSiVpyhQ5ChgViwCuvYNsfFqCS", + "authorizer": "8zWzM8NVDrgqZMqcKhESsTumo1JTyhLjRDpBMZBCy394", + "executionCount": 0, + "maxExecutionCount": 1 + } + }, + "time": 1693749978.337, + "channel": "FISHNET_DEMO_BERLIN_2", + "size": 472, + "confirmations": [ + { + "chain": "ETH", + "hash": "0x723b7bb333fd9a97ef0abe3a424ce5a61a64231a405f2aa5df0f8107506df8c2", + "height": 18056735 + } + ], + "confirmed": true + }, + { + "item_hash": "a17588da875f17a0775d7d80a87a2e1719edef401671d4a65936746c00a6a234", + "type": "AGGREGATE", + "chain": "ETH", + "sender": "0x51A58800b26AA1451aaA803d1746687cB88E0501", + "signature": "0x7a808edfecf2abac1606612ab7f9d52ff31eea7e2bc549824187eae9107a9c1a46ece07ec1cb28411d08394304c651b578658d2de4af30ca1a0526441dc543c11b", + "item_type": "inline", + "item_content": "{\"address\":\"0x51A58800b26AA1451aaA803d1746687cB88E0501\",\"key\":\"0x1ef1f1bb75314f8ef86039c96cf39f11754d9ad0binance\",\"content\":{\"1693923683606\":{\"version\":\"x25519-xsalsa20-poly1305\",\"nonce\":\"hX6Xt8UJbWMjDO9Q8oF1iboZYUu1DXzR\",\"ephemPublicKey\":\"8kvL6HEq3MefSfXBMjozkoQbLmHciRrkdKedIDXJsCA=\",\"ciphertext\":\"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\",\"sha256\":\"df4ba2c781428d5d92341f518895a57c697f1871ec672872e67a51c849ec5042\"}},\"time\":1693923684.147}", + "content": { + "key": "0x1ef1f1bb75314f8ef86039c96cf39f11754d9ad0binance", + "time": 1693923684.147, + "address": "0x51A58800b26AA1451aaA803d1746687cB88E0501", + "content": { + "1693923683606": { + "nonce": "hX6Xt8UJbWMjDO9Q8oF1iboZYUu1DXzR", + "sha256": "df4ba2c781428d5d92341f518895a57c697f1871ec672872e67a51c849ec5042", + "version": "x25519-xsalsa20-poly1305", + "ciphertext": "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", + "ephemPublicKey": "8kvL6HEq3MefSfXBMjozkoQbLmHciRrkdKedIDXJsCA=" + } + } + }, + "time": 1693923684.147, + "channel": "UNSLASHED", + "size": 4006, + "confirmations": [], + "confirmed": false + } +] \ No newline at end of file diff --git a/tests/unit/test_chain_ethereum.py b/tests/unit/test_chain_ethereum.py index fcf7382c..dea58c69 100644 --- a/tests/unit/test_chain_ethereum.py +++ b/tests/unit/test_chain_ethereum.py @@ -81,6 +81,14 @@ async def test_verify_signature(ethereum_account): ) +@pytest.mark.asyncio +async def test_verify_signature_with_processed_message(ethereum_account, messages): + message = messages[1] + verify_signature( + message["signature"], message["sender"], get_verification_buffer(message) + ) + + @pytest.mark.asyncio async def test_verify_signature_with_forged_signature(ethereum_account): account = ethereum_account diff --git a/tests/unit/test_chain_solana.py b/tests/unit/test_chain_solana.py index 8115563f..1e0ffcfd 100644 --- a/tests/unit/test_chain_solana.py +++ b/tests/unit/test_chain_solana.py @@ -102,6 +102,16 @@ async def test_verify_signature(solana_account): ) +@pytest.mark.asyncio +async def test_verify_signature_with_processed_message(solana_account, messages): + message = messages[0] + signature = json.loads(message["signature"])["signature"] + verify_signature( + signature, message["sender"], get_verification_buffer(message) + ) + + + @pytest.mark.asyncio async def test_verify_signature_with_forged_signature(solana_account): message = asdict( From 4ea59741902e180b1cefb28d75fc310420c1354f Mon Sep 17 00:00:00 2001 From: mhh Date: Tue, 5 Sep 2023 16:36:40 +0200 Subject: [PATCH 16/17] fix messages.json path --- tests/unit/conftest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index c8c0defb..4f62c0c5 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -47,5 +47,6 @@ def substrate_account() -> substrate.DOTAccount: @pytest.fixture def messages(): - with open("./messages.json") as f: + messages_path = Path(__file__).parent / "messages.json" + with open(messages_path) as f: return json.load(f) From 51716c5e79b6f899af62e23539c30ce4e748ef36 Mon Sep 17 00:00:00 2001 From: mhh Date: Tue, 5 Sep 2023 16:50:05 +0200 Subject: [PATCH 17/17] format --- tests/unit/test_chain_solana.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/unit/test_chain_solana.py b/tests/unit/test_chain_solana.py index 1e0ffcfd..5088158a 100644 --- a/tests/unit/test_chain_solana.py +++ b/tests/unit/test_chain_solana.py @@ -106,10 +106,7 @@ async def test_verify_signature(solana_account): async def test_verify_signature_with_processed_message(solana_account, messages): message = messages[0] signature = json.loads(message["signature"])["signature"] - verify_signature( - signature, message["sender"], get_verification_buffer(message) - ) - + verify_signature(signature, message["sender"], get_verification_buffer(message)) @pytest.mark.asyncio