mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-01 11:58:28 +00:00
fixup! feat(core)): forbid multisig to singlesig change outputs
This commit is contained in:
parent
c5200261fb
commit
b7d26c794b
@ -17,15 +17,11 @@ _BIP32_MAX_LAST_ELEMENT = const(1_000_000)
|
|||||||
class ChangeDetector:
|
class ChangeDetector:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
from .matchcheck import (
|
from .matchcheck import (
|
||||||
MultisigChecker,
|
|
||||||
MultisigFingerprintChecker,
|
MultisigFingerprintChecker,
|
||||||
ScriptTypeChecker,
|
ScriptTypeChecker,
|
||||||
WalletPathChecker,
|
WalletPathChecker,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Whether all inputs are multisig or all inputs are singlesig, used to validate change-output.
|
|
||||||
self.multisig = MultisigChecker()
|
|
||||||
|
|
||||||
# Checksum of multisig inputs, used to validate change-output.
|
# Checksum of multisig inputs, used to validate change-output.
|
||||||
self.multisig_fingerprint = MultisigFingerprintChecker()
|
self.multisig_fingerprint = MultisigFingerprintChecker()
|
||||||
|
|
||||||
@ -40,37 +36,30 @@ class ChangeDetector:
|
|||||||
self.wallet_path.add_input(txi)
|
self.wallet_path.add_input(txi)
|
||||||
self.script_type.add_input(txi)
|
self.script_type.add_input(txi)
|
||||||
self.multisig_fingerprint.add_input(txi)
|
self.multisig_fingerprint.add_input(txi)
|
||||||
self.multisig.add_input(txi)
|
|
||||||
|
|
||||||
def check_input(self, txi: TxInput) -> None:
|
def check_input(self, txi: TxInput) -> None:
|
||||||
self.wallet_path.check_input(txi)
|
self.wallet_path.check_input(txi)
|
||||||
self.script_type.check_input(txi)
|
self.script_type.check_input(txi)
|
||||||
self.multisig_fingerprint.check_input(txi)
|
self.multisig_fingerprint.check_input(txi)
|
||||||
self.multisig.check_input(txi)
|
|
||||||
|
|
||||||
def output_is_change(self, txo: TxOutput) -> bool:
|
def output_is_change(self, txo: TxOutput) -> bool:
|
||||||
if txo.script_type not in common.CHANGE_OUTPUT_SCRIPT_TYPES:
|
if txo.script_type not in common.CHANGE_OUTPUT_SCRIPT_TYPES:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if txo.multisig:
|
if txo.multisig and not common.multisig_uses_single_path(txo.multisig):
|
||||||
if not (
|
# An address that uses different derivation paths for different xpubs
|
||||||
self.multisig_fingerprint.output_matches(txo)
|
# could be difficult to discover if the user did not note all the paths.
|
||||||
and common.multisig_uses_single_path(
|
# The reason is that each path ends with an address index, which can
|
||||||
txo.multisig
|
# have 1,000,000 possible values. If the address is a t-out-of-n
|
||||||
) # An address that uses different derivation paths for different xpubs
|
# multisig, the total number of possible paths is 1,000,000^n. This can
|
||||||
# could be difficult to discover if the user did not note all the paths.
|
# be exploited by an attacker who has compromised the user's computer.
|
||||||
# The reason is that each path ends with an address index, which can
|
# The attacker could randomize the address indices and then demand a
|
||||||
# have 1,000,000 possible values. If the address is a t-out-of-n
|
# ransom from the user to reveal the paths. To prevent this, we require
|
||||||
# multisig, the total number of possible paths is 1,000,000^n. This can
|
# that all xpubs use the same derivation path.
|
||||||
# be exploited by an attacker who has compromised the user's computer.
|
return False
|
||||||
# The attacker could randomize the address indices and then demand a
|
|
||||||
# ransom from the user to reveal the paths. To prevent this, we require
|
|
||||||
# that all xpubs use the same derivation path.
|
|
||||||
):
|
|
||||||
return False
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
self.multisig.output_matches(txo)
|
self.multisig_fingerprint.output_matches(txo)
|
||||||
and self.wallet_path.output_matches(txo)
|
and self.wallet_path.output_matches(txo)
|
||||||
and self.script_type.output_matches(txo)
|
and self.script_type.output_matches(txo)
|
||||||
and len(txo.address_n) >= common.BIP32_WALLET_DEPTH
|
and len(txo.address_n) >= common.BIP32_WALLET_DEPTH
|
||||||
|
@ -103,15 +103,14 @@ class MultisigFingerprintChecker(MatchChecker):
|
|||||||
from .. import multisig
|
from .. import multisig
|
||||||
|
|
||||||
if not txio.multisig:
|
if not txio.multisig:
|
||||||
return None
|
# The fingerprint of a singlesig input or output is defined as an empty byte string.
|
||||||
|
# This has two consequences: First, a singlesig output matches if and only if all
|
||||||
|
# the added inputs are singlesig. Second, a multisig output does not match if any of
|
||||||
|
# the added inputs is singlesig.
|
||||||
|
return bytes()
|
||||||
return multisig.multisig_fingerprint(txio.multisig)
|
return multisig.multisig_fingerprint(txio.multisig)
|
||||||
|
|
||||||
|
|
||||||
class MultisigChecker(MatchChecker):
|
|
||||||
def attribute_from_tx(self, txio: TxInput | TxOutput) -> Any:
|
|
||||||
return txio.multisig is not None
|
|
||||||
|
|
||||||
|
|
||||||
class ScriptTypeChecker(MatchChecker):
|
class ScriptTypeChecker(MatchChecker):
|
||||||
def attribute_from_tx(self, txio: TxInput | TxOutput) -> Any:
|
def attribute_from_tx(self, txio: TxInput | TxOutput) -> Any:
|
||||||
from trezor.enums import InputScriptType
|
from trezor.enums import InputScriptType
|
||||||
|
Loading…
Reference in New Issue
Block a user