Skip to content

Commit c75fbd5

Browse files
committed
Merge remote-tracking branch 'origin/master' into test/onscreen-signed-content-disclosure
2 parents 709d3fd + 604cfc0 commit c75fbd5

23 files changed

Lines changed: 2327 additions & 83 deletions

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[submodule "device-protocol"]
22
path = device-protocol
3-
url = https://github.com/keepkey/device-protocol.git
3+
url = https://github.com/BitHighlander/device-protocol.git
44
branch = master
55
[submodule "keepkeylib/eth/ethereum-lists"]
66
path = keepkeylib/eth/ethereum-lists

keepkeylib/client.py

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
from . import messages_tron_pb2 as tron_proto
5050
from . import messages_ton_pb2 as ton_proto
5151
from . import messages_zcash_pb2 as zcash_proto
52+
from . import messages_hive_pb2 as hive_proto
5253
from . import types_pb2 as types
5354
from . import eos
5455
from . import nano
@@ -1724,10 +1725,28 @@ def ton_sign_message(self, address_n, message, show_display=False):
17241725

17251726
# ── Zcash Address Display ─────────────────────────────────
17261727
@expect(zcash_proto.ZcashAddress)
1727-
def zcash_display_address(self, address_n, address, ak, nk, rivk, account=None):
1728+
def zcash_display_address(self, address_n, address, ak, nk, rivk,
1729+
account=None, expected_seed_fingerprint=None):
1730+
"""Display a Zcash unified address on the device for user confirmation.
1731+
1732+
Args:
1733+
address_n: ZIP-32 derivation path [32', 133', account']
1734+
address: unified address string ("u1...")
1735+
ak, nk, rivk: 32-byte FVK components for verification
1736+
account: account index (alternative to full path)
1737+
expected_seed_fingerprint: optional 32-byte ZIP-32 §6.1 seed
1738+
fingerprint. If provided, device verifies the match before
1739+
displaying and rejects with Failure on mismatch.
1740+
1741+
Returns:
1742+
ZcashAddress with .address and .seed_fingerprint of the
1743+
attesting device.
1744+
"""
17281745
kwargs = dict(address_n=address_n, address=address, ak=ak, nk=nk, rivk=rivk)
17291746
if account is not None:
17301747
kwargs['account'] = account
1748+
if expected_seed_fingerprint is not None:
1749+
kwargs['expected_seed_fingerprint'] = expected_seed_fingerprint
17311750
return self.call(zcash_proto.ZcashDisplayAddress(**kwargs))
17321751

