1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-03 21:32:33 +00:00

feat(core): verify bip340 pubkeys used in p2tr addresses

Co-Authored-By: Ondřej Vejpustek <ondrej.vejpustek@satoshilabs.com>
This commit is contained in:
Pavol Rusnak 2022-01-21 15:31:40 +01:00 committed by Andrew Kozlik
parent ea6b005003
commit c6667fa0c2
6 changed files with 36 additions and 5 deletions

View File

@ -0,0 +1 @@
Add extra check for Taproot scripts validity

View File

@ -113,6 +113,23 @@ STATIC mp_obj_t mod_trezorcrypto_bip340_sign(mp_obj_t secret_key,
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_bip340_sign_obj, STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_bip340_sign_obj,
mod_trezorcrypto_bip340_sign); mod_trezorcrypto_bip340_sign);
/// def verify_publickey(public_key: bytes) -> bool:
/// """
/// Verifies whether the public key is valid.
/// Returns True on success.
/// """
STATIC mp_obj_t mod_trezorcrypto_bip340_verify_publickey(mp_obj_t public_key) {
mp_buffer_info_t pk = {0};
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
if (pk.len != 32) {
return mp_const_false;
}
int ret = zkp_bip340_verify_publickey((const uint8_t *)pk.buf);
return mp_obj_new_bool(ret == 0);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_bip340_verify_publickey_obj,
mod_trezorcrypto_bip340_verify_publickey);
/// def verify(public_key: bytes, signature: bytes, digest: bytes) -> bool: /// def verify(public_key: bytes, signature: bytes, digest: bytes) -> bool:
/// """ /// """
/// Uses public key to verify the signature of the digest. /// Uses public key to verify the signature of the digest.
@ -229,6 +246,8 @@ STATIC const mp_rom_map_elem_t mod_trezorcrypto_bip340_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR_publickey), {MP_ROM_QSTR(MP_QSTR_publickey),
MP_ROM_PTR(&mod_trezorcrypto_bip340_publickey_obj)}, MP_ROM_PTR(&mod_trezorcrypto_bip340_publickey_obj)},
{MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_bip340_sign_obj)}, {MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_bip340_sign_obj)},
{MP_ROM_QSTR(MP_QSTR_verify_publickey),
MP_ROM_PTR(&mod_trezorcrypto_bip340_verify_publickey_obj)},
{MP_ROM_QSTR(MP_QSTR_verify), {MP_ROM_QSTR(MP_QSTR_verify),
MP_ROM_PTR(&mod_trezorcrypto_bip340_verify_obj)}, MP_ROM_PTR(&mod_trezorcrypto_bip340_verify_obj)},
{MP_ROM_QSTR(MP_QSTR_tweak_public_key), {MP_ROM_QSTR(MP_QSTR_tweak_public_key),

View File

@ -25,6 +25,14 @@ def sign(
""" """
# extmod/modtrezorcrypto/modtrezorcrypto-bip340.h
def verify_publickey(public_key: bytes) -> bool:
"""
Verifies whether the public key is valid.
Returns True on success.
"""
# extmod/modtrezorcrypto/modtrezorcrypto-bip340.h # extmod/modtrezorcrypto/modtrezorcrypto-bip340.h
def verify(public_key: bytes, signature: bytes, digest: bytes) -> bool: def verify(public_key: bytes, signature: bytes, digest: bytes) -> bool:
""" """

View File

@ -130,10 +130,13 @@ def encode_bech32_address(prefix: str, witver: int, script: bytes) -> str:
def decode_bech32_address(prefix: str, address: str) -> tuple[int, bytes]: def decode_bech32_address(prefix: str, address: str) -> tuple[int, bytes]:
witver, raw = bech32.decode(prefix, address) witver, raw = bech32.decode(prefix, address)
if witver not in _BECH32_WITVERS: if witver not in _BECH32_WITVERS:
raise wire.ProcessError("Invalid address witness program") raise wire.DataError("Invalid address witness program")
assert witver is not None assert witver is not None
assert raw is not None assert raw is not None
return witver, bytes(raw) # check that P2TR address encodes a valid BIP340 public key
if witver == 1 and not bip340.verify_publickey(raw):
raise wire.DataError("Invalid Taproot witness program")
return witver, raw
def input_is_segwit(txi: TxInput) -> bool: def input_is_segwit(txi: TxInput) -> bool:

View File

@ -154,7 +154,7 @@ def convertbits(
return ret return ret
def decode(hrp: str, addr: str) -> OptionalTuple2[int, list[int]]: def decode(hrp: str, addr: str) -> OptionalTuple2[int, bytes]:
"""Decode a segwit address.""" """Decode a segwit address."""
hrpgot, data, spec = bech32_decode(addr) hrpgot, data, spec = bech32_decode(addr)
# the following two lines are strictly not required # the following two lines are strictly not required
@ -164,7 +164,7 @@ def decode(hrp: str, addr: str) -> OptionalTuple2[int, list[int]]:
if hrpgot != hrp: if hrpgot != hrp:
return (None, None) return (None, None)
try: try:
decoded = convertbits(data[1:], 5, 8, False) decoded = bytes(convertbits(data[1:], 5, 8, False))
except ValueError: except ValueError:
return (None, None) return (None, None)
if not 2 <= len(decoded) <= 40: if not 2 <= len(decoded) <= 40:

View File

@ -27,7 +27,7 @@ from trezor.crypto import bech32
def segwit_scriptpubkey(witver, witprog): def segwit_scriptpubkey(witver, witprog):
"""Construct a Segwit scriptPubKey for a given witness program.""" """Construct a Segwit scriptPubKey for a given witness program."""
return bytes([witver + 0x50 if witver else 0, len(witprog)] + witprog) return bytes([witver + 0x50 if witver else 0, len(witprog)]) + witprog
VALID_CHECKSUM = [ VALID_CHECKSUM = [