1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-24 23:38:09 +00:00

feat(legacy): Implement GetAddress for taproot.

This commit is contained in:
Andrew Kozlik 2021-11-10 13:15:20 +01:00 committed by Andrew Kozlik
parent 34e8284331
commit 6c9c727359
4 changed files with 53 additions and 31 deletions

View File

@ -0,0 +1 @@
Support GetAddress for Taproot addresses.

View File

@ -233,7 +233,8 @@ void fsm_msgGetAddress(const GetAddress *msg) {
} }
bool is_cashaddr = coin->cashaddr_prefix != NULL; bool is_cashaddr = coin->cashaddr_prefix != NULL;
bool is_bech32 = msg->script_type == InputScriptType_SPENDWITNESS; bool is_bech32 = msg->script_type == InputScriptType_SPENDWITNESS ||
msg->script_type == InputScriptType_SPENDTAPROOT;
if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32, if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32,
is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0, is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0,
msg->address_n, msg->address_n_count, false, msg->address_n, msg->address_n_count, false,

View File

@ -33,8 +33,10 @@
#include "ripemd160.h" #include "ripemd160.h"
#include "segwit_addr.h" #include "segwit_addr.h"
#include "util.h" #include "util.h"
#include "zkp_bip340.h"
#define SEGWIT_VERSION_0 0 #define SEGWIT_VERSION_0 0
#define SEGWIT_VERSION_1 1
#define CASHADDR_P2KH (0) #define CASHADDR_P2KH (0)
#define CASHADDR_P2SH (8) #define CASHADDR_P2SH (8)
@ -143,21 +145,27 @@ bool compute_address(const CoinInfo *coin, InputScriptType script_type,
address, MAX_ADDR_SIZE)) { address, MAX_ADDR_SIZE)) {
return 0; return 0;
} }
} else if (coin->cashaddr_prefix) { } else if (script_type == InputScriptType_SPENDADDRESS ||
raw[0] = CASHADDR_P2SH | CASHADDR_160; script_type == InputScriptType_SPENDMULTISIG) {
ripemd160(digest, 32, raw + 1); if (coin->cashaddr_prefix) {
if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { raw[0] = CASHADDR_P2SH | CASHADDR_160;
return 0; ripemd160(digest, 32, raw + 1);
if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) {
return 0;
}
} else {
// non-segwit p2sh multisig
prelen = address_prefix_bytes_len(coin->address_type_p2sh);
address_write_prefix_bytes(coin->address_type_p2sh, raw);
ripemd160(digest, 32, raw + prelen);
if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58,
address, MAX_ADDR_SIZE)) {
return 0;
}
} }
} else { } else {
// non-segwit p2sh multisig // unsupported script type
prelen = address_prefix_bytes_len(coin->address_type_p2sh); return 0;
address_write_prefix_bytes(coin->address_type_p2sh, raw);
ripemd160(digest, 32, raw + prelen);
if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58,
address, MAX_ADDR_SIZE)) {
return 0;
}
} }
} else if (script_type == InputScriptType_SPENDWITNESS) { } else if (script_type == InputScriptType_SPENDWITNESS) {
// segwit p2wpkh: pubkey hash is ripemd160 of sha256 // segwit p2wpkh: pubkey hash is ripemd160 of sha256
@ -169,6 +177,17 @@ bool compute_address(const CoinInfo *coin, InputScriptType script_type,
digest, 20)) { digest, 20)) {
return 0; return 0;
} }
} else if (script_type == InputScriptType_SPENDTAPROOT) {
// taproot
if (!coin->has_taproot || !coin->has_segwit || !coin->bech32_prefix) {
return 0;
}
uint8_t tweaked_pubkey[32];
zkp_bip340_tweak_public_key(node->public_key + 1, NULL, tweaked_pubkey);
if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_1,
tweaked_pubkey, 32)) {
return 0;
}
} else if (script_type == InputScriptType_SPENDP2SHWITNESS) { } else if (script_type == InputScriptType_SPENDP2SHWITNESS) {
// segwit p2wpkh embedded in p2sh // segwit p2wpkh embedded in p2sh
if (!coin->has_segwit) { if (!coin->has_segwit) {
@ -177,16 +196,22 @@ bool compute_address(const CoinInfo *coin, InputScriptType script_type,
ecdsa_get_address_segwit_p2sh( ecdsa_get_address_segwit_p2sh(
node->public_key, coin->address_type_p2sh, coin->curve->hasher_pubkey, node->public_key, coin->address_type_p2sh, coin->curve->hasher_pubkey,
coin->curve->hasher_base58, address, MAX_ADDR_SIZE); coin->curve->hasher_base58, address, MAX_ADDR_SIZE);
} else if (coin->cashaddr_prefix) { } else if (script_type == InputScriptType_SPENDADDRESS ||
ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160, script_type == InputScriptType_SPENDMULTISIG) {
coin->curve->hasher_pubkey, raw); if (coin->cashaddr_prefix) {
if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160,
return 0; coin->curve->hasher_pubkey, raw);
if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) {
return 0;
}
} else {
ecdsa_get_address(node->public_key, coin->address_type,
coin->curve->hasher_pubkey, coin->curve->hasher_base58,
address, MAX_ADDR_SIZE);
} }
} else { } else {
ecdsa_get_address(node->public_key, coin->address_type, // unsupported script type
coin->curve->hasher_pubkey, coin->curve->hasher_base58, return 0;
address, MAX_ADDR_SIZE);
} }
return 1; return 1;
} }

View File

@ -45,33 +45,29 @@ VECTORS = ( # coin, path, script_type, address
proto.InputScriptType.SPENDWITNESS, proto.InputScriptType.SPENDWITNESS,
"bc1qktmhrsmsenepnnfst8x6j27l0uqv7ggrg8x38q", "bc1qktmhrsmsenepnnfst8x6j27l0uqv7ggrg8x38q",
), ),
pytest.param( (
"Testnet", "Testnet",
"86'/1'/0'/0/0", "86'/1'/0'/0/0",
proto.InputScriptType.SPENDTAPROOT, proto.InputScriptType.SPENDTAPROOT,
"tb1pswrqtykue8r89t9u4rprjs0gt4qzkdfuursfnvqaa3f2yql07zmq8s8a5u", "tb1pswrqtykue8r89t9u4rprjs0gt4qzkdfuursfnvqaa3f2yql07zmq8s8a5u",
marks=pytest.mark.skip_t1,
), ),
pytest.param( (
"Testnet", "Testnet",
"86'/1'/0'/1/0", "86'/1'/0'/1/0",
proto.InputScriptType.SPENDTAPROOT, proto.InputScriptType.SPENDTAPROOT,
"tb1pn2d0yjeedavnkd8z8lhm566p0f2utm3lgvxrsdehnl94y34txmts5s7t4c", "tb1pn2d0yjeedavnkd8z8lhm566p0f2utm3lgvxrsdehnl94y34txmts5s7t4c",
marks=pytest.mark.skip_t1,
), ),
pytest.param( (
"Bitcoin", "Bitcoin",
"86'/0'/0'/0/0", "86'/0'/0'/0/0",
proto.InputScriptType.SPENDTAPROOT, proto.InputScriptType.SPENDTAPROOT,
"bc1ptxs597p3fnpd8gwut5p467ulsydae3rp9z75hd99w8k3ljr9g9rqx6ynaw", "bc1ptxs597p3fnpd8gwut5p467ulsydae3rp9z75hd99w8k3ljr9g9rqx6ynaw",
marks=pytest.mark.skip_t1,
), ),
pytest.param( (
"Bitcoin", "Bitcoin",
"86'/0'/0'/1/0", "86'/0'/0'/1/0",
proto.InputScriptType.SPENDTAPROOT, proto.InputScriptType.SPENDTAPROOT,
"bc1pgypgja2hmcx2l6s2ssq75k6ev68ved6nujcspt47dgvkp8euc70s6uegk6", "bc1pgypgja2hmcx2l6s2ssq75k6ev68ved6nujcspt47dgvkp8euc70s6uegk6",
marks=pytest.mark.skip_t1,
), ),
pytest.param( pytest.param(
"Groestlcoin", "Groestlcoin",
@ -114,7 +110,6 @@ def test_show_segwit(client, show_display, coin, path, script_type, address):
# Tests https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki#test-vectors # Tests https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki#test-vectors
@pytest.mark.skip_t1
@pytest.mark.setup_client( @pytest.mark.setup_client(
mnemonic="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" mnemonic="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
) )