17331752
# ── Zcash Orchard ──────────────────────────────────────────
@@ -1744,7 +1763,8 @@ def zcash_sign_pczt(self, address_n, actions, account=None,
17441763
header_digest=None, transparent_digest=None,
17451764
sapling_digest=None, orchard_digest=None,
17461765
orchard_flags=None, orchard_value_balance=None,
1747-
orchard_anchor=None, transparent_inputs=None):
1766+
orchard_anchor=None, transparent_inputs=None,
1767+
expected_seed_fingerprint=None):
17481768
"""Sign a Zcash Orchard shielded transaction via PCZT protocol.
17491769
17501770
Phase 2: Sends ZcashSignPCZT, then loops on ZcashPCZTActionAck
@@ -1800,6 +1820,8 @@ def zcash_sign_pczt(self, address_n, actions, account=None,
18001820
kwargs['orchard_value_balance'] = orchard_value_balance
18011821
if orchard_anchor is not None:
18021822
kwargs['orchard_anchor'] = orchard_anchor
1823+
if expected_seed_fingerprint is not None:
1824+
kwargs['expected_seed_fingerprint'] = expected_seed_fingerprint
18031825

18041826
resp = self.call(zcash_proto.ZcashSignPCZT(**kwargs))
18051827

@@ -1836,6 +1858,74 @@ def zcash_sign_pczt(self, address_n, actions, account=None,
18361858

18371859
return resp
18381860

1861+
# ── Hive ────────────────────────────────────────────────────
1862+
@expect(hive_proto.HivePublicKey)
1863+
def hive_get_public_key(self, address_n, show_display=False, role=None):
1864+
kwargs = dict(address_n=address_n, show_display=show_display)
1865+
if role is not None:
1866+
kwargs['role'] = role
1867+
return self.call(hive_proto.HiveGetPublicKey(**kwargs))
1868+
1869+
@expect(hive_proto.HivePublicKeys)
1870+
def hive_get_public_keys(self, account_index=0, show_display=False):
1871+
return self.call(
1872+
hive_proto.HiveGetPublicKeys(account_index=account_index, show_display=show_display)
1873+
)
1874+
1875+
@expect(hive_proto.HiveSignedTx)
1876+
def hive_sign_tx(self, address_n, chain_id, ref_block_num, ref_block_prefix,
1877+
expiration, sender, recipient, amount, decimals, asset_symbol, memo=''):
1878+
return self.call(hive_proto.HiveSignTx(**{
1879+
'address_n': address_n,
1880+
'chain_id': chain_id,
1881+
'ref_block_num': ref_block_num,
1882+
'ref_block_prefix': ref_block_prefix,
1883+
'expiration': expiration,
1884+
'from': sender,
1885+
'to': recipient,
1886+
'amount': amount,
1887+
'decimals': decimals,
1888+
'asset_symbol': asset_symbol,
1889+
'memo': memo,
1890+
}))
1891+
1892+
@expect(hive_proto.HiveSignedAccountCreate)
1893+
def hive_sign_account_create(self, address_n, chain_id, ref_block_num, ref_block_prefix,
1894+
expiration, creator, new_account_name, fee_amount=3000,
1895+
owner_key='', active_key='', posting_key='', memo_key=''):
1896+
return self.call(hive_proto.HiveSignAccountCreate(
1897+
address_n=address_n,
1898+
chain_id=chain_id,
1899+
ref_block_num=ref_block_num,
1900+
ref_block_prefix=ref_block_prefix,
1901+
expiration=expiration,
1902+
creator=creator,
1903+
new_account_name=new_account_name,
1904+
fee_amount=fee_amount,
1905+
owner_key=owner_key,
1906+
active_key=active_key,
1907+
posting_key=posting_key,
1908+
memo_key=memo_key,
1909+
))
1910+
1911+
@expect(hive_proto.HiveSignedAccountUpdate)
1912+
def hive_sign_account_update(self, address_n, chain_id, ref_block_num, ref_block_prefix,
1913+
expiration, account,
1914+
new_owner_key='', new_active_key='',
1915+
new_posting_key='', new_memo_key=''):
1916+
return self.call(hive_proto.HiveSignAccountUpdate(
1917+
address_n=address_n,
1918+
chain_id=chain_id,
1919+
ref_block_num=ref_block_num,
1920+
ref_block_prefix=ref_block_prefix,
1921+
expiration=expiration,
1922+
account=account,
1923+
new_owner_key=new_owner_key,
1924+
new_active_key=new_active_key,
1925+
new_posting_key=new_posting_key,
1926+
new_memo_key=new_memo_key,
1927+
))
1928+
18391929
class KeepKeyClient(ProtocolMixin, TextUIMixin, BaseClient):
18401930
pass
18411931

keepkeylib/hive.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from . import messages_hive_pb2 as proto
2+
3+
4+
def get_public_key(client, address_n, show_display=False, role=None):
5+
kwargs = dict(address_n=address_n, show_display=show_display)
6+
if role is not None:
7+
kwargs['role'] = role
8+
return client.call(proto.HiveGetPublicKey(**kwargs))
9+
10+
11+
def get_public_keys(client, account_index=0, show_display=False):
12+
return client.call(
13+
proto.HiveGetPublicKeys(account_index=account_index, show_display=show_display)
14+
)
15+
16+
17+
def sign_tx(client, address_n, chain_id, ref_block_num, ref_block_prefix,
18+
expiration, sender, recipient, amount, decimals, asset_symbol, memo=''):
19+
# 'from' is a Python keyword so use **-unpacking to set the field
20+
return client.call(proto.HiveSignTx(**{
21+
'address_n': address_n,
22+
'chain_id': chain_id,
23+
'ref_block_num': ref_block_num,
24+
'ref_block_prefix': ref_block_prefix,
25+
'expiration': expiration,
26+
'from': sender,
27+
'to': recipient,
28+
'amount': amount,
29+
'decimals': decimals,
30+
'asset_symbol': asset_symbol,
31+
'memo': memo,
32+
}))
33+
34+
35+
def sign_account_create(client, address_n, chain_id, ref_block_num, ref_block_prefix,
36+
expiration, creator, new_account_name, fee_amount=3000,
37+
owner_key='', active_key='', posting_key='', memo_key=''):
38+
return client.call(proto.HiveSignAccountCreate(
39+
address_n=address_n,
40+
chain_id=chain_id,
41+
ref_block_num=ref_block_num,
42+
ref_block_prefix=ref_block_prefix,
43+
expiration=expiration,
44+
creator=creator,
45+
new_account_name=new_account_name,
46+
fee_amount=fee_amount,
47+
owner_key=owner_key,
48+
active_key=active_key,
49+
posting_key=posting_key,
50+
memo_key=memo_key,
51+
))
52+
53+
54+
def sign_account_update(client, address_n, chain_id, ref_block_num, ref_block_prefix,
55+
expiration, account,
56+
new_owner_key='', new_active_key='',
57+
new_posting_key='', new_memo_key=''):
58+
return client.call(proto.HiveSignAccountUpdate(
59+
address_n=address_n,
60+
chain_id=chain_id,
61+
ref_block_num=ref_block_num,
62+
ref_block_prefix=ref_block_prefix,
63+
expiration=expiration,
64+
account=account,
65+
new_owner_key=new_owner_key,
66+
new_active_key=new_active_key,
67+
new_posting_key=new_posting_key,
68+
new_memo_key=new_memo_key,
69+
))

keepkeylib/mapping.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from . import messages_tron_pb2 as tron_proto
1414
from . import messages_ton_pb2 as ton_proto
1515
from . import messages_zcash_pb2 as zcash_proto
16+
from . import messages_hive_pb2 as hive_proto
1617

1718
map_type_to_class = {}
1819
map_class_to_type = {}
@@ -97,4 +98,23 @@ def check_missing():
9798
map_type_to_class[wire_id] = msg_class
9899
map_class_to_type[msg_class] = wire_id
99100

100-
# check_missing() — skip: Zcash types are not in old messages_pb2 enum
101+
# Manually register Hive messages (not in the old messages_pb2.py enum)
102+
_hive_wire_ids = {
103+
1600: ('HiveGetPublicKey', hive_proto),
104+
1601: ('HivePublicKey', hive_proto),
105+
1602: ('HiveSignTx', hive_proto),
106+
1603: ('HiveSignedTx', hive_proto),
107+
1604: ('HiveGetPublicKeys', hive_proto),
108+
1605: ('HivePublicKeys', hive_proto),
109+
1606: ('HiveSignAccountCreate', hive_proto),
110+
1607: ('HiveSignedAccountCreate', hive_proto),
111+
1608: ('HiveSignAccountUpdate', hive_proto),
112+
1609: ('HiveSignedAccountUpdate', hive_proto),
113+
}
114+
for wire_id, (msg_name, mod) in _hive_wire_ids.items():
115+
msg_class = getattr(mod, msg_name, None)
116+
if msg_class is not None:
117+
map_type_to_class[wire_id] = msg_class
118+
map_class_to_type[msg_class] = wire_id
119+
120+
# check_missing() — skip: Zcash/Hive types are not in old messages_pb2 enum

0 commit comments

Comments
 (0)