Skip to content

Commit 4cfa279

Browse files
Merge pull request #6 from BitHighlander/fix/test-updates
fix: update tests for AdvancedMode gate + BIP-85 display-only
2 parents 81de77b + f90fe14 commit 4cfa279

4 files changed

Lines changed: 27 additions & 108 deletions

File tree

tests/test_msg_bip85.py

Lines changed: 23 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,158 +1,74 @@
1-
# BIP-85 child mnemonic derivation tests.
2-
#
3-
# Tests GetBip85Mnemonic message which derives deterministic child
4-
# mnemonics from the device seed per the BIP-85 specification.
5-
#
6-
# Uses the "all" x12 mnemonic as the master seed.
1+
"""BIP-85 display-only tests.
2+
3+
Firmware >= 7.14.0 derives the BIP-85 child mnemonic, displays it on the
4+
device screen, and responds with Success (mnemonic is never sent over USB).
5+
"""
76

87
import unittest
98
import common
10-
119
import keepkeylib.messages_pb2 as proto
12-
13-
# BIP-39 English wordlist (2048 words)
14-
# We load it inline to avoid external file dependencies.
15-
BIP39_WORDLIST = None
16-
17-
def _load_bip39_wordlist():
18-
"""Load BIP-39 English wordlist from mnemonic package or fallback."""
19-
global BIP39_WORDLIST
20-
if BIP39_WORDLIST is not None:
21-
return BIP39_WORDLIST
22-
23-
# Try the mnemonic package first (ships with python-keepkey deps)
24-
try:
25-
from mnemonic import Mnemonic
26-
m = Mnemonic("english")
27-
BIP39_WORDLIST = m.wordlist
28-
return BIP39_WORDLIST
29-
except ImportError:
30-
pass
31-
32-
# Fallback: accept any lowercase alpha words and skip strict validation
33-
BIP39_WORDLIST = None
34-
return None
35-
36-
37-
def _validate_mnemonic_words(mnemonic_str):
38-
"""Validate that each word in the mnemonic is in the BIP-39 wordlist.
39-
40-
Returns (is_valid, bad_words) tuple. If wordlist unavailable, returns
41-
(True, []) -- we still validate word count and format elsewhere.
42-
"""
43-
wordlist = _load_bip39_wordlist()
44-
words = mnemonic_str.split()
45-
if wordlist is None:
46-
# No wordlist available; just check words are lowercase alpha
47-
bad = [w for w in words if not w.isalpha() or not w.islower()]
48-
return (len(bad) == 0, bad)
49-
bad = [w for w in words if w not in wordlist]
50-
return (len(bad) == 0, bad)
10+
import keepkeylib.types_pb2 as proto_types
5111

5212

5313
class TestMsgBip85(common.KeepKeyTest):
54-
"""Test BIP-85 child mnemonic derivation from the device."""
5514

5615
def test_bip85_12word(self):
57-
"""Derive a 12-word child mnemonic at index 0."""
16+
"""Derive a 12-word child mnemonic at index 0 — device displays, returns Success."""
5817
self.requires_firmware("7.14.0")
5918
self.setup_mnemonic_allallall()
6019

6120
resp = self.client.call(proto.GetBip85Mnemonic(word_count=12, index=0))
6221

63-
# Response must be a Bip85Mnemonic message
64-
self.assertTrue(
65-
isinstance(resp, proto.Bip85Mnemonic),
66-
"Expected Bip85Mnemonic response, got %s" % type(resp).__name__
67-
)
68-
69-
mnemonic = resp.mnemonic
70-
words = mnemonic.split()
71-
72-
# Must have exactly 12 words
73-
self.assertTrue(
74-
len(words) == 12,
75-
"Expected 12 words, got %d: %s" % (len(words), mnemonic)
76-
)
77-
78-
# Each word must be a valid BIP-39 word
79-
is_valid, bad_words = _validate_mnemonic_words(mnemonic)
22+
# Firmware display-only mode returns Success
8023
self.assertTrue(
81-
is_valid,
82-
"Invalid BIP-39 words found: %s" % bad_words
24+
isinstance(resp, proto.Success),
25+
"Expected Success response, got %s" % type(resp).__name__
8326
)
8427

8528
def test_bip85_24word(self):
86-
"""Derive a 24-word child mnemonic at index 0."""
29+
"""Derive a 24-word child mnemonic at index 0 — device displays, returns Success."""
8730
self.requires_firmware("7.14.0")
8831
self.setup_mnemonic_allallall()
8932

9033
resp = self.client.call(proto.GetBip85Mnemonic(word_count=24, index=0))
9134

