From cb6022ce04ea70521ec94a8a62eb4a291e134cad Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 4 Jan 2018 20:18:34 +0100 Subject: [PATCH] Added support for cashaddr. --- firmware/Makefile | 1 + firmware/coin_info.py | 1 + firmware/coins.h | 1 + firmware/transaction.c | 49 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index 88fa9ace0b..8aaae3854c 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -58,6 +58,7 @@ OBJS += ../vendor/trezor-crypto/pbkdf2.o OBJS += ../vendor/trezor-crypto/base32.o OBJS += ../vendor/trezor-crypto/base58.o OBJS += ../vendor/trezor-crypto/segwit_addr.o +OBJS += ../vendor/trezor-crypto/cash_addr.o OBJS += ../vendor/trezor-crypto/ripemd160.o OBJS += ../vendor/trezor-crypto/sha2.o diff --git a/firmware/coin_info.py b/firmware/coin_info.py index 509d06c152..a84e8e4588 100755 --- a/firmware/coin_info.py +++ b/firmware/coin_info.py @@ -91,6 +91,7 @@ def coin_to_struct(coin): ("xprv_magic", format_hex(coin["xprv_magic"])), ("forkid", format_number(coin["forkid"])), ("bech32_prefix", format_string(coin["bech32_prefix"])), + ("cashaddr_prefix", format_string(coin["cashaddr_prefix"])), ("coin_type", "({} | 0x80000000)".format(format_number(coin["bip44"]))), # noqa: E501 ("curve_name", "{}_NAME".format(coin["curve_name"].upper())), # noqa: E501 ("curve", "&{}_info".format(coin["curve_name"])), diff --git a/firmware/coins.h b/firmware/coins.h index 2cdd657240..a344c17845 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -44,6 +44,7 @@ typedef struct _CoinInfo { uint32_t xprv_magic; uint32_t forkid; const char *bech32_prefix; + const char *cashaddr_prefix; uint32_t coin_type; const char *curve_name; const curve_info *curve; diff --git a/firmware/transaction.c b/firmware/transaction.c index 5a544a9271..ef025c8b7d 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -32,9 +32,14 @@ #include "messages.pb.h" #include "types.pb.h" #include "segwit_addr.h" +#include "cash_addr.h" #define SEGWIT_VERSION_0 0 +#define CASHADDR_P2KH (0) +#define CASHADDR_P2SH (8) +#define CASHADDR_160 (0) + /* transaction input size (without script): 32 prevhash, 4 idx, 4 sequence */ #define TXSIZE_INPUT 40 /* transaction output size (without script): 8 amount */ @@ -138,6 +143,12 @@ bool compute_address(const CoinInfo *coin, if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, address, MAX_ADDR_SIZE)) { return 0; } + } else if (coin->cashaddr_prefix) { + raw[0] = CASHADDR_P2SH | CASHADDR_160; + 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); @@ -165,6 +176,11 @@ bool compute_address(const CoinInfo *coin, return 0; } ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, coin->curve->hasher_pubkey, coin->curve->hasher_base58, address, MAX_ADDR_SIZE); + } else if (coin->cashaddr_prefix) { + ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160, coin->curve->hasher_type, 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); } @@ -252,6 +268,28 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL out->script_pubkey.size = 23; + } else if (coin->cashaddr_prefix + && cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, in->address)) { + if (addr_raw_len == 21 + && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { + out->script_pubkey.bytes[0] = 0x76; // OP_DUP + out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 3, addr_raw + 1, 20); + out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY + out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG + out->script_pubkey.size = 25; + + } else if (addr_raw_len == 21 + && addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { + out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); + out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL + out->script_pubkey.size = 23; + } else { + return 0; + } } else if (coin->bech32_prefix) { int witver; if (!segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, in->address)) { @@ -736,7 +774,16 @@ uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) { uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; int witver; size_t addr_raw_len; - if (coin->bech32_prefix + if (coin->cashaddr_prefix + && cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, txoutput->address)) { + if (addr_raw_len == 21 + && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { + output_script_size = TXSIZE_P2PKHASH; + } else if (addr_raw_len == 21 + && addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { + output_script_size = TXSIZE_P2SCRIPT; + } + } else if (coin->bech32_prefix && segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, txoutput->address)) { output_script_size = 2 + addr_raw_len; } else {