feat: eip712 tests

This commit is contained in:
Coline
2022-07-04 12:40:14 +02:00
parent e162bbe35e
commit 0ba963cf02
39 changed files with 251 additions and 3 deletions

View File

@@ -7,7 +7,7 @@ from speculos.client import SpeculosClient, ApduException
from ethereum_client.ethereum_cmd_builder import EthereumCommandBuilder, InsType
from ethereum_client.exception import DeviceException
from ethereum_client.transaction import PersonalTransaction, Transaction
from ethereum_client.transaction import EIP712, PersonalTransaction, Transaction
from ethereum_client.plugin import ERC20_Information, Plugin
from ethereum_client.utils import parse_sign_response
@@ -173,6 +173,29 @@ class EthereumCommand:
result.append(v)
result.append(r)
result.append(s)
@contextmanager
def sign_eip712(self, bip32_path: str, transaction: EIP712, result: List = list()) -> None:
try:
chunk: bytes = self.builder.sign_eip712(bip32_path=bip32_path, transaction=transaction)
with self.client.apdu_exchange_nowait(cla=chunk[0], ins=chunk[1],
p1=chunk[2], p2=chunk[3],
data=chunk[5:]) as exchange:
yield exchange
response: bytes = exchange.receive()
except ApduException as error:
raise DeviceException(error_code=error.sw, ins=InsType.INS_SIGN_EIP712)
# response = V (1) || R (32) || S (32)
assert len(response) == 65
v, r, s = parse_sign_response(response)
result.append(v)
result.append(r)
result.append(s)
@contextmanager

View File