9235
self.assertTrue(
93-
isinstance(resp, proto.Bip85Mnemonic),
94-
"Expected Bip85Mnemonic response, got %s" % type(resp).__name__
95-
)
96-
97-
mnemonic = resp.mnemonic
98-
words = mnemonic.split()
99-
100-
# Must have exactly 24 words
101-
self.assertTrue(
102-
len(words) == 24,
103-
"Expected 24 words, got %d: %s" % (len(words), mnemonic)
104-
)
105-
106-
# Each word must be a valid BIP-39 word
107-
is_valid, bad_words = _validate_mnemonic_words(mnemonic)
108-
self.assertTrue(
109-
is_valid,
110-
"Invalid BIP-39 words found: %s" % bad_words
36+
isinstance(resp, proto.Success),
37+
"Expected Success response, got %s" % type(resp).__name__
11138
)
11239

11340
def test_bip85_different_indices(self):
114-
"""Index 0 and index 1 must produce different child mnemonics."""
41+
"""Index 0 and index 1 both succeed (different seeds displayed on device)."""
11542
self.requires_firmware("7.14.0")
11643
self.setup_mnemonic_allallall()
11744

11845
resp0 = self.client.call(proto.GetBip85Mnemonic(word_count=12, index=0))
11946
resp1 = self.client.call(proto.GetBip85Mnemonic(word_count=12, index=1))
12047

12148
self.assertTrue(
122-
isinstance(resp0, proto.Bip85Mnemonic),
123-
"Expected Bip85Mnemonic for index 0, got %s" % type(resp0).__name__
49+
isinstance(resp0, proto.Success),
50+
"Expected Success for index 0, got %s" % type(resp0).__name__
12451
)
12552
self.assertTrue(
126-
isinstance(resp1, proto.Bip85Mnemonic),
127-
"Expected Bip85Mnemonic for index 1, got %s" % type(resp1).__name__
128-
)
129-
130-
# Different indices must yield different mnemonics
131-
self.assertTrue(
132-
resp0.mnemonic != resp1.mnemonic,
133-
"Index 0 and index 1 produced identical mnemonics: %s" % resp0.mnemonic
53+
isinstance(resp1, proto.Success),
54+
"Expected Success for index 1, got %s" % type(resp1).__name__
13455
)
13556

13657
def test_bip85_deterministic(self):
137-
"""Same parameters must produce the same child mnemonic every time."""
58+
"""Same parameters succeed consistently (determinism verified by device display)."""
13859
self.requires_firmware("7.14.0")
13960
self.setup_mnemonic_allallall()
14061

14162
resp1 = self.client.call(proto.GetBip85Mnemonic(word_count=12, index=0))
14263
resp2 = self.client.call(proto.GetBip85Mnemonic(word_count=12, index=0))
14364

14465
self.assertTrue(
145-
isinstance(resp1, proto.Bip85Mnemonic),
146-
"Expected Bip85Mnemonic (call 1), got %s" % type(resp1).__name__
66+
isinstance(resp1, proto.Success),
67+
"Expected Success (call 1), got %s" % type(resp1).__name__
14768
)
14869
self.assertTrue(
149-
isinstance(resp2, proto.Bip85Mnemonic),
150-
"Expected Bip85Mnemonic (call 2), got %s" % type(resp2).__name__
151-
)
152-
153-
self.assertTrue(
154-
resp1.mnemonic == resp2.mnemonic,
155-
"Determinism violated: '%s' != '%s'" % (resp1.mnemonic, resp2.mnemonic)
70+
isinstance(resp2, proto.Success),
71+
"Expected Success (call 2), got %s" % type(resp2).__name__
15672
)
15773

15874

tests/test_msg_ethereum_cfunc.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def test_sign_execTx(self):
3535
self.requires_fullFeature()
3636
self.requires_firmware("7.5.2")
3737
self.setup_mnemonic_nopin_nopassphrase()
38+
self.client.apply_policy("AdvancedMode", 1)
3839

3940
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
4041
n=[2147483692,2147483708,2147483648,0,0],

tests/test_msg_ethereum_erc20_0x_signtx.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ def test_sign_longdata_swap(self):
9898
self.requires_fullFeature()
9999
self.requires_firmware("7.0.2")
100100
self.setup_mnemonic_nopin_nopassphrase()
101+
self.client.apply_policy("AdvancedMode", 1)
101102

102103
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
103104
n=[2147483692,2147483708,2147483648,0,0],

tests/test_msg_ethereum_signtx.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class TestMsgEthereumSigntx(common.KeepKeyTest):
3333
def test_ethereum_signtx_data(self):
3434
self.requires_fullFeature()
3535
self.setup_mnemonic_nopin_nopassphrase()
36-
self.client.apply_policy("AdvancedMode", 0)
36+
self.client.apply_policy("AdvancedMode", 1)
3737

3838
with self.client:
3939
self.client.set_expected_responses(
@@ -441,6 +441,7 @@ def test_ethereum_signtx_data1_eip_1559(self):
441441
self.requires_fullFeature()
442442
self.requires_firmware("7.2.1")
443443
self.setup_mnemonic_allallall()
444+
self.client.apply_policy("AdvancedMode", 1)
444445

445446
# from trezor test vector:
446447
# https://github.com/trezor/trezor-firmware/blob/master/common/tests/fixtures/ethereum/sign_tx_eip1559.json#L27

0 commit comments

Comments
 (0)