mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-18 12:28:09 +00:00
core/bitcoin: Implement parsing of scripts and witnesses for signature verification.
This commit is contained in:
parent
173bb7ed13
commit
d1e043f417
@ -7,6 +7,7 @@ from trezor.messages.TxInputType import TxInputType
|
|||||||
|
|
||||||
from apps.common import address_type
|
from apps.common import address_type
|
||||||
from apps.common.coininfo import CoinInfo
|
from apps.common.coininfo import CoinInfo
|
||||||
|
from apps.common.readers import BytearrayReader, read_bitcoin_varint
|
||||||
from apps.common.writers import empty_bytearray, write_bitcoin_varint
|
from apps.common.writers import empty_bytearray, write_bitcoin_varint
|
||||||
|
|
||||||
from . import common
|
from . import common
|
||||||
@ -15,6 +16,7 @@ from .multisig import (
|
|||||||
multisig_get_pubkeys,
|
multisig_get_pubkeys,
|
||||||
multisig_pubkey_index,
|
multisig_pubkey_index,
|
||||||
)
|
)
|
||||||
|
from .readers import read_bytes_prefixed, read_op_push
|
||||||
from .writers import (
|
from .writers import (
|
||||||
write_bytes_fixed,
|
write_bytes_fixed,
|
||||||
write_bytes_prefixed,
|
write_bytes_prefixed,
|
||||||
@ -23,7 +25,7 @@ from .writers import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
from typing import List, Optional
|
from typing import List, Optional, Tuple
|
||||||
from trezor.messages.TxInputType import EnumTypeInputScriptType
|
from trezor.messages.TxInputType import EnumTypeInputScriptType
|
||||||
from .writers import Writer
|
from .writers import Writer
|
||||||
|
|
||||||
@ -143,6 +145,23 @@ def input_script_p2pkh_or_p2sh(
|
|||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
|
def parse_input_script_p2pkh(script_sig: bytes,) -> Tuple[bytes, bytes, int]:
|
||||||
|
try:
|
||||||
|
r = BytearrayReader(script_sig)
|
||||||
|
n = read_op_push(r)
|
||||||
|
signature = r.read(n - 1)
|
||||||
|
hash_type = r.get()
|
||||||
|
|
||||||
|
n = read_op_push(r)
|
||||||
|
pubkey = r.read()
|
||||||
|
if len(pubkey) != n:
|
||||||
|
raise ValueError
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
wire.DataError("Invalid scriptSig.")
|
||||||
|
|
||||||
|
return pubkey, signature, hash_type
|
||||||
|
|
||||||
|
|
||||||
def output_script_p2pkh(pubkeyhash: bytes) -> bytearray:
|
def output_script_p2pkh(pubkeyhash: bytes) -> bytearray:
|
||||||
utils.ensure(len(pubkeyhash) == 20)
|
utils.ensure(len(pubkeyhash) == 20)
|
||||||
s = bytearray(25)
|
s = bytearray(25)
|
||||||
@ -253,6 +272,27 @@ def witness_p2wpkh(signature: bytes, pubkey: bytes, sighash: int) -> bytearray:
|
|||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
|
def parse_witness_p2wpkh(witness: bytes) -> Tuple[bytes, bytes, int]:
|
||||||
|
try:
|
||||||
|
r = BytearrayReader(witness)
|
||||||
|
|
||||||
|
if r.get() != 2:
|
||||||
|
# num of stack items, in P2WPKH it's always 2
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
n = read_bitcoin_varint(r)
|
||||||
|
signature = r.read(n - 1)
|
||||||
|
hash_type = r.get()
|
||||||
|
|
||||||
|
pubkey = read_bytes_prefixed(r)
|
||||||
|
if r.remaining_count():
|
||||||
|
raise ValueError
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
raise wire.DataError("Invalid witness.")
|
||||||
|
|
||||||
|
return pubkey, signature, hash_type
|
||||||
|
|
||||||
|
|
||||||
def witness_p2wsh(
|
def witness_p2wsh(
|
||||||
multisig: MultisigRedeemScriptType,
|
multisig: MultisigRedeemScriptType,
|
||||||
signature: bytes,
|
signature: bytes,
|
||||||
@ -302,6 +342,33 @@ def witness_p2wsh(
|
|||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
|
def parse_witness_p2wsh(witness: bytes) -> Tuple[bytes, List[Tuple[bytes, int]]]:
|
||||||
|
try:
|
||||||
|
r = BytearrayReader(witness)
|
||||||
|
|
||||||
|
# Get number of witness stack items.
|
||||||
|
item_count = read_bitcoin_varint(r)
|
||||||
|
|
||||||
|
# Skip over OP_FALSE, which is due to the old OP_CHECKMULTISIG bug.
|
||||||
|
if r.get() != 0:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
signatures = []
|
||||||
|
for i in range(item_count - 2):
|
||||||
|
n = read_bitcoin_varint(r)
|
||||||
|
signature = r.read(n - 1)
|
||||||
|
hash_type = r.get()
|
||||||
|
signatures.append((signature, hash_type))
|
||||||
|
|
||||||
|
script = read_bytes_prefixed(r)
|
||||||
|
if r.remaining_count():
|
||||||
|
raise ValueError
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
raise wire.DataError("Invalid witness.")
|
||||||
|
|
||||||
|
return script, signatures
|
||||||
|
|
||||||
|
|
||||||
# Multisig
|
# Multisig
|
||||||
# ===
|
# ===
|
||||||
#
|
#
|
||||||
@ -351,6 +418,33 @@ def input_script_multisig(
|
|||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
|
def parse_input_script_multisig(
|
||||||
|
script_sig: bytes,
|
||||||
|
) -> Tuple[bytes, List[Tuple[bytes, int]]]:
|
||||||
|
try:
|
||||||
|
r = BytearrayReader(script_sig)
|
||||||
|
|
||||||
|
# Skip over OP_FALSE, which is due to the old OP_CHECKMULTISIG bug.
|
||||||
|
if r.get() != 0:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
signatures = []
|
||||||
|
n = read_op_push(r)
|
||||||
|
while r.remaining_count() > n:
|
||||||
|
signature = r.read(n - 1)
|
||||||
|
hash_type = r.get()
|
||||||
|
signatures.append((signature, hash_type))
|
||||||
|
n = read_op_push(r)
|
||||||
|
|
||||||
|
script = r.read()
|
||||||
|
if len(script) != n:
|
||||||
|
raise ValueError
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
raise wire.DataError("Invalid scriptSig.")
|
||||||
|
|
||||||
|
return script, signatures
|
||||||
|
|
||||||
|
|
||||||
def output_script_multisig(pubkeys: List[bytes], m: int) -> bytearray:
|
def output_script_multisig(pubkeys: List[bytes], m: int) -> bytearray:
|
||||||
w = empty_bytearray(output_script_multisig_length(pubkeys, m))
|
w = empty_bytearray(output_script_multisig_length(pubkeys, m))
|
||||||
write_output_script_multisig(w, pubkeys, m)
|
write_output_script_multisig(w, pubkeys, m)
|
||||||
@ -376,6 +470,39 @@ def output_script_multisig_length(pubkeys: List[bytes], m: int) -> int:
|
|||||||
return 1 + len(pubkeys) * (1 + 33) + 1 + 1 # see output_script_multisig
|
return 1 + len(pubkeys) * (1 + 33) + 1 + 1 # see output_script_multisig
|
||||||
|
|
||||||
|
|
||||||
|
def parse_output_script_multisig(script: bytes) -> Tuple[List[bytes], int]:
|
||||||
|
try:
|
||||||
|
r = BytearrayReader(script)
|
||||||
|
|
||||||
|
threshold = r.get() - 0x50
|
||||||
|
pubkey_count = script[-2] - 0x50
|
||||||
|
|
||||||
|
if (
|
||||||
|
not 1 <= threshold <= 15
|
||||||
|
or not 1 <= pubkey_count <= 15
|
||||||
|
or threshold > pubkey_count
|
||||||
|
):
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
public_keys = []
|
||||||
|
for i in range(pubkey_count):
|
||||||
|
n = read_op_push(r)
|
||||||
|
if n != 33:
|
||||||
|
raise ValueError
|
||||||
|
public_keys.append(r.read(n))
|
||||||
|
|
||||||
|
r.get() # ignore pubkey_count
|
||||||
|
if r.get() != 0xAE: # OP_CHECKMULTISIG
|
||||||
|
raise ValueError
|
||||||
|
if r.remaining_count():
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
raise wire.DataError("Invalid multisig script")
|
||||||
|
|
||||||
|
return public_keys, threshold
|
||||||
|
|
||||||
|
|
||||||
# OP_RETURN
|
# OP_RETURN
|
||||||
# ===
|
# ===
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user