@@ -3,7 +3,7 @@ import logging
import struct
from typing import List, Tuple, Union, Iterator, cast
from ethereum_client.transaction import PersonalTransaction, Transaction
from ethereum_client.transaction import EIP712, PersonalTransaction, Transaction
from ethereum_client.plugin import ERC20_Information, Plugin
from ethereum_client.utils import bip32_path_from_string
@@ -320,6 +320,41 @@ class EthereumCommandBuilder:
p2=0x00,
cdata=cdata)
def sign_eip712(self, bip32_path: str, transaction: EIP712) -> bytes:
"""Command builder for INS_SIGN_EIP712.
Parameters
----------
bip32_path : str
String representation of BIP32 path.
transaction : EIP712
Domain hash -> 32 bytes
Message hash -> 32 bytes
Yields
-------
bytes
APDU command chunk for INS_SIGN_EIP712.
"""
bip32_paths: List[bytes] = bip32_path_from_string(bip32_path)
cdata: bytes = b"".join([
len(bip32_paths).to_bytes(1, byteorder="big"),
*bip32_paths
])
tx: bytes = transaction.serialize()
cdata = cdata + tx
return self.serialize(cla=self.CLA,
ins=InsType.INS_SIGN_EIP712,
p1=0x00,
p2=0x00,
cdata=cdata)
def simple_personal_sign_tx(self, bip32_path: str, transaction: PersonalTransaction) -> bytes:
"""Command builder for INS_SIGN_PERSONAL_TX.

View File

@@ -1,6 +1,6 @@
from typing import Union
from ethereum_client.utils import write_varint, UINT64_MAX
from ethereum_client.utils import apdu_as_string, write_varint, UINT64_MAX
class TransactionError(Exception):
@@ -83,3 +83,14 @@ class Transaction:
self.chainID,
])
class EIP712:
def __init__(self, domain_hash: str, msg_hash: str) -> None:
self.domain_hash = apdu_as_string(domain_hash)
self.msg_hash = apdu_as_string(msg_hash)
def serialize(self) -> bytes:
return b"".join([
self.domain_hash,
self.msg_hash
])

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

View File

@@ -0,0 +1,179 @@
from time import sleep
from ethereum_client.utils import compare_screenshot, save_screenshot, PATH_IMG, parse_sign_response
from ethereum_client.transaction import EIP712
import ethereum_client
def test_sign_eip_712_hashed_msg(cmd):
result: list = []
bip32_path="44'/60'/0'/0'/0"
transaction = EIP712(
domain_hash="c24f499b8c957196651b13edd64aaccc3980009674b2aea0966c8a56ba81278e",
msg_hash="9d96be8a7cca396e711a3ba356bd9878df02a726d753ddb6cda3c507d888bc77"
)
with cmd.sign_eip712(bip32_path=bip32_path, transaction=transaction, result=result) as ex:
sleep(0.5)
if cmd.model == "nanos":
# Sign typed message
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00000.png")
cmd.client.press_and_release('right')
# Domain hash 1/4, 2/4, 3/4, 4/4
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00001.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00002.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00003.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00004.png")
cmd.client.press_and_release('right')
# Message hash 1/4, 2/4, 3/4, 4/4
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00005.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00006.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00007.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00008.png")
cmd.client.press_and_release('right')
# Sign message
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00009.png")
cmd.client.press_and_release('both')
if cmd.model == "nanox" or cmd.model == "nanosp":
# Sign typed message
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00000.png")
cmd.client.press_and_release('right')
# Domain hash 1/2, 2/2
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00001.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00002.png")
cmd.client.press_and_release('right')
# Message hash 1/2, 2/2
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00003.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00004.png")
cmd.client.press_and_release('right')
# Sign message
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg/00005.png")
cmd.client.press_and_release('both')
v, r, s = result
assert v == 0x1B #27
assert r.hex() == "b1cf3dd6f2902ae9b181e158cc07f6ee6e6c456360b18842ece0b947dec89f07"
assert s.hex() == "5372a9b1a495b76ccd75347b6f591867859fb73aa05a546b79c81073ddff5e8a"
def test_sign_eip_712_hashed_msg_reject(cmd):
result: list = []
bip32_path="44'/60'/0'/0'/0"
transaction = EIP712(
domain_hash="c24f499b8c957196651b13edd64aaccc3980009674b2aea0966c8a56ba81278e",
msg_hash="9d96be8a7cca396e711a3ba356bd9878df02a726d753ddb6cda3c507d888bc77"
)
try:
with cmd.sign_eip712(bip32_path=bip32_path, transaction=transaction, result=result) as ex:
sleep(0.5)
if cmd.model == "nanos":
# Sign typed message
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00000.png")
cmd.client.press_and_release('right')
# Domain hash 1/4, 2/4, 3/4, 4/4
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00001.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00002.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00003.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00004.png")
cmd.client.press_and_release('right')
# Message hash 1/4, 2/4, 3/4, 4/4
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00005.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00006.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00007.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00008.png")
cmd.client.press_and_release('right')
# Sign message
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00009.png")
cmd.client.press_and_release('right')
# Cancel signature
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00010.png")
cmd.client.press_and_release('both')
if cmd.model == "nanox" or cmd.model == "nanosp":
# Sign typed message
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00000.png")
cmd.client.press_and_release('right')
# Domain hash 1/2, 2/2
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00001.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00002.png")
cmd.client.press_and_release('right')
# Message hash 1/2, 2/2
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00003.png")
cmd.client.press_and_release('right')
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00004.png")
cmd.client.press_and_release('right')
# Sign message
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00005.png")
cmd.client.press_and_release('right')
# Cancel signature
compare_screenshot(cmd, f"screenshots/eip712/{PATH_IMG[cmd.model]}/sign_eip_712_hashed_msg_reject/00006.png")
cmd.client.press_and_release('both')
except ethereum_client.exception.errors.DenyError as error:
assert error.args[0] == '0x6985'
def test_sign_eip_712_bad_domain(cmd):
result: list = []
bip32_path="44'/60'/0'/0'/0"
transaction = EIP712(
domain_hash="deadbeef",
msg_hash="9d96be8a7cca396e711a3ba356bd9878df02a726d753ddb6cda3c507d888bc77"
)
try:
with cmd.sign_eip712(bip32_path=bip32_path, transaction=transaction, result=result) as ex:
pass
except ethereum_client.exception.errors.UnknownDeviceError as error:
assert error.args[0] == '0x6a80'
def test_sign_eip_712_bad_msg(cmd):
result: list = []
bip32_path="44'/60'/0'/0'/0"
transaction = EIP712(
domain_hash="c24f499b8c957196651b13edd64aaccc3980009674b2aea0966c8a56ba81278e",
msg_hash="deadbeef"
)
try:
with cmd.sign_eip712(bip32_path=bip32_path, transaction=transaction, result=result) as ex:
pass
except ethereum_client.exception.errors.UnknownDeviceError as error:
assert error.args[0] == '0x6a80'