parent
a07e125793
commit
be7e98aa47
@ -0,0 +1,12 @@
|
|||||||
|
from trezor.crypto import bip32, der
|
||||||
|
from trezor.crypto.curve import secp256k1
|
||||||
|
|
||||||
|
|
||||||
|
class SigningError(ValueError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def ecdsa_sign(node: bip32.HDNode, digest: bytes) -> bytes:
|
||||||
|
sig = secp256k1.sign(node.private_key(), digest)
|
||||||
|
sigder = der.encode_seq((sig[1:33], sig[33:65]))
|
||||||
|
return sigder
|
@ -0,0 +1,85 @@
|
|||||||
|
from micropython import const
|
||||||
|
|
||||||
|
from trezor.messages import FailureType
|
||||||
|
from trezor.messages.TxInputType import TxInputType
|
||||||
|
from trezor.messages.TxOutputType import TxOutputType
|
||||||
|
from trezor.utils import ensure
|
||||||
|
|
||||||
|
from apps.wallet.sign_tx import multisig
|
||||||
|
from apps.wallet.sign_tx.common import SigningError
|
||||||
|
|
||||||
|
if False:
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
# the number of bip32 levels used in a wallet (chain and address)
|
||||||
|
_BIP32_WALLET_DEPTH = const(2)
|
||||||
|
|
||||||
|
|
||||||
|
class MatchChecker:
|
||||||
|
"""
|
||||||
|
MatchCheckers are used to identify the change-output in a transaction. An output is a change-output
|
||||||
|
if it has certain matching attributes with all inputs.
|
||||||
|
1. When inputs are first processed, add_input() is called on each one to determine if they all match.
|
||||||
|
2. Outputs are tested using output_matches() to tell whether they are admissible as a change-output.
|
||||||
|
3. Before signing each input, check_input() is used to ensure that the attribute has not changed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
MISMATCH = object()
|
||||||
|
UNDEFINED = object()
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.attribute = self.UNDEFINED # type: object
|
||||||
|
self.read_only = False # Failsafe to ensure that add_input() is not accidentally called after output_matches().
|
||||||
|
|
||||||
|
def attribute_from_tx(self, txio: Union[TxInputType, TxOutputType]) -> object:
|
||||||
|
# Return the attribute from the txio, which is to be used for matching.
|
||||||
|
# If the txio is invalid for matching, then return an object which
|
||||||
|
# evaluates as a boolean False.
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def add_input(self, txi: TxInputType) -> None:
|
||||||
|
ensure(not self.read_only)
|
||||||
|
|
||||||
|
if self.attribute is self.MISMATCH:
|
||||||
|
return # There was a mismatch in previous inputs.
|
||||||
|
|
||||||
|
added_attribute = self.attribute_from_tx(txi)
|
||||||
|
if not added_attribute:
|
||||||
|
self.attribute = self.MISMATCH # The added input is invalid for matching.
|
||||||
|
elif self.attribute is self.UNDEFINED:
|
||||||
|
self.attribute = added_attribute # This is the first input.
|
||||||
|
elif self.attribute != added_attribute:
|
||||||
|
self.attribute = self.MISMATCH
|
||||||
|
|
||||||
|
def check_input(self, txi: TxInputType) -> None:
|
||||||
|
if self.attribute is self.MISMATCH:
|
||||||
|
return # There was already a mismatch when adding inputs, ignore it now.
|
||||||
|
|
||||||
|
# All added inputs had a matching attribute, allowing a change-output.
|
||||||
|
# Ensure that this input still has the same attribute.
|
||||||
|
if self.attribute != self.attribute_from_tx(txi):
|
||||||
|
raise SigningError(
|
||||||
|
FailureType.ProcessError, "Transaction has changed during signing"
|
||||||
|
)
|
||||||
|
|
||||||
|
def output_matches(self, txo: TxOutputType) -> bool:
|
||||||
|
self.read_only = True
|
||||||
|
|
||||||
|
if self.attribute is self.MISMATCH:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return self.attribute_from_tx(txo) == self.attribute
|
||||||
|
|
||||||
|
|
||||||
|
class WalletPathChecker(MatchChecker):
|
||||||
|
def attribute_from_tx(self, txio: Union[TxInputType, TxOutputType]) -> object:
|
||||||
|
if not txio.address_n:
|
||||||
|
return None
|
||||||
|
return txio.address_n[:-_BIP32_WALLET_DEPTH]
|
||||||
|
|
||||||
|
|
||||||
|
class MultisigFingerprintChecker(MatchChecker):
|
||||||
|
def attribute_from_tx(self, txio: Union[TxInputType, TxOutputType]) -> object:
|
||||||
|
if not txio.multisig:
|
||||||
|
return None
|
||||||
|
return multisig.multisig_fingerprint(txio.multisig)
|
Loading…
Reference in new issue