diff --git a/extmod/foundation/modtcc-codecs.c b/extmod/foundation/modtcc-codecs.c index 38af7781d..dc6a54801 100644 --- a/extmod/foundation/modtcc-codecs.c +++ b/extmod/foundation/modtcc-codecs.c @@ -113,6 +113,10 @@ STATIC mp_obj_t modtcc_bech32_encode(size_t n_args, const mp_obj_t *args) { const uint32_t segwit_version = mp_obj_int_get_checked(args[1]); uint32_t bech32_version = BECH32_ENCODING_BECH32; + if (segwit_version > 0) { + bech32_version = BECH32_ENCODING_BECH32M; + } + if (n_args == 4) { bech32_version = mp_obj_int_get_checked(args[3]); } diff --git a/ports/stm32/boards/Passport/modules/chains.py b/ports/stm32/boards/Passport/modules/chains.py index 21cf3172c..a892a61d2 100644 --- a/ports/stm32/boards/Passport/modules/chains.py +++ b/ports/stm32/boards/Passport/modules/chains.py @@ -12,7 +12,7 @@ import trezorcrypto import tcc from public_constants import AF_CLASSIC, AF_P2SH, AF_P2WPKH, AF_P2WSH, AF_P2WPKH_P2SH, AF_P2WSH_P2SH -from public_constants import AFC_PUBKEY, AFC_SEGWIT, AFC_BECH32, AFC_SCRIPT, AFC_WRAPPED +from public_constants import AFC_PUBKEY, AFC_SEGWIT, AFC_BECH32, AFC_SCRIPT, AFC_WRAPPED, AFC_BECH32M from serializations import hash160, ser_compact_size from ucollections import namedtuple from opcodes import OP_CHECKMULTISIG @@ -116,6 +116,8 @@ def address(cls, node, addr_fmt): if addr_fmt & AFC_BECH32: # bech32 encoded segwit p2pkh return tcc.codecs.bech32_encode(cls.bech32_hrp, 0, raw) + elif addr_fmt & AFC_BECH32M: + return tcc.codecs.bech32_encode(cls.bech32_hrp, 1, raw) # see bip-141, "P2WPKH nested in BIP16 P2SH" section assert addr_fmt == AF_P2WPKH_P2SH diff --git a/ports/stm32/boards/Passport/modules/public_constants.py b/ports/stm32/boards/Passport/modules/public_constants.py index 13f983a7d..077462207 100644 --- a/ports/stm32/boards/Passport/modules/public_constants.py +++ b/ports/stm32/boards/Passport/modules/public_constants.py @@ -50,6 +50,7 @@ AFC_BECH32 = const(0x04) # just how we're encoding it? AFC_SCRIPT = const(0x08) # paying into a script AFC_WRAPPED = const(0x10) # for transition/compat types for segwit vs. old +AFC_BECH32M = const(0x20) # bech32m encoding # Numeric codes for specific address types AF_CLASSIC = AFC_PUBKEY # 1addr @@ -58,6 +59,7 @@ AF_P2WSH = AFC_SCRIPT | AFC_SEGWIT | AFC_BECH32 # segwit multisig AF_P2WPKH_P2SH = AFC_WRAPPED | AFC_PUBKEY | AFC_SEGWIT # looks classic P2SH, but p2wpkh inside AF_P2WSH_P2SH = AFC_WRAPPED | AFC_SCRIPT | AFC_SEGWIT # looks classic P2SH, segwit multisig +AF_P2TR = AFC_PUBKEY | AFC_SEGWIT | AFC_BECH32M # taproot allows scripts and pubkeys SUPPORTED_ADDR_FORMATS = frozenset([ AF_CLASSIC, @@ -66,6 +68,7 @@ AF_P2WSH, AF_P2WPKH_P2SH, AF_P2WSH_P2SH, + AF_P2TR, ]) # BIP-174 aka PSBT defined values diff --git a/ports/stm32/boards/Passport/modules/tasks/search_for_address_task.py b/ports/stm32/boards/Passport/modules/tasks/search_for_address_task.py index b8c813041..b2ace014f 100644 --- a/ports/stm32/boards/Passport/modules/tasks/search_for_address_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/search_for_address_task.py @@ -24,6 +24,7 @@ async def search_for_address_task( import stash from errors import Error from uasyncio import sleep_ms + from ubinascii import hexlify as b2a_hex try: with stash.SensitiveValues() as sv: @@ -50,9 +51,11 @@ async def search_for_address_task( addr_path = '{}/{}/{}'.format(path, is_change, curr_idx) # Zero for non-change address # print('Singlesig: addr_path={}'.format(addr_path)) node = sv.derive_path(addr_path) + print(b2a_hex(node.public_key())) curr_address = sv.chain.address(node, addr_type) # print(' curr_idx={}: path={} addr_type={} curr_address = {}'.format(curr_idx, addr_path, # addr_type, curr_address)) + print("path: {}, address: {}".format(addr_path, curr_address)) if curr_address == address: await on_done(curr_idx, addr_path, None) return diff --git a/ports/stm32/boards/Passport/modules/wallets/utils.py b/ports/stm32/boards/Passport/modules/wallets/utils.py index d5896b127..83c87267d 100644 --- a/ports/stm32/boards/Passport/modules/wallets/utils.py +++ b/ports/stm32/boards/Passport/modules/wallets/utils.py @@ -6,7 +6,7 @@ import chains import common -from public_constants import AF_CLASSIC, AF_P2SH, AF_P2WPKH_P2SH, AF_P2WSH_P2SH, AF_P2WPKH, AF_P2WSH +from public_constants import AF_CLASSIC, AF_P2SH, AF_P2WPKH_P2SH, AF_P2WSH_P2SH, AF_P2WPKH, AF_P2WSH, AF_P2TR from utils import get_accounts, get_derived_keys @@ -73,7 +73,10 @@ def get_addr_type_from_address(address, is_multisig): return AF_P2WSH_P2SH if is_multisig else AF_P2WPKH_P2SH elif (address[0] == 'b' and address[1] == 'c' and address[2] == '1') or \ (address[0] == 't' and address[1] == 'b' and address[2] == '1'): - return AF_P2WSH if is_multisig else AF_P2WPKH + if address[3] == 'p': + return AF_P2TR + else: + return AF_P2WSH if is_multisig else AF_P2WPKH return None @@ -91,6 +94,8 @@ def get_bip_num_from_addr_type(addr_type, is_multisig): return 84 elif addr_type == AF_P2WPKH_P2SH: return 49 + elif addr_type == AF_P2TR: + return 86 else: raise ValueError(addr_type) @@ -110,6 +115,8 @@ def get_addr_type_from_deriv(path): return AF_P2WSH_P2SH elif subpath == '2': return AF_P2WSH + elif type_str == '86': + return AF_P2TR return None @@ -133,7 +140,10 @@ def get_deriv_fmt_from_address(address, is_multisig): return "m/49'/{coin_type}'/{acct}'" elif ((address[0] == 'b' and address[1] == 'c' and address[2] == '1') or (address[0] == 't' and address[1] == 'b' and address[2] == '1')): - return "m/84'/{coin_type}'/{acct}'" + if address[3] == 'p': + return "m/86'/{coin_type}'/{acct}'" + else: + return "m/84'/{coin_type}'/{acct}'" return None @@ -154,6 +164,8 @@ def get_deriv_fmt_from_addr_type(addr_type, is_multisig): return "m/49'/{coin_type}'/{acct}'" elif addr_type == AF_P2WPKH: return "m/84'/{coin_type}'/{acct}'" + elif addr_type == AF_P2TR: + return "m/86'/{coin_type}'/{acct}'" return None