Skip to content

Commit

Permalink
Merge pull request #20 from trilitech/palmer@functori@test-signing-co…
Browse files Browse the repository at this point in the history
…nstraints

Test signing constraints
  • Loading branch information
ajinkyaraj-23 authored Feb 2, 2024
2 parents 7fc866e + c077e15 commit 888c826
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 20 deletions.
168 changes: 150 additions & 18 deletions test/python/test_instructions.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""Module gathering the baking app instruction tests."""

from pathlib import Path
from typing import Callable, Tuple
import pytest
from ragger.firmware import Firmware
from ragger.navigator import Navigator, NavInsID
from utils.client import TezosClient, Version, Hwm
from utils.account import Account
from utils.client import TezosClient, Version, Hwm, StatusCode
from utils.account import Account, SigScheme
from utils.helper import get_current_commit
from utils.message import (
Message,
Preattestation,
Attestation,
AttestationDal,
Expand All @@ -22,7 +24,6 @@
TESTS_ROOT_DIR
)


def test_review_home(
firmware: Firmware,
navigator: Navigator,
Expand Down Expand Up @@ -270,6 +271,37 @@ def test_get_all_hwm(
f"Expected test hmw {test_hwm} but got {received_test_hwm}"


def build_preattestation(op_level, op_round, chain_id):
"""Build a preattestation."""
return Preattestation(
op_level=op_level,
op_round=op_round
).forge(chain_id=chain_id)

def build_attestation(op_level, op_round, chain_id):
"""Build a attestation."""
return Attestation(
op_level=op_level,
op_round=op_round
).forge(chain_id=chain_id)

def build_attestation_dal(op_level, op_round, chain_id):
"""Build a attestation_dal."""
return AttestationDal(
op_level=op_level,
op_round=op_round
).forge(chain_id=chain_id)

def build_block(level, current_round, chain_id):
"""Build a block."""
return Block(
header=BlockHeader(
level=level,
fitness=Fitness(current_round=current_round)
)
).forge(chain_id=chain_id)


@pytest.mark.parametrize("account", [DEFAULT_ACCOUNT])
@pytest.mark.parametrize("with_hash", [False, True])
def test_sign_preattestation(
Expand All @@ -291,10 +323,11 @@ def test_sign_preattestation(
test_hwm
)

preattestation = Preattestation(
preattestation = build_preattestation(
op_level=1,
op_round=2
).forge(chain_id=main_chain_id)
op_round=2,
chain_id=main_chain_id
)

if with_hash:
signature = client.sign_message(account, preattestation)
Expand Down Expand Up @@ -337,10 +370,11 @@ def test_sign_attestation(
test_hwm
)

attestation = Attestation(
attestation = build_attestation(
op_level=1,
op_round=2
).forge(chain_id=main_chain_id)
op_round=2,
chain_id=main_chain_id
)

if with_hash:
signature = client.sign_message(account, attestation)
Expand Down Expand Up @@ -383,10 +417,11 @@ def test_sign_attestation_dal(
test_hwm
)

attestation = AttestationDal(
attestation = build_attestation_dal(
op_level=1,
op_round=2
).forge(chain_id=main_chain_id)
op_round=2,
chain_id=main_chain_id
)

if with_hash:
signature = client.sign_message(account, attestation)
Expand Down Expand Up @@ -429,12 +464,11 @@ def test_sign_block(
test_hwm
)

block = Block(
header=BlockHeader(
level=1,
fitness=Fitness(current_round=2)
)
).forge(chain_id=main_chain_id)
block = build_block(
level=1,
current_round=2,
chain_id=main_chain_id
)

if with_hash:
signature = client.sign_message(account, block)
Expand All @@ -455,6 +489,104 @@ def test_sign_block(
path=test_name
)

PARAMETERS = [
(build_attestation, (0, 0), build_preattestation, (0, 1), True ),
(build_block, (0, 1), build_attestation_dal, (1, 0), True ),
(build_block, (0, 1), build_attestation_dal, (0, 0), False),
(build_attestation, (1, 0), build_preattestation, (0, 1), False),
] + [
(build_preattestation, (0, 0), build_preattestation, (0, 0), False),
(build_preattestation, (0, 0), build_block, (0, 0), False),
(build_preattestation, (0, 0), build_attestation, (0, 0), True ),
(build_preattestation, (0, 0), build_attestation_dal, (0, 0), True ),
(build_attestation, (0, 0), build_preattestation, (0, 0), False),
(build_attestation, (0, 0), build_attestation, (0, 0), False),
(build_attestation, (0, 0), build_attestation_dal, (0, 0), False),
(build_attestation, (0, 0), build_block, (0, 0), False),
(build_attestation_dal, (0, 0), build_preattestation, (0, 0), False),
(build_attestation_dal, (0, 0), build_attestation, (0, 0), False),
(build_attestation_dal, (0, 0), build_attestation_dal, (0, 0), False),
(build_attestation_dal, (0, 0), build_block, (0, 0), False),
(build_block, (1, 1), build_preattestation, (1, 1), True ),
(build_block, (1, 1), build_attestation, (1, 1), True ),
(build_block, (1, 1), build_attestation_dal, (1, 1), True ),
(build_block, (1, 1), build_block, (1, 1), False),
]

@pytest.mark.parametrize(
"message_builder_1, level_round_1, " \
"message_builder_2, level_round_2, " \
"success",
PARAMETERS)
@pytest.mark.parametrize("account", [DEFAULT_ACCOUNT])
def test_sign_level_authorized(
account: Account,
message_builder_1: Callable[[int, int, str], Message],
level_round_1: Tuple[int, int],
message_builder_2: Callable[[int, int, str], Message],
level_round_2: Tuple[int, int],
success: bool,
client: TezosClient,
tezos_navigator: TezosNavigator) -> None:
"""Test whether the level/round constraints behave as expected."""

main_chain_id = DEFAULT_CHAIN_ID
main_level = 1

tezos_navigator.setup_app_context(
account,
main_chain_id,
main_hwm=Hwm(main_level),
test_hwm=Hwm(0)
)

level_1, round_1 = level_round_1
message_1 = message_builder_1(
level_1 + main_level,
round_1,
main_chain_id
)
level_2, round_2 = level_round_2
message_2 = message_builder_2(
level_2 + main_level,
round_2,
main_chain_id
)

client.sign_message(account, message_1)

if success:
client.sign_message(account, message_2)
else:
with StatusCode.WRONG_VALUES.expected():
client.sign_message(account, message_2)

def test_sign_not_authorized_key(
client: TezosClient,
tezos_navigator: TezosNavigator) -> None:
"""Check that signing with a key different from the authorized key is not authorized.."""

account_1 = DEFAULT_ACCOUNT
account_2 = Account(
"m/9'/12'/13'/8'/78'",
SigScheme.ED25519,
"edsk3eZBgFAf1VtdibfxoCcihxXje9S3th7jdEgVA2kHG82EKYNKNm"
)

main_chain_id = DEFAULT_CHAIN_ID

tezos_navigator.setup_app_context(
account_1,
main_chain_id,
main_hwm=Hwm(0),
test_hwm=Hwm(0)
)

attestation = build_attestation(0, 0, main_chain_id)

with StatusCode.SECURITY.expected():
client.sign_message(account_2, attestation)


# Data generated by the old application itself
HMAC_TEST_SET = [
Expand Down
28 changes: 26 additions & 2 deletions test/python/utils/client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""Module providing a tezos client."""

from typing import Tuple, Optional
from typing import Tuple, Optional, Generator
from enum import IntEnum
from contextlib import contextmanager

from ragger.utils import RAPDU
from ragger.backend import BackendInterface
Expand Down Expand Up @@ -142,7 +143,30 @@ class Index(IntEnum):
class StatusCode(IntEnum):
"""Class representing the status code."""

OK = 0x9000
OK = 0x9000
WRONG_PARAM = 0x6b00
WRONG_LENGTH = 0x6c00
INVALID_INS = 0x6d00
WRONG_LENGTH_FOR_INS = 0x917e
REJECT = 0x6985
PARSE_ERROR = 0x9405
REFERENCED_DATA_NOT_FOUND = 0x6a88
WRONG_VALUES = 0x6a80
SECURITY = 0x6982
HID_REQUIRED = 0x6983
CLASS = 0x6e00
MEMORY_ERROR = 0x9200

@contextmanager
def expected(self) -> Generator[None, None, None]:
"""Fail if the right RAPDU code exception is not raise."""
try:
yield
assert False, f"Expect fail with { self.name } but succeed"
except ExceptionRAPDU as e:
failing_code = StatusCode(e.status)
assert self == failing_code, \
f"Expect fail with { self.name } but fail with { failing_code.name }"


MAX_APDU_SIZE: int = 235
Expand Down

0 comments on commit 888c826

Please sign in to comment.