2020-05-15 18:35:09 +00:00
|
|
|
from trezor import wire
|
2018-01-29 13:41:56 +00:00
|
|
|
from trezor.crypto import bip32
|
2018-07-03 14:20:26 +00:00
|
|
|
from trezor.crypto.hashlib import sha256
|
2019-02-04 00:15:13 +00:00
|
|
|
from trezor.messages.HDNodeType import HDNodeType
|
2018-07-03 14:20:26 +00:00
|
|
|
from trezor.messages.MultisigRedeemScriptType import MultisigRedeemScriptType
|
2020-04-15 15:16:20 +00:00
|
|
|
from trezor.utils import HashWriter
|
2018-01-29 13:41:56 +00:00
|
|
|
|
2020-07-23 11:58:19 +00:00
|
|
|
from apps.common import paths
|
|
|
|
|
2020-05-15 18:35:09 +00:00
|
|
|
from .writers import write_bytes_fixed, write_uint32
|
2018-02-08 12:14:36 +00:00
|
|
|
|
2020-04-07 07:39:11 +00:00
|
|
|
if False:
|
2020-04-15 15:16:20 +00:00
|
|
|
from typing import List
|
2020-04-07 07:39:11 +00:00
|
|
|
|
2018-02-08 12:14:36 +00:00
|
|
|
|
|
|
|
def multisig_fingerprint(multisig: MultisigRedeemScriptType) -> bytes:
|
2019-02-04 00:15:13 +00:00
|
|
|
if multisig.nodes:
|
|
|
|
pubnodes = multisig.nodes
|
|
|
|
else:
|
|
|
|
pubnodes = [hd.node for hd in multisig.pubkeys]
|
2018-02-08 12:14:36 +00:00
|
|
|
m = multisig.m
|
2019-02-04 00:15:13 +00:00
|
|
|
n = len(pubnodes)
|
2018-02-08 12:14:36 +00:00
|
|
|
|
2018-02-23 18:55:28 +00:00
|
|
|
if n < 1 or n > 15 or m < 1 or m > 15:
|
2020-05-15 18:35:09 +00:00
|
|
|
raise wire.DataError("Invalid multisig parameters")
|
2018-02-08 12:14:36 +00:00
|
|
|
|
2019-02-04 00:15:13 +00:00
|
|
|
for d in pubnodes:
|
2018-02-23 18:55:28 +00:00
|
|
|
if len(d.public_key) != 33 or len(d.chain_code) != 32:
|
2020-05-15 18:35:09 +00:00
|
|
|
raise wire.DataError("Invalid multisig parameters")
|
2018-02-08 12:14:36 +00:00
|
|
|
|
|
|
|
# casting to bytes(), sorting on bytearray() is not supported in MicroPython
|
2019-02-04 00:15:13 +00:00
|
|
|
pubnodes = sorted(pubnodes, key=lambda n: bytes(n.public_key))
|
2018-02-08 12:14:36 +00:00
|
|
|
|
2018-10-30 14:48:26 +00:00
|
|
|
h = HashWriter(sha256())
|
2018-02-08 12:14:36 +00:00
|
|
|
write_uint32(h, m)
|
|
|
|
write_uint32(h, n)
|
2019-02-04 00:15:13 +00:00
|
|
|
for d in pubnodes:
|
2018-02-08 12:14:36 +00:00
|
|
|
write_uint32(h, d.depth)
|
|
|
|
write_uint32(h, d.fingerprint)
|
|
|
|
write_uint32(h, d.child_num)
|
2020-03-16 11:42:19 +00:00
|
|
|
write_bytes_fixed(h, d.chain_code, 32)
|
|
|
|
write_bytes_fixed(h, d.public_key, 33)
|
2018-02-08 12:14:36 +00:00
|
|
|
|
|
|
|
return h.get_digest()
|
2018-01-29 13:41:56 +00:00
|
|
|
|
|
|
|
|
2020-07-23 11:58:19 +00:00
|
|
|
def validate_multisig(multisig: MultisigRedeemScriptType) -> None:
|
|
|
|
if any(paths.is_hardened(n) for n in multisig.address_n):
|
|
|
|
raise wire.DataError("Cannot perform hardened derivation from XPUB")
|
|
|
|
for hd in multisig.pubkeys:
|
|
|
|
if any(paths.is_hardened(n) for n in hd.address_n):
|
|
|
|
raise wire.DataError("Cannot perform hardened derivation from XPUB")
|
|
|
|
|
|
|
|
|
2018-01-31 11:48:18 +00:00
|
|
|
def multisig_pubkey_index(multisig: MultisigRedeemScriptType, pubkey: bytes) -> int:
|
2020-07-23 11:58:19 +00:00
|
|
|
validate_multisig(multisig)
|
2019-02-04 00:15:13 +00:00
|
|
|
if multisig.nodes:
|
2020-04-08 15:37:40 +00:00
|
|
|
for i, hd_node in enumerate(multisig.nodes):
|
|
|
|
if multisig_get_pubkey(hd_node, multisig.address_n) == pubkey:
|
2019-02-04 00:15:13 +00:00
|
|
|
return i
|
|
|
|
else:
|
|
|
|
for i, hd in enumerate(multisig.pubkeys):
|
|
|
|
if multisig_get_pubkey(hd.node, hd.address_n) == pubkey:
|
|
|
|
return i
|
2020-05-15 18:35:09 +00:00
|
|
|
raise wire.DataError("Pubkey not found in multisig script")
|
2018-01-31 11:48:18 +00:00
|
|
|
|
|
|
|
|
2020-07-23 11:58:19 +00:00
|
|
|
def multisig_get_pubkey(n: HDNodeType, p: paths.Bip32Path) -> bytes:
|
2018-01-29 13:41:56 +00:00
|
|
|
node = bip32.HDNode(
|
|
|
|
depth=n.depth,
|
|
|
|
fingerprint=n.fingerprint,
|
|
|
|
child_num=n.child_num,
|
|
|
|
chain_code=n.chain_code,
|
2018-07-03 14:20:58 +00:00
|
|
|
public_key=n.public_key,
|
|
|
|
)
|
2018-01-29 13:41:56 +00:00
|
|
|
for i in p:
|
|
|
|
node.derive(i, True)
|
|
|
|
return node.public_key()
|
|
|
|
|
|
|
|
|
2020-04-07 07:39:11 +00:00
|
|
|
def multisig_get_pubkeys(multisig: MultisigRedeemScriptType) -> List[bytes]:
|
2020-07-23 11:58:19 +00:00
|
|
|
validate_multisig(multisig)
|
2019-02-04 00:15:13 +00:00
|
|
|
if multisig.nodes:
|
2019-02-04 00:51:56 +00:00
|
|
|
return [multisig_get_pubkey(hd, multisig.address_n) for hd in multisig.nodes]
|
2019-02-04 00:15:13 +00:00
|
|
|
else:
|
|
|
|
return [multisig_get_pubkey(hd.node, hd.address_n) for hd in multisig.pubkeys]
|
|
|
|
|
|
|
|
|
2020-04-07 07:39:11 +00:00
|
|
|
def multisig_get_pubkey_count(multisig: MultisigRedeemScriptType) -> int:
|
2019-02-04 00:15:13 +00:00
|
|
|
if multisig.nodes:
|
|
|
|
return len(multisig.nodes)
|
|
|
|
else:
|
2019-02-04 12:57:31 +00:00
|
|
|
return len(multisig.pubkeys)
|