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,
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:
/// """
/// 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_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_verify_publickey),
MP_ROM_PTR(&mod_trezorcrypto_bip340_verify_publickey_obj)},
{MP_ROM_QSTR(MP_QSTR_verify),
MP_ROM_PTR(&mod_trezorcrypto_bip340_verify_obj)},
{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
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]:
witver, raw = bech32.decode(prefix, address)
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 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:

@ -154,7 +154,7 @@ def convertbits(
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."""
hrpgot, data, spec = bech32_decode(addr)
# 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:
return (None, None)
try:
decoded = convertbits(data[1:], 5, 8, False)
decoded = bytes(convertbits(data[1:], 5, 8, False))
except ValueError:
return (None, None)
if not 2 <= len(decoded) <= 40:

@ -27,7 +27,7 @@ from trezor.crypto import bech32
def segwit_scriptpubkey(witver, witprog):
"""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 = [

Loading…
Cancel
Save