1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-13 19:18:56 +00:00
trezor-firmware/src/apps/wallet/sign_tx/multisig.py

108 lines
3.4 KiB
Python
Raw Normal View History

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
2018-02-27 11:58:37 +00:00
from trezor.messages import FailureType
2018-07-03 14:20:26 +00:00
from trezor.messages.HDNodePathType import HDNodePathType
from trezor.messages.HDNodeType import HDNodeType
2018-07-03 14:20:26 +00:00
from trezor.messages.MultisigRedeemScriptType import MultisigRedeemScriptType
from trezor.utils import HashWriter, ensure
2018-01-29 13:41:56 +00:00
2018-06-05 18:21:31 +00:00
from apps.wallet.sign_tx.writers import write_bytes, write_uint32
2018-02-27 11:58:37 +00:00
class MultisigError(ValueError):
pass
2018-02-23 18:55:28 +00:00
class MultisigFingerprint:
def __init__(self):
self.fingerprint = None # multisig fingerprint bytes
self.mismatch = False # flag if multisig input fingerprints are equal
def add(self, multisig: MultisigRedeemScriptType):
fp = multisig_fingerprint(multisig)
ensure(fp is not None)
2018-02-23 18:55:28 +00:00
if self.fingerprint is None:
self.fingerprint = fp
elif self.fingerprint != fp:
self.mismatch = True
def matches(self, multisig: MultisigRedeemScriptType):
fp = multisig_fingerprint(multisig)
ensure(fp is not None)
2018-02-23 18:55:28 +00:00
if self.mismatch is False and self.fingerprint == fp:
return True
else:
return False
def multisig_fingerprint(multisig: MultisigRedeemScriptType) -> bytes:
if multisig.nodes:
pubnodes = multisig.nodes
else:
pubnodes = [hd.node for hd in multisig.pubkeys]
m = multisig.m
n = len(pubnodes)
2018-02-23 18:55:28 +00:00
if n < 1 or n > 15 or m < 1 or m > 15:
2018-07-03 14:20:58 +00:00
raise MultisigError(FailureType.DataError, "Invalid multisig parameters")
for d in pubnodes:
2018-02-23 18:55:28 +00:00
if len(d.public_key) != 33 or len(d.chain_code) != 32:
2018-07-03 14:20:58 +00:00
raise MultisigError(FailureType.DataError, "Invalid multisig parameters")
# casting to bytes(), sorting on bytearray() is not supported in MicroPython
pubnodes = sorted(pubnodes, key=lambda n: bytes(n.public_key))
2018-10-30 14:48:26 +00:00
h = HashWriter(sha256())
write_uint32(h, m)
write_uint32(h, n)
for d in pubnodes:
write_uint32(h, d.depth)
write_uint32(h, d.fingerprint)
write_uint32(h, d.child_num)
write_bytes(h, d.chain_code)
write_bytes(h, d.public_key)
return h.get_digest()
2018-01-29 13:41:56 +00:00
def multisig_pubkey_index(multisig: MultisigRedeemScriptType, pubkey: bytes) -> int:
if multisig.nodes:
for i, hd in enumerate(multisig.nodes):
if multisig_get_pubkey(hd, multisig.address_n) == pubkey:
return i
else:
for i, hd in enumerate(multisig.pubkeys):
if multisig_get_pubkey(hd.node, hd.address_n) == pubkey:
return i
2018-07-03 14:20:58 +00:00
raise MultisigError(FailureType.DataError, "Pubkey not found in multisig script")
def multisig_get_pubkey(n: HDNodeType, p: list) -> 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()
def multisig_get_pubkeys(multisig: MultisigRedeemScriptType):
if multisig.nodes:
return [
multisig_get_pubkey(hd, multisig.address_n) for hd in multisig.nodes
]
else:
return [multisig_get_pubkey(hd.node, hd.address_n) for hd in multisig.pubkeys]
def multisig_get_pubkey_count(multisig: MultisigRedeemScriptType):
if multisig.nodes:
return len(multisig.nodes)
else:
len(multisig.pubkeys)