mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-07 07:12:34 +00:00
Merge branch 'segwit'
This commit is contained in:
commit
f1db85948e
@ -31,6 +31,8 @@
|
|||||||
#include "protect.h"
|
#include "protect.h"
|
||||||
#include "pinmatrix.h"
|
#include "pinmatrix.h"
|
||||||
#include "layout2.h"
|
#include "layout2.h"
|
||||||
|
#include "address.h"
|
||||||
|
#include "base58.h"
|
||||||
#include "ecdsa.h"
|
#include "ecdsa.h"
|
||||||
#include "reset.h"
|
#include "reset.h"
|
||||||
#include "recovery.h"
|
#include "recovery.h"
|
||||||
@ -579,24 +581,9 @@ void fsm_msgGetAddress(GetAddress *msg)
|
|||||||
if (!node) return;
|
if (!node) return;
|
||||||
hdnode_fill_public_key(node);
|
hdnode_fill_public_key(node);
|
||||||
|
|
||||||
if (msg->has_multisig) {
|
layoutProgress("Computing address", 0);
|
||||||
layoutProgressSwipe("Preparing", 0);
|
if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, resp->address)) {
|
||||||
if (cryptoMultisigPubkeyIndex(&(msg->multisig), node->public_key) < 0) {
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Can't encode address");
|
||||||
fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script");
|
|
||||||
layoutHome();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uint8_t buf[32];
|
|
||||||
if (compile_script_multisig_hash(&(msg->multisig), buf) == 0) {
|
|
||||||
fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig script");
|
|
||||||
layoutHome();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ripemd160(buf, 32, buf + 1);
|
|
||||||
buf[0] = coin->address_type_p2sh; // multisig cointype
|
|
||||||
base58_encode_check(buf, 21, resp->address, sizeof(resp->address));
|
|
||||||
} else {
|
|
||||||
ecdsa_get_address(node->public_key, coin->address_type, resp->address, sizeof(resp->address));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg->has_show_display && msg->show_display) {
|
if (msg->has_show_display && msg->show_display) {
|
||||||
|
@ -249,6 +249,7 @@ void layoutAddress(const char *address, const char *desc)
|
|||||||
static unsigned char bitdata[QR_MAX_BITDATA];
|
static unsigned char bitdata[QR_MAX_BITDATA];
|
||||||
int a, i, j;
|
int a, i, j;
|
||||||
int side = qr_encode(QR_LEVEL_M, 0, address, 0, bitdata);
|
int side = qr_encode(QR_LEVEL_M, 0, address, 0, bitdata);
|
||||||
|
int startx;
|
||||||
|
|
||||||
if (side > 0 && side <= 29) {
|
if (side > 0 && side <= 29) {
|
||||||
oledInvert(0, 0, (side + 2) * 2, (side + 2) * 2);
|
oledInvert(0, 0, (side + 2) * 2, (side + 2) * 2);
|
||||||
@ -263,6 +264,20 @@ void layoutAddress(const char *address, const char *desc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
startx = 68;
|
||||||
|
} else if (side > 0 && side <= 60) {
|
||||||
|
oledInvert(0, 0, (side + 3), (side + 3));
|
||||||
|
for (i = 0; i < side; i++) {
|
||||||
|
for (j = 0; j< side; j++) {
|
||||||
|
a = j * side + i;
|
||||||
|
if (bitdata[a / 8] & (1 << (7 - a % 8))) {
|
||||||
|
oledClearPixel(2 + i, 2 + j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startx = side + 6;
|
||||||
|
} else {
|
||||||
|
startx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t addrlen = strlen(address);
|
uint32_t addrlen = strlen(address);
|
||||||
@ -273,12 +288,11 @@ void layoutAddress(const char *address, const char *desc)
|
|||||||
const char **str = split_message((const uint8_t *)address, addrlen, rowlen);
|
const char **str = split_message((const uint8_t *)address, addrlen, rowlen);
|
||||||
|
|
||||||
if (desc) {
|
if (desc) {
|
||||||
oledDrawString(68, 0 * 9, desc);
|
oledDrawString(startx, 0 * 9, desc);
|
||||||
|
}
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
oledDrawString(startx, (i+1) * 9 + 4, str[i]);
|
||||||
}
|
}
|
||||||
oledDrawString(68, 1 * 9 + 4, str[0]);
|
|
||||||
oledDrawString(68, 2 * 9 + 4, str[1]);
|
|
||||||
oledDrawString(68, 3 * 9 + 4, str[2]);
|
|
||||||
oledDrawString(68, 4 * 9 + 4, str[3]);
|
|
||||||
|
|
||||||
static const char *btnYes = "Continue";
|
static const char *btnYes = "Continue";
|
||||||
oledDrawString(OLED_WIDTH - fontCharWidth('\x06') - 1, OLED_HEIGHT - 8, "\x06");
|
oledDrawString(OLED_WIDTH - fontCharWidth('\x06') - 1, OLED_HEIGHT - 8, "\x06");
|
||||||
|
@ -33,7 +33,7 @@ PublicKey.xpub max_size:113
|
|||||||
GetAddress.address_n max_count:8
|
GetAddress.address_n max_count:8
|
||||||
GetAddress.coin_name max_size:17
|
GetAddress.coin_name max_size:17
|
||||||
|
|
||||||
Address.address max_size:41
|
Address.address max_size:60
|
||||||
|
|
||||||
EthereumGetAddress.address_n max_count:8
|
EthereumGetAddress.address_n max_count:8
|
||||||
EthereumAddress.address max_size:20
|
EthereumAddress.address max_size:20
|
||||||
|
@ -127,7 +127,7 @@ typedef struct _WipeDevice {
|
|||||||
} WipeDevice;
|
} WipeDevice;
|
||||||
|
|
||||||
typedef struct _Address {
|
typedef struct _Address {
|
||||||
char address[41];
|
char address[60];
|
||||||
} Address;
|
} Address;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -1215,7 +1215,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2];
|
|||||||
#define PublicKey_size (121 + HDNodeType_size)
|
#define PublicKey_size (121 + HDNodeType_size)
|
||||||
#define GetAddress_size (81 + MultisigRedeemScriptType_size)
|
#define GetAddress_size (81 + MultisigRedeemScriptType_size)
|
||||||
#define EthereumGetAddress_size 50
|
#define EthereumGetAddress_size 50
|
||||||
#define Address_size 43
|
#define Address_size 62
|
||||||
#define EthereumAddress_size 22
|
#define EthereumAddress_size 22
|
||||||
#define WipeDevice_size 0
|
#define WipeDevice_size 0
|
||||||
#define LoadDevice_size (326 + HDNodeType_size)
|
#define LoadDevice_size (326 + HDNodeType_size)
|
||||||
|
@ -12,7 +12,7 @@ TxInputType.address_n max_count:8
|
|||||||
TxInputType.prev_hash max_size:32
|
TxInputType.prev_hash max_size:32
|
||||||
TxInputType.script_sig max_size:1650
|
TxInputType.script_sig max_size:1650
|
||||||
|
|
||||||
TxOutputType.address max_size:41
|
TxOutputType.address max_size:54
|
||||||
TxOutputType.address_n max_count:8
|
TxOutputType.address_n max_count:8
|
||||||
TxOutputType.op_return_data max_size:80
|
TxOutputType.op_return_data max_size:80
|
||||||
|
|
||||||
|
@ -246,7 +246,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct _TxOutputType {
|
typedef struct _TxOutputType {
|
||||||
bool has_address;
|
bool has_address;
|
||||||
char address[41];
|
char address[54];
|
||||||
size_t address_n_count;
|
size_t address_n_count;
|
||||||
uint32_t address_n[8];
|
uint32_t address_n[8];
|
||||||
uint64_t amount;
|
uint64_t amount;
|
||||||
@ -409,9 +409,9 @@ extern const pb_field_t IdentityType_fields[7];
|
|||||||
#define CoinType_size 113
|
#define CoinType_size 113
|
||||||
#define MultisigRedeemScriptType_size 3741
|
#define MultisigRedeemScriptType_size 3741
|
||||||
#define TxInputType_size 5508
|
#define TxInputType_size 5508
|
||||||
#define TxOutputType_size 3934
|
#define TxOutputType_size 3947
|
||||||
#define TxOutputBinType_size 534
|
#define TxOutputBinType_size 534
|
||||||
#define TransactionType_size 11042
|
#define TransactionType_size 11055
|
||||||
#define TxRequestDetailsType_size 52
|
#define TxRequestDetailsType_size 52
|
||||||
#define TxRequestSerializedType_size 2132
|
#define TxRequestSerializedType_size 2132
|
||||||
#define IdentityType_size 416
|
#define IdentityType_size 416
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -32,6 +32,8 @@
|
|||||||
#include "messages.pb.h"
|
#include "messages.pb.h"
|
||||||
#include "types.pb.h"
|
#include "types.pb.h"
|
||||||
|
|
||||||
|
static const uint8_t segwit_header[2] = {0,1};
|
||||||
|
|
||||||
uint32_t op_push(uint32_t i, uint8_t *out) {
|
uint32_t op_push(uint32_t i, uint8_t *out) {
|
||||||
if (i < 0x4C) {
|
if (i < 0x4C) {
|
||||||
out[0] = i & 0xFF;
|
out[0] = i & 0xFF;
|
||||||
@ -56,95 +58,118 @@ uint32_t op_push(uint32_t i, uint8_t *out) {
|
|||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool compute_address(const CoinType *coin,
|
||||||
|
InputScriptType script_type,
|
||||||
|
const HDNode *node,
|
||||||
|
bool has_multisig, const MultisigRedeemScriptType *multisig,
|
||||||
|
char address[MAX_ADDR_SIZE]) {
|
||||||
|
|
||||||
|
uint8_t raw[32];
|
||||||
|
uint8_t digest[MAX_ADDR_RAW_SIZE];
|
||||||
|
size_t prelen;
|
||||||
|
|
||||||
|
if (has_multisig) {
|
||||||
|
if (cryptoMultisigPubkeyIndex(multisig, node->public_key) < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (compile_script_multisig_hash(multisig, digest) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (script_type == InputScriptType_SPENDWITNESS) {
|
||||||
|
// segwit p2wsh: script hash is single sha256
|
||||||
|
if (!coin->has_segwit || !coin->segwit) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!coin->has_address_type_p2wsh) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
prelen = address_prefix_bytes_len(coin->address_type_p2wsh);
|
||||||
|
address_write_prefix_bytes(coin->address_type_p2wsh, raw);
|
||||||
|
raw[prelen] = 0; // version byte
|
||||||
|
raw[prelen + 1] = 0; // always 0, see bip-142
|
||||||
|
memcpy(raw+prelen+2, digest, 32);
|
||||||
|
if (!base58_encode_check(raw, prelen + 34, address, MAX_ADDR_SIZE)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (script_type == InputScriptType_SPENDP2SHWITNESS) {
|
||||||
|
// segwit p2wsh encapsuled in p2sh address
|
||||||
|
if (!coin->has_segwit || !coin->segwit) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!coin->has_address_type_p2sh) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
raw[0] = 0; // push version
|
||||||
|
raw[1] = 32; // push 32 bytes
|
||||||
|
memcpy(raw+2, digest, 32); // push hash
|
||||||
|
sha256_Raw(raw, 34, digest);
|
||||||
|
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, address, MAX_ADDR_SIZE)) {
|
||||||
|
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, address, MAX_ADDR_SIZE)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (script_type == InputScriptType_SPENDWITNESS) {
|
||||||
|
// segwit p2wpkh: pubkey hash is ripemd160 of sha256
|
||||||
|
if (!coin->has_segwit || !coin->segwit) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!coin->has_address_type_p2wpkh) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
prelen = address_prefix_bytes_len(coin->address_type_p2wpkh);
|
||||||
|
address_write_prefix_bytes(coin->address_type_p2wpkh, raw);
|
||||||
|
raw[prelen] = 0; // version byte
|
||||||
|
raw[prelen + 1] = 0; // always 0, see bip-142
|
||||||
|
ecdsa_get_pubkeyhash(node->public_key, raw + prelen + 2);
|
||||||
|
if (!base58_encode_check(raw, prelen + 22, address, MAX_ADDR_SIZE)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (script_type == InputScriptType_SPENDP2SHWITNESS) {
|
||||||
|
// segwit p2wpkh embedded in p2sh
|
||||||
|
if (!coin->has_segwit || !coin->segwit) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!coin->has_address_type_p2sh) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
prelen = address_prefix_bytes_len(coin->address_type_p2sh);
|
||||||
|
raw[0] = 0; // version byte
|
||||||
|
raw[1] = 20; // push 20 bytes
|
||||||
|
ecdsa_get_pubkeyhash(node->public_key, raw + 2);
|
||||||
|
sha256_Raw(raw, 22, digest);
|
||||||
|
address_write_prefix_bytes(coin->address_type_p2sh, raw);
|
||||||
|
ripemd160(digest, 32, raw + prelen);
|
||||||
|
if (!base58_encode_check(raw, prelen + 20, address, MAX_ADDR_SIZE)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ecdsa_get_address(node->public_key, coin->address_type, address, MAX_ADDR_SIZE);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm)
|
int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm)
|
||||||
{
|
{
|
||||||
memset(out, 0, sizeof(TxOutputBinType));
|
memset(out, 0, sizeof(TxOutputBinType));
|
||||||
out->amount = in->amount;
|
out->amount = in->amount;
|
||||||
uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
|
uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
|
||||||
|
size_t addr_raw_len;
|
||||||
if (in->script_type == OutputScriptType_PAYTOADDRESS) {
|
|
||||||
|
|
||||||
// address_n provided-> change address -> calculate from address_n
|
|
||||||
if (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, NULL) == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 + address_prefix_bytes_len(coin->address_type), 20);
|
|
||||||
out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY
|
|
||||||
out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG
|
|
||||||
out->script_pubkey.size = 25;
|
|
||||||
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);
|
|
||||||
if (!in->has_multisig) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (compile_script_multisig_hash(&(in->multisig), buf) == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
address_write_prefix_bytes(coin->address_type_p2sh, addr_raw);
|
|
||||||
ripemd160(buf, 32, addr_raw + prefix_bytes);
|
|
||||||
if (needs_confirm) {
|
|
||||||
base58_encode_check(addr_raw, prefix_bytes + 20, in->address, sizeof(in->address));
|
|
||||||
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 + prefix_bytes, 20);
|
|
||||||
out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL
|
|
||||||
out->script_pubkey.size = 23;
|
|
||||||
return 23;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in->script_type == OutputScriptType_PAYTOOPRETURN) {
|
if (in->script_type == OutputScriptType_PAYTOOPRETURN) {
|
||||||
if (in->amount != 0) return 0; // only 0 satoshi allowed for OP_RETURN
|
// only 0 satoshi allowed for OP_RETURN
|
||||||
|
if (in->amount != 0) {
|
||||||
|
return 0; // failed to compile output
|
||||||
|
}
|
||||||
uint32_t r = 0;
|
uint32_t r = 0;
|
||||||
out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN
|
out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN
|
||||||
r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r);
|
r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r);
|
||||||
@ -153,7 +178,85 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
if (in->address_n_count > 0) {
|
||||||
|
HDNode node;
|
||||||
|
InputScriptType input_script_type;
|
||||||
|
|
||||||
|
switch (in->script_type) {
|
||||||
|
case OutputScriptType_PAYTOADDRESS:
|
||||||
|
input_script_type = InputScriptType_SPENDADDRESS;
|
||||||
|
break;
|
||||||
|
case OutputScriptType_PAYTOMULTISIG:
|
||||||
|
input_script_type = InputScriptType_SPENDMULTISIG;
|
||||||
|
break;
|
||||||
|
case OutputScriptType_PAYTOWITNESS:
|
||||||
|
input_script_type = InputScriptType_SPENDWITNESS;
|
||||||
|
break;
|
||||||
|
case OutputScriptType_PAYTOP2SHWITNESS:
|
||||||
|
input_script_type = InputScriptType_SPENDP2SHWITNESS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0; // failed to compile output
|
||||||
|
}
|
||||||
|
memcpy(&node, root, sizeof(HDNode));
|
||||||
|
if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count, NULL) == 0) {
|
||||||
|
return 0; // failed to compile output
|
||||||
|
}
|
||||||
|
hdnode_fill_public_key(&node);
|
||||||
|
if (!compute_address(coin, input_script_type, &node,
|
||||||
|
in->has_multisig, &in->multisig,
|
||||||
|
in->address)) {
|
||||||
|
return 0; // failed to compile output
|
||||||
|
}
|
||||||
|
} else if (!in->has_address) {
|
||||||
|
return 0; // failed to compile output
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_raw_len = base58_decode_check(in->address, addr_raw, MAX_ADDR_RAW_SIZE);
|
||||||
|
size_t prefix_len;
|
||||||
|
if (address_check_prefix(addr_raw, coin->address_type) // p2pkh
|
||||||
|
&& addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type))) {
|
||||||
|
|
||||||
|
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 + prefix_len, 20);
|
||||||
|
out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY
|
||||||
|
out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG
|
||||||
|
out->script_pubkey.size = 25;
|
||||||
|
} else if (address_check_prefix(addr_raw, coin->address_type_p2sh) // p2sh
|
||||||
|
&& addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_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 + prefix_len, 20);
|
||||||
|
out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL
|
||||||
|
out->script_pubkey.size = 23;
|
||||||
|
} else if (address_check_prefix(addr_raw, coin->address_type_p2wpkh)
|
||||||
|
&& addr_raw_len == 22 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2wpkh))
|
||||||
|
&& addr_raw[prefix_len] == 0 && addr_raw[prefix_len + 1] == 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 + prefix_len + 2, 20);
|
||||||
|
out->script_pubkey.size = 22;
|
||||||
|
} else if (address_check_prefix(addr_raw, coin->address_type_p2wsh)
|
||||||
|
&& addr_raw_len == 34 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2wsh))
|
||||||
|
&& addr_raw[prefix_len] == 0 && addr_raw[prefix_len + 1] == 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 + prefix_len + 2, 32);
|
||||||
|
out->script_pubkey.size = 34;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needs_confirm) {
|
||||||
|
layoutConfirmOutput(coin, in);
|
||||||
|
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
|
||||||
|
return -1; // user aborted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out->script_pubkey.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out)
|
uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out)
|
||||||
@ -259,16 +362,64 @@ uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uin
|
|||||||
|
|
||||||
// tx methods
|
// tx methods
|
||||||
|
|
||||||
|
uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
sha256_Update(ctx, &(input->prev_hash.bytes[31 - i]), 1);
|
||||||
|
}
|
||||||
|
sha256_Update(ctx, (const uint8_t *)&input->prev_index, 4);
|
||||||
|
return 36;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tx_script_hash(SHA256_CTX *ctx, uint32_t size, const uint8_t *data)
|
||||||
|
{
|
||||||
|
int r = ser_length_hash(ctx, size);
|
||||||
|
sha256_Update(ctx, data, size);
|
||||||
|
return r + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tx_sequence_hash(SHA256_CTX *ctx, const TxInputType *input)
|
||||||
|
{
|
||||||
|
sha256_Update(ctx, (const uint8_t *)&input->sequence, 4);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tx_output_hash(SHA256_CTX *ctx, const TxOutputBinType *output)
|
||||||
|
{
|
||||||
|
uint32_t r = 0;
|
||||||
|
sha256_Update(ctx, (const uint8_t *)&output->amount, 8); r += 8;
|
||||||
|
r += tx_script_hash(ctx, output->script_pubkey.size, output->script_pubkey.bytes);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out)
|
||||||
|
{
|
||||||
|
int r = ser_length(size, out);
|
||||||
|
memcpy(out + r, data, size);
|
||||||
|
return r + size;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out)
|
uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out)
|
||||||
{
|
{
|
||||||
|
int r = 4;
|
||||||
memcpy(out, &(tx->version), 4);
|
memcpy(out, &(tx->version), 4);
|
||||||
return 4 + ser_length(tx->inputs_len, out + 4);
|
if (tx->is_segwit) {
|
||||||
|
memcpy(out + r, segwit_header, 2);
|
||||||
|
r += 2;
|
||||||
|
}
|
||||||
|
return r + ser_length(tx->inputs_len, out + r);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t tx_serialize_header_hash(TxStruct *tx)
|
uint32_t tx_serialize_header_hash(TxStruct *tx)
|
||||||
{
|
{
|
||||||
|
int r = 4;
|
||||||
sha256_Update(&(tx->ctx), (const uint8_t *)&(tx->version), 4);
|
sha256_Update(&(tx->ctx), (const uint8_t *)&(tx->version), 4);
|
||||||
return 4 + ser_length_hash(&(tx->ctx), tx->inputs_len);
|
if (tx->is_segwit) {
|
||||||
|
sha256_Update(&(tx->ctx), segwit_header, 2);
|
||||||
|
r += 2;
|
||||||
|
}
|
||||||
|
return r + ser_length_hash(&(tx->ctx), tx->inputs_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out)
|
uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out)
|
||||||
@ -287,8 +438,7 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out
|
|||||||
}
|
}
|
||||||
r += 32;
|
r += 32;
|
||||||
memcpy(out + r, &input->prev_index, 4); r += 4;
|
memcpy(out + r, &input->prev_index, 4); r += 4;
|
||||||
r += ser_length(input->script_sig.size, out + r);
|
r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r);
|
||||||
memcpy(out + r, input->script_sig.bytes, input->script_sig.size); r += input->script_sig.size;
|
|
||||||
memcpy(out + r, &input->sequence, 4); r += 4;
|
memcpy(out + r, &input->sequence, 4); r += 4;
|
||||||
|
|
||||||
tx->have_inputs++;
|
tx->have_inputs++;
|
||||||
@ -299,7 +449,6 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out
|
|||||||
|
|
||||||
uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input)
|
uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
if (tx->have_inputs >= tx->inputs_len) {
|
if (tx->have_inputs >= tx->inputs_len) {
|
||||||
// already got all inputs
|
// already got all inputs
|
||||||
return 0;
|
return 0;
|
||||||
@ -308,14 +457,9 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input)
|
|||||||
if (tx->have_inputs == 0) {
|
if (tx->have_inputs == 0) {
|
||||||
r += tx_serialize_header_hash(tx);
|
r += tx_serialize_header_hash(tx);
|
||||||
}
|
}
|
||||||
for (i = 0; i < 32; i++) {
|
r += tx_prevout_hash(&(tx->ctx), input);
|
||||||
sha256_Update(&(tx->ctx), &(input->prev_hash.bytes[31 - i]), 1);
|
r += tx_script_hash(&(tx->ctx), input->script_sig.size, input->script_sig.bytes);
|
||||||
}
|
r += tx_sequence_hash(&(tx->ctx), input);
|
||||||
r += 32;
|
|
||||||
sha256_Update(&(tx->ctx), (const uint8_t *)&input->prev_index, 4); r += 4;
|
|
||||||
r += ser_length_hash(&(tx->ctx), input->script_sig.size);
|
|
||||||
sha256_Update(&(tx->ctx), input->script_sig.bytes, input->script_sig.size); r += input->script_sig.size;
|
|
||||||
sha256_Update(&(tx->ctx), (const uint8_t *)&input->sequence, 4); r += 4;
|
|
||||||
|
|
||||||
tx->have_inputs++;
|
tx->have_inputs++;
|
||||||
tx->size += r;
|
tx->size += r;
|
||||||
@ -372,10 +516,10 @@ uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_
|
|||||||
r += tx_serialize_middle(tx, out + r);
|
r += tx_serialize_middle(tx, out + r);
|
||||||
}
|
}
|
||||||
memcpy(out + r, &output->amount, 8); r += 8;
|
memcpy(out + r, &output->amount, 8); r += 8;
|
||||||
r += ser_length(output->script_pubkey.size, out + r);
|
r += tx_serialize_script(output->script_pubkey.size, output->script_pubkey.bytes, out + r);
|
||||||
memcpy(out + r, output->script_pubkey.bytes, output->script_pubkey.size); r+= output->script_pubkey.size;
|
|
||||||
tx->have_outputs++;
|
tx->have_outputs++;
|
||||||
if (tx->have_outputs == tx->outputs_len) {
|
if (tx->have_outputs == tx->outputs_len
|
||||||
|
&& !tx->is_segwit) {
|
||||||
r += tx_serialize_footer(tx, out + r);
|
r += tx_serialize_footer(tx, out + r);
|
||||||
}
|
}
|
||||||
tx->size += r;
|
tx->size += r;
|
||||||
@ -396,11 +540,10 @@ uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output)
|
|||||||
if (tx->have_outputs == 0) {
|
if (tx->have_outputs == 0) {
|
||||||
r += tx_serialize_middle_hash(tx);
|
r += tx_serialize_middle_hash(tx);
|
||||||
}
|
}
|
||||||
sha256_Update(&(tx->ctx), (const uint8_t *)&output->amount, 8); r += 8;
|
r += tx_output_hash(&(tx->ctx), output);
|
||||||
r += ser_length_hash(&(tx->ctx), output->script_pubkey.size);
|
|
||||||
sha256_Update(&(tx->ctx), output->script_pubkey.bytes, output->script_pubkey.size); r+= output->script_pubkey.size;
|
|
||||||
tx->have_outputs++;
|
tx->have_outputs++;
|
||||||
if (tx->have_outputs == tx->outputs_len) {
|
if (tx->have_outputs == tx->outputs_len
|
||||||
|
&& !tx->is_segwit) {
|
||||||
r += tx_serialize_footer_hash(tx);
|
r += tx_serialize_footer_hash(tx);
|
||||||
}
|
}
|
||||||
tx->size += r;
|
tx->size += r;
|
||||||
@ -439,6 +582,7 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v
|
|||||||
tx->extra_data_len = extra_data_len;
|
tx->extra_data_len = extra_data_len;
|
||||||
tx->extra_data_received = 0;
|
tx->extra_data_received = 0;
|
||||||
tx->size = 0;
|
tx->size = 0;
|
||||||
|
tx->is_segwit = false;
|
||||||
sha256_Init(&(tx->ctx));
|
sha256_Init(&(tx->ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ typedef struct {
|
|||||||
|
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t lock_time;
|
uint32_t lock_time;
|
||||||
bool add_hash_type;
|
bool add_hash_type, is_segwit;
|
||||||
|
|
||||||
uint32_t have_inputs;
|
uint32_t have_inputs;
|
||||||
uint32_t have_outputs;
|
uint32_t have_outputs;
|
||||||
@ -45,12 +45,21 @@ typedef struct {
|
|||||||
SHA256_CTX ctx;
|
SHA256_CTX ctx;
|
||||||
} TxStruct;
|
} TxStruct;
|
||||||
|
|
||||||
|
bool compute_address(const CoinType *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]);
|
||||||
uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out);
|
uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out);
|
||||||
uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out);
|
uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out);
|
||||||
uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash);
|
uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash);
|
||||||
uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out);
|
uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out);
|
||||||
uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out);
|
uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out);
|
||||||
int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm);
|
int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm);
|
||||||
|
|
||||||
|
uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input);
|
||||||
|
uint32_t tx_script_hash(SHA256_CTX *ctx, uint32_t size, const uint8_t *data);
|
||||||
|
uint32_t tx_sequence_hash(SHA256_CTX *ctx, const TxInputType *input);
|
||||||
|
uint32_t tx_output_hash(SHA256_CTX *ctx, const TxOutputBinType *output);
|
||||||
|
uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out);
|
||||||
|
|
||||||
|
uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out);
|
||||||
uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out);
|
uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out);
|
||||||
uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out);
|
uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user