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

Co-Authored-By: Ondřej Vejpustek <ondrej.vejpustek@satoshilabs.com>
pull/2098/head
Pavol Rusnak 2 years ago committed by Andrew Kozlik
parent ea6b005003
commit c6667fa0c2

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

@ -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),

@ -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:
""" """

@ -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:

@ -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:

@ -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 = [

Loading…
Cancel
Save