1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-19 20:01:11 +00:00

Allow SegWit addresses

New output scripts for segwit addresses in accordance to BIP-142 and BIP-141.
This allows Trezor to pay to segwit users, but it doesn't enable segwit for
Trezor itself.
This commit is contained in:
Jochen Hoenicke 2016-04-27 23:38:59 +02:00 committed by Pavol Rusnak
parent 71890e4edf
commit 1bd4b99f95
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
3 changed files with 61 additions and 34 deletions

View File

@ -12,7 +12,7 @@ TxInputType.address_n max_count:8
TxInputType.prev_hash max_size:32
TxInputType.script_sig max_size:1650
TxOutputType.address max_size:41
TxOutputType.address max_size:54
TxOutputType.address_n max_count:8
TxOutputType.op_return_data max_size:80

View File

@ -229,7 +229,7 @@ typedef struct {
typedef struct _TxOutputType {
bool has_address;
char address[41];
char address[54];
size_t address_n_count;
uint32_t address_n[8];
uint64_t amount;

View File

@ -61,11 +61,68 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
memset(out, 0, sizeof(TxOutputBinType));
out->amount = in->amount;
uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
int addr_raw_len;
if (in->has_address) { // address provided -> regular output
addr_raw_len = base58_decode_check(in->address, addr_raw, MAX_ADDR_RAW_SIZE);
if (in->script_type != OutputScriptType_PAYTOADDRESS) {
// allow for p2sh (backward compatibility only)
if (in->script_type != OutputScriptType_PAYTOSCRIPTHASH
|| addr_raw_len != 21
|| addr_raw[0] != coin->address_type_p2sh) {
return 0;
}
}
if (addr_raw_len == 21 &&
addr_raw[0] == coin->address_type) { // p2pkh
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] == coin->address_type_p2sh) { // p2sh
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 if (addr_raw_len == 23
&& addr_raw[0] == coin->address_type_p2wpkh
&& addr_raw[1] == 0 && addr_raw[2] == 0) { // p2wpkh v0
out->script_pubkey.bytes[0] = 0x00; // version 0
out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes
memcpy(out->script_pubkey.bytes + 2, addr_raw + 3, 20);
out->script_pubkey.size = 22;
} else if (addr_raw_len == 35
&& addr_raw[0] == coin->address_type_p2wsh
&& addr_raw[1] == 0 && addr_raw[2] == 0) { // p2wsh v0
out->script_pubkey.bytes[0] = 0x00; // version 0
out->script_pubkey.bytes[1] = 0x20; // pushing 32 bytes
memcpy(out->script_pubkey.bytes + 2, addr_raw + 3, 32);
out->script_pubkey.size = 34;
} else {
return 0;
}
if (needs_confirm) {
layoutConfirmOutput(coin, in);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return -1;
}
}
return out->script_pubkey.size;
}
if (in->script_type == OutputScriptType_PAYTOADDRESS) {
// address_n provided-> change address -> calculate from address_n
if (in->address_n_count > 0) {
if (in->script_type == OutputScriptType_PAYTOADDRESS &&
in->address_n_count > 0) {
HDNode node;
memcpy(&node, root, sizeof(HDNode));
if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count) == 0) {
@ -73,18 +130,6 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
}
layoutProgressUpdate(true);
hdnode_get_address_raw(&node, coin->address_type, addr_raw);
} else
if (in->has_address) { // address provided -> regular output
if (needs_confirm) {
layoutConfirmOutput(coin, in);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return -1;
}
}
if (!ecdsa_address_decode(in->address, coin->address_type, addr_raw)) {
return 0;
}
} else { // does not have address_n neither address -> error
return 0;
}
@ -99,24 +144,6 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
return 25;
}
if (in->script_type == OutputScriptType_PAYTOSCRIPTHASH) {
if (!in->has_address || !ecdsa_address_decode(in->address, coin->address_type_p2sh, addr_raw)) {
return 0;
}
if (needs_confirm) {
layoutConfirmOutput(coin, in);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return -1;
}
}
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 + address_prefix_bytes_len(coin->address_type_p2sh), 20);
out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL
out->script_pubkey.size = 23;
return 23;
}
if (in->script_type == OutputScriptType_PAYTOMULTISIG) {
uint8_t buf[32];
size_t prefix_bytes = address_prefix_bytes_len(coin->address_type_p2sh);