mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-03 13:22: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:
parent
ea6b005003
commit
c6667fa0c2
1
core/.changelog.d/2077.added
Normal file
1
core/.changelog.d/2077.added
Normal file
@ -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…
Reference in New Issue
Block a user