1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-25 07:48:10 +00:00
trezor-firmware/firmware/transaction.c

843 lines
25 KiB
C
Raw Normal View History

2014-04-29 12:26:51 +00:00
/*
* This file is part of the TREZOR project, https://trezor.io/
2014-04-29 12:26:51 +00:00
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "transaction.h"
#include "ecdsa.h"
#include "coins.h"
#include "util.h"
#include "debug.h"
#include "protect.h"
#include "layout2.h"
#include "crypto.h"
#include "ripemd160.h"
#include "base58.h"
#include "address.h"
2014-04-29 12:26:51 +00:00
#include "messages.pb.h"
2014-12-21 18:39:20 +00:00
#include "types.pb.h"
#include "segwit_addr.h"
2018-01-04 19:18:34 +00:00
#include "cash_addr.h"
#define SEGWIT_VERSION_0 0
2014-04-29 12:26:51 +00:00
2018-01-04 19:18:34 +00:00
#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 */
#define TXSIZE_OUTPUT 8
/* size of a pubkey */
#define TXSIZE_PUBKEY 33
/* size of a DER signature (3 type bytes, 3 len bytes, 33 R, 32 S, 1 sighash */
#define TXSIZE_SIGNATURE 72
/* size of a multiscript without pubkey (1 M, 1 N, 1 checksig) */
#define TXSIZE_MULTISIGSCRIPT 3
/* size of a p2wpkh script (1 version, 1 push, 20 hash) */
#define TXSIZE_WITNESSPKHASH 22
/* size of a p2wsh script (1 version, 1 push, 32 hash) */
#define TXSIZE_WITNESSSCRIPT 34
/* size of a p2pkh script (dup, hash, push, 20 pubkeyhash, equal, checksig) */
#define TXSIZE_P2PKHASH 25
/* size of a p2sh script (hash, push, 20 scripthash, equal) */
#define TXSIZE_P2SCRIPT 23
2017-12-18 16:49:17 +00:00
/* size of a Decred witness (without script): 8 amount, 4 block height, 4 block index */
#define TXSIZE_DECRED_WITNESS 16
2016-04-29 20:15:55 +00:00
static const uint8_t segwit_header[2] = {0,1};
2017-12-18 21:33:58 +00:00
static inline uint32_t op_push_size(uint32_t i) {
if (i < 0x4C) {
return 1;
}
if (i < 0x100) {
return 2;
}
if (i < 0x10000) {
return 3;
}
return 5;
}
2014-04-29 12:26:51 +00:00
uint32_t op_push(uint32_t i, uint8_t *out) {
if (i < 0x4C) {
out[0] = i & 0xFF;
return 1;
}
if (i < 0x100) {
2014-04-29 12:26:51 +00:00
out[0] = 0x4C;
out[1] = i & 0xFF;
return 2;
}
if (i < 0x10000) {
2014-04-29 12:26:51 +00:00
out[0] = 0x4D;
out[1] = i & 0xFF;
out[2] = (i >> 8) & 0xFF;
return 3;
}
out[0] = 0x4E;
out[1] = i & 0xFF;
out[2] = (i >> 8) & 0xFF;
out[3] = (i >> 16) & 0xFF;
out[4] = (i >> 24) & 0xFF;
return 5;
}
bool compute_address(const CoinInfo *coin,
InputScriptType script_type,
const HDNode *node,
bool has_multisig, const MultisigRedeemScriptType *multisig,
char address[MAX_ADDR_SIZE]) {
uint8_t raw[MAX_ADDR_RAW_SIZE];
uint8_t digest[32];
size_t prelen;
if (has_multisig) {
if (cryptoMultisigPubkeyIndex(coin, multisig, node->public_key) < 0) {
return 0;
}
if (compile_script_multisig_hash(coin, multisig, digest) == 0) {
return 0;
}
if (script_type == InputScriptType_SPENDWITNESS) {
// segwit p2wsh: script hash is single sha256
if (!coin->has_segwit || !coin->bech32_prefix) {
return 0;
}
if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 32)) {
return 0;
}
} else if (script_type == InputScriptType_SPENDP2SHWITNESS) {
// segwit p2wsh encapsuled in p2sh address
if (!coin->has_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
2018-04-03 14:25:06 +00:00
hasher_Raw(coin->curve->hasher_pubkey, 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);
2018-04-03 14:25:06 +00:00
if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, address, MAX_ADDR_SIZE)) {
return 0;
}
2018-01-04 19:18:34 +00:00
} 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);
address_write_prefix_bytes(coin->address_type_p2sh, raw);
ripemd160(digest, 32, raw + prelen);
2018-04-03 14:25:06 +00:00
if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, 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->bech32_prefix) {
return 0;
}
2018-04-03 14:25:06 +00:00
ecdsa_get_pubkeyhash(node->public_key, coin->curve->hasher_pubkey, digest);
if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 20)) {
return 0;
}
} else if (script_type == InputScriptType_SPENDP2SHWITNESS) {
// segwit p2wpkh embedded in p2sh
if (!coin->has_segwit) {
return 0;
}
if (!coin->has_address_type_p2sh) {
return 0;
}
2018-04-03 14:25:06 +00:00
ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, coin->curve->hasher_pubkey, coin->curve->hasher_base58, address, MAX_ADDR_SIZE);
2018-01-04 19:18:34 +00:00
} else if (coin->cashaddr_prefix) {
2018-04-05 09:56:25 +00:00
ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160, coin->curve->hasher_pubkey, raw);
2018-01-04 19:18:34 +00:00
if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) {
return 0;
}
} else {
2018-04-03 14:25:06 +00:00
ecdsa_get_address(node->public_key, coin->address_type, coin->curve->hasher_pubkey, coin->curve->hasher_base58, address, MAX_ADDR_SIZE);
}
return 1;
}
int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm)
2014-04-29 12:26:51 +00:00
{
memset(out, 0, sizeof(TxOutputBinType));
out->amount = in->amount;
2017-12-10 19:22:31 +00:00
out->decred_script_version = in->decred_script_version;
uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
2016-12-28 18:16:50 +00:00
size_t addr_raw_len;
if (in->script_type == OutputScriptType_PAYTOOPRETURN) {
// only 0 satoshi allowed for OP_RETURN
if (in->amount != 0) {
return 0; // failed to compile output
}
if (needs_confirm) {
layoutConfirmOpReturn(in->op_return_data.bytes, in->op_return_data.size);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return -1; // user aborted
}
}
uint32_t r = 0;
out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN
r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r);
memcpy(out->script_pubkey.bytes + r, in->op_return_data.bytes, in->op_return_data.size); r += in->op_return_data.size;
out->script_pubkey.size = r;
return r;
}
if (in->address_n_count > 0) {
static CONFIDENTIAL 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
2014-04-29 12:26:51 +00:00
}
} else if (!in->has_address) {
return 0; // failed to compile output
}
2018-04-03 14:25:06 +00:00
addr_raw_len = base58_decode_check(in->address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE);
size_t prefix_len;
if (coin->has_address_type // p2pkh
&& addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type))
&& address_check_prefix(addr_raw, coin->address_type)) {
2014-04-29 12:26:51 +00:00
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);
2014-04-29 12:26:51 +00:00
out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY
out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG
out->script_pubkey.size = 25;
} else if (coin->has_address_type_p2sh // p2sh
&& addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2sh))
&& address_check_prefix(addr_raw, 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);
2014-04-29 12:26:51 +00:00
out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL
out->script_pubkey.size = 23;
2018-01-04 19:18:34 +00:00
} 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)) {
return 0;
}
// segwit:
// push 1 byte version id (opcode OP_0 = 0, OP_i = 80+i)
// push addr_raw (segwit_addr_decode makes sure addr_raw_len is at most 40)
out->script_pubkey.bytes[0] = witver == 0 ? 0 : 80 + witver;
out->script_pubkey.bytes[1] = addr_raw_len;
memcpy(out->script_pubkey.bytes + 2, addr_raw, addr_raw_len);
out->script_pubkey.size = addr_raw_len + 2;
} else {
return 0;
2014-04-29 12:26:51 +00:00
}
if (needs_confirm) {
layoutConfirmOutput(coin, in);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return -1; // user aborted
}
2015-02-04 19:04:59 +00:00
}
return out->script_pubkey.size;
2014-04-29 12:26:51 +00:00
}
uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out)
2014-04-29 12:26:51 +00:00
{
if (coinByAddressType(address_type)) { // valid coin type
out[0] = 0x76; // OP_DUP
out[1] = 0xA9; // OP_HASH_160
out[2] = 0x14; // pushing 20 bytes
memcpy(out + 3, pubkeyhash, 20);
out[23] = 0x88; // OP_EQUALVERIFY
out[24] = 0xAC; // OP_CHECKSIG
return 25;
} else {
return 0; // unsupported
}
}
2014-12-06 18:12:55 +00:00
// if out == NULL just compute the length
uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *out)
2014-12-06 18:12:55 +00:00
{
if (!multisig->has_m) return 0;
2014-12-16 15:50:12 +00:00
const uint32_t m = multisig->m;
const uint32_t n = multisig->pubkeys_count;
2014-12-10 18:50:10 +00:00
if (m < 1 || m > 15) return 0;
if (n < 1 || n > 15) return 0;
2017-07-23 20:20:51 +00:00
uint32_t r = 0;
2014-12-06 18:12:55 +00:00
if (out) {
out[r] = 0x50 + m; r++;
2017-07-23 20:20:51 +00:00
for (uint32_t i = 0; i < n; i++) {
2014-12-13 19:33:49 +00:00
out[r] = 33; r++; // OP_PUSH 33
const uint8_t *pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i]));
if (!pubkey) return 0;
memcpy(out + r, pubkey, 33); r += 33;
2014-12-06 18:12:55 +00:00
}
out[r] = 0x50 + n; r++;
out[r] = 0xAE; r++; // OP_CHECKMULTISIG
} else {
2014-12-13 19:33:49 +00:00
r = 1 + 34 * n + 2;
2014-12-06 18:12:55 +00:00
}
return r;
}
uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *hash)
2014-12-10 17:04:51 +00:00
{
if (!multisig->has_m) return 0;
2014-12-16 15:50:12 +00:00
const uint32_t m = multisig->m;
const uint32_t n = multisig->pubkeys_count;
2014-12-10 18:50:10 +00:00
if (m < 1 || m > 15) return 0;
if (n < 1 || n > 15) return 0;
2014-12-10 17:04:51 +00:00
Hasher hasher;
2018-04-03 14:25:06 +00:00
hasher_Init(&hasher, coin->curve->hasher_pubkey);
2014-12-10 17:04:51 +00:00
2014-12-21 17:58:56 +00:00
uint8_t d[2];
d[0] = 0x50 + m; hasher_Update(&hasher, d, 1);
2017-07-23 20:20:51 +00:00
for (uint32_t i = 0; i < n; i++) {
d[0] = 33; hasher_Update(&hasher, d, 1); // OP_PUSH 33
const uint8_t *pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i]));
if (!pubkey) return 0;
hasher_Update(&hasher, pubkey, 33);
2014-12-10 17:04:51 +00:00
}
2014-12-21 17:58:56 +00:00
d[0] = 0x50 + n;
d[1] = 0xAE;
hasher_Update(&hasher, d, 2);
2014-12-10 17:04:51 +00:00
hasher_Final(&hasher, hash);
2014-12-10 17:04:51 +00:00
return 1;
}
2017-07-25 14:24:24 +00:00
uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out)
2014-04-29 12:26:51 +00:00
{
uint32_t r = 0;
r += op_push(signature_len + 1, out + r);
memcpy(out + r, signature, signature_len); r += signature_len;
2017-07-25 14:24:24 +00:00
out[r] = sighash; r++;
2014-04-29 12:26:51 +00:00
r += op_push(pubkey_len, out + r);
memcpy(out + r, pubkey, pubkey_len); r += pubkey_len;
return r;
}
uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out)
2014-12-06 18:12:55 +00:00
{
2017-07-23 20:20:51 +00:00
uint32_t r = 0;
2017-12-20 20:38:36 +00:00
if (!coin->decred) {
// Decred fixed the off-by-one bug
out[r] = 0x00; r++;
}
2017-07-23 20:20:51 +00:00
for (uint32_t i = 0; i < multisig->signatures_count; i++) {
2014-12-06 18:12:55 +00:00
if (multisig->signatures[i].size == 0) {
continue;
}
r += op_push(multisig->signatures[i].size + 1, out + r);
memcpy(out + r, multisig->signatures[i].bytes, multisig->signatures[i].size); r += multisig->signatures[i].size;
2017-07-25 14:24:24 +00:00
out[r] = sighash; r++;
2014-12-06 18:12:55 +00:00
}
uint32_t script_len = compile_script_multisig(coin, multisig, 0);
if (script_len == 0) {
return 0;
}
2014-12-06 18:12:55 +00:00
r += op_push(script_len, out + r);
r += compile_script_multisig(coin, multisig, out + r);
2014-12-06 18:12:55 +00:00
return r;
}
2014-04-29 12:26:51 +00:00
// tx methods
uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input)
2016-04-29 19:17:06 +00:00
{
2017-07-23 20:20:51 +00:00
for (int i = 0; i < 32; i++) {
hasher_Update(hasher, &(input->prev_hash.bytes[31 - i]), 1);
2016-04-29 19:17:06 +00:00
}
hasher_Update(hasher, (const uint8_t *)&input->prev_index, 4);
2016-04-29 19:17:06 +00:00
return 36;
}
uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data)
2016-04-29 20:15:55 +00:00
{
int r = ser_length_hash(hasher, size);
hasher_Update(hasher, data, size);
2016-04-29 20:15:55 +00:00
return r + size;
}
uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input)
2016-04-29 19:17:06 +00:00
{
hasher_Update(hasher, (const uint8_t *)&input->sequence, 4);
2016-04-29 19:17:06 +00:00
return 4;
}
2017-12-10 19:22:31 +00:00
uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred)
2016-04-29 19:17:06 +00:00
{
uint32_t r = 0;
hasher_Update(hasher, (const uint8_t *)&output->amount, 8); r += 8;
2017-12-10 19:22:31 +00:00
if (decred) {
uint16_t script_version = output->decred_script_version & 0xFFFF;
hasher_Update(hasher, (const uint8_t *)&script_version, 2); r += 2;
}
r += tx_script_hash(hasher, output->script_pubkey.size, output->script_pubkey.bytes);
2016-04-29 19:17:06 +00:00
return r;
}
2016-04-29 20:15:55 +00:00
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;
}
2014-04-29 12:26:51 +00:00
uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out)
{
2016-04-29 20:15:55 +00:00
int r = 4;
2018-06-12 13:03:17 +00:00
if (tx->overwintered) {
uint32_t ver = tx->version | TX_OVERWINTERED;
memcpy(out, &ver, 4);
uint32_t version_group_id = 0x03c48270;
memcpy(out + 4, &version_group_id, 4);
r += 4;
} else {
memcpy(out, &(tx->version), 4);
if (tx->is_segwit) {
memcpy(out + r, segwit_header, 2);
r += 2;
}
2016-04-29 20:15:55 +00:00
}
return r + ser_length(tx->inputs_len, out + r);
2014-04-29 12:26:51 +00:00
}
2014-12-21 18:39:20 +00:00
uint32_t tx_serialize_header_hash(TxStruct *tx)
{
2016-04-29 20:15:55 +00:00
int r = 4;
2018-06-12 13:03:17 +00:00
if (tx->overwintered) {
uint32_t ver = tx->version | TX_OVERWINTERED;
hasher_Update(&(tx->hasher), (const uint8_t *)&ver, 4);
uint32_t version_group_id = 0x03c48270;
hasher_Update(&(tx->hasher), (const uint8_t *)&version_group_id, 4);
r += 4;
} else {
hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version), 4);
if (tx->is_segwit) {
hasher_Update(&(tx->hasher), segwit_header, 2);
r += 2;
}
2016-04-29 20:15:55 +00:00
}
return r + ser_length_hash(&(tx->hasher), tx->inputs_len);
2014-12-21 18:39:20 +00:00
}
uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out)
2014-04-29 12:26:51 +00:00
{
if (tx->have_inputs >= tx->inputs_len) {
// already got all inputs
return 0;
}
uint32_t r = 0;
if (tx->have_inputs == 0) {
r += tx_serialize_header(tx, out + r);
}
2017-07-23 20:20:51 +00:00
for (int i = 0; i < 32; i++) {
2014-12-21 18:39:20 +00:00
*(out + r + i) = input->prev_hash.bytes[31 - i];
}
r += 32;
memcpy(out + r, &input->prev_index, 4); r += 4;
2017-12-10 19:22:31 +00:00
if (tx->is_decred) {
uint8_t tree = input->decred_tree & 0xFF;
out[r++] = tree;
} else {
r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r);
}
2014-12-21 18:39:20 +00:00
memcpy(out + r, &input->sequence, 4); r += 4;
tx->have_inputs++;
tx->size += r;
return r;
}
uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input)
{
if (tx->have_inputs >= tx->inputs_len) {
// already got all inputs
return 0;
}
uint32_t r = 0;
if (tx->have_inputs == 0) {
r += tx_serialize_header_hash(tx);
}
r += tx_prevout_hash(&(tx->hasher), input);
2017-12-10 19:22:31 +00:00
if (tx->is_decred) {
uint8_t tree = input->decred_tree & 0xFF;
hasher_Update(&(tx->hasher), (const uint8_t *)&(tree), 1); r++;
} else {
r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes);
}
r += tx_sequence_hash(&(tx->hasher), input);
2014-04-29 12:26:51 +00:00
tx->have_inputs++;
tx->size += r;
return r;
}
2017-12-10 19:22:31 +00:00
uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out)
{
static const uint64_t amount = 0;
static const uint32_t block_height = 0x00000000;
static const uint32_t block_index = 0xFFFFFFFF;
if (tx->have_inputs >= tx->inputs_len) {
// already got all inputs
return 0;
}
uint32_t r = 0;
if (tx->have_inputs == 0) {
r += ser_length(tx->inputs_len, out + r);
}
memcpy(out + r, &amount, 8); r += 8;
memcpy(out + r, &block_height, 4); r += 4;
memcpy(out + r, &block_index, 4); r += 4;
r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r);
tx->have_inputs++;
tx->size += r;
return r;
}
uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input)
{
if (tx->have_inputs >= tx->inputs_len) {
// already got all inputs
return 0;
}
uint32_t r = 0;
if (tx->have_inputs == 0) {
r += tx_serialize_header_hash(tx);
}
if (input == NULL) {
r += ser_length_hash(&(tx->hasher), 0);
} else {
r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes);
}
tx->have_inputs++;
tx->size += r;
return r;
}
2014-04-29 12:26:51 +00:00
uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out)
{
return ser_length(tx->outputs_len, out);
}
2014-12-21 18:39:20 +00:00
uint32_t tx_serialize_middle_hash(TxStruct *tx)
{
return ser_length_hash(&(tx->hasher), tx->outputs_len);
2014-12-21 18:39:20 +00:00
}
2014-04-29 12:26:51 +00:00
uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out)
{
memcpy(out, &(tx->lock_time), 4);
2018-06-12 13:03:17 +00:00
if (tx->overwintered) {
memcpy(out + 4, &(tx->expiry), 4);
out[8] = 0x00; // nJoinSplit
return 9;
}
2017-12-10 19:22:31 +00:00
if (tx->is_decred) {
memcpy(out + 4, &(tx->expiry), 4);
2017-12-10 19:22:31 +00:00
return 8;
}
return 4;
2014-04-29 12:26:51 +00:00
}
2014-12-21 18:39:20 +00:00
uint32_t tx_serialize_footer_hash(TxStruct *tx)
{
hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->lock_time), 4);
2018-06-12 13:03:17 +00:00
if (tx->overwintered) {
hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4);
hasher_Update(&(tx->hasher), (const uint8_t *)"\x00", 1); // nJoinSplit
return 9;
}
2017-12-10 19:22:31 +00:00
if (tx->is_decred) {
hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4);
2017-12-10 19:22:31 +00:00
return 8;
}
return 4;
2014-12-21 18:39:20 +00:00
}
uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out)
2014-04-29 12:26:51 +00:00
{
if (tx->have_inputs < tx->inputs_len) {
// not all inputs provided
return 0;
}
if (tx->have_outputs >= tx->outputs_len) {
// already got all outputs
return 0;
}
uint32_t r = 0;
if (tx->have_outputs == 0) {
r += tx_serialize_middle(tx, out + r);
}
2014-12-21 18:39:20 +00:00
memcpy(out + r, &output->amount, 8); r += 8;
2017-12-10 19:22:31 +00:00
if (tx->is_decred) {
uint16_t script_version = output->decred_script_version & 0xFFFF;
memcpy(out + r, &script_version, 2); r += 2;
}
2016-04-29 20:15:55 +00:00
r += tx_serialize_script(output->script_pubkey.size, output->script_pubkey.bytes, out + r);
2014-04-29 12:26:51 +00:00
tx->have_outputs++;
if (tx->have_outputs == tx->outputs_len
&& !tx->is_segwit) {
2014-04-29 12:26:51 +00:00
r += tx_serialize_footer(tx, out + r);
}
tx->size += r;
return r;
}
2014-12-21 18:39:20 +00:00
uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output)
{
if (tx->have_inputs < tx->inputs_len) {
// not all inputs provided
return 0;
}
if (tx->have_outputs >= tx->outputs_len) {
// already got all outputs
return 0;
}
uint32_t r = 0;
if (tx->have_outputs == 0) {
r += tx_serialize_middle_hash(tx);
}
2017-12-10 19:22:31 +00:00
r += tx_output_hash(&(tx->hasher), output, tx->is_decred);
2014-12-21 18:39:20 +00:00
tx->have_outputs++;
if (tx->have_outputs == tx->outputs_len
&& !tx->is_segwit) {
2014-12-21 18:39:20 +00:00
r += tx_serialize_footer_hash(tx);
}
tx->size += r;
return r;
}
uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen)
{
if (tx->have_inputs < tx->inputs_len) {
// not all inputs provided
return 0;
}
if (tx->have_outputs < tx->outputs_len) {
// not all inputs provided
return 0;
}
if (tx->extra_data_received + datalen > tx->extra_data_len) {
// we are receiving too much data
return 0;
}
hasher_Update(&(tx->hasher), data, datalen);
tx->extra_data_received += datalen;
tx->size += datalen;
return datalen;
}
2018-06-12 13:03:17 +00:00
void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered)
2014-04-29 12:26:51 +00:00
{
tx->inputs_len = inputs_len;
tx->outputs_len = outputs_len;
tx->version = version;
tx->lock_time = lock_time;
2018-06-07 11:17:51 +00:00
tx->expiry = expiry;
2014-04-29 12:26:51 +00:00
tx->have_inputs = 0;
tx->have_outputs = 0;
tx->extra_data_len = extra_data_len;
tx->extra_data_received = 0;
2014-04-29 12:26:51 +00:00
tx->size = 0;
tx->is_segwit = false;
2017-12-10 19:22:31 +00:00
tx->is_decred = false;
2018-06-12 13:03:17 +00:00
tx->overwintered = overwintered;
2018-04-03 14:25:06 +00:00
hasher_Init(&(tx->hasher), hasher_sign);
2014-04-29 12:26:51 +00:00
}
void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse)
{
2018-04-03 14:25:06 +00:00
hasher_Final(&(t->hasher), hash);
2014-04-29 12:26:51 +00:00
if (!reverse) return;
2017-07-23 20:20:51 +00:00
for (uint8_t i = 0; i < 16; i++) {
uint8_t k = hash[31 - i];
2014-04-29 12:26:51 +00:00
hash[31 - i] = hash[i];
hash[i] = k;
}
}
2017-12-18 16:49:17 +00:00
static uint32_t tx_input_script_size(const TxInputType *txinput) {
uint32_t input_script_size;
if (txinput->has_multisig) {
uint32_t multisig_script_size = TXSIZE_MULTISIGSCRIPT
+ txinput->multisig.pubkeys_count * (1 + TXSIZE_PUBKEY);
input_script_size = 1 // the OP_FALSE bug in multisig
+ txinput->multisig.m * (1 + TXSIZE_SIGNATURE)
+ op_push_size(multisig_script_size) + multisig_script_size;
} else {
input_script_size = (1 + TXSIZE_SIGNATURE + 1 + TXSIZE_PUBKEY);
}
2017-12-18 16:49:17 +00:00
return input_script_size;
}
uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput) {
if (coin->decred) {
return 4 * (TXSIZE_INPUT + 1); // Decred tree
}
uint32_t input_script_size = tx_input_script_size(txinput);
uint32_t weight = 4 * TXSIZE_INPUT;
if (txinput->script_type == InputScriptType_SPENDADDRESS
|| txinput->script_type == InputScriptType_SPENDMULTISIG) {
input_script_size += ser_length_size(input_script_size);
weight += 4 * input_script_size;
} else if (txinput->script_type == InputScriptType_SPENDWITNESS
|| txinput->script_type == InputScriptType_SPENDP2SHWITNESS) {
if (txinput->script_type == InputScriptType_SPENDP2SHWITNESS) {
weight += 4 * (2 + (txinput->has_multisig
? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH));
} else {
weight += 4; // empty input script
}
weight += input_script_size; // discounted witness
}
return weight;
}
uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) {
uint32_t output_script_size = 0;
if (txoutput->script_type == OutputScriptType_PAYTOOPRETURN) {
output_script_size = 1 + op_push_size(txoutput->op_return_data.size)
+ txoutput->op_return_data.size;
} else if (txoutput->address_n_count > 0) {
if (txoutput->script_type == OutputScriptType_PAYTOWITNESS) {
output_script_size = txoutput->has_multisig
? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH;
} else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) {
output_script_size = TXSIZE_P2SCRIPT;
} else {
output_script_size = txoutput->has_multisig
? TXSIZE_P2SCRIPT : TXSIZE_P2PKHASH;
}
} else {
uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
int witver;
size_t addr_raw_len;
2018-01-04 19:18:34 +00:00
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 {
2018-04-03 14:25:06 +00:00
addr_raw_len = base58_decode_check(txoutput->address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE);
if (coin->has_address_type
&& address_check_prefix(addr_raw, coin->address_type)) {
output_script_size = TXSIZE_P2PKHASH;
} else if (coin->has_address_type_p2sh
&& address_check_prefix(addr_raw, coin->address_type_p2sh)) {
output_script_size = TXSIZE_P2SCRIPT;
}
}
}
output_script_size += ser_length_size(output_script_size);
2017-12-18 16:49:17 +00:00
uint32_t size = TXSIZE_OUTPUT;
if (coin->decred) {
size += 2; // Decred script version
}
return 4 * (size + output_script_size);
}
uint32_t tx_decred_witness_weight(const TxInputType *txinput) {
uint32_t input_script_size = tx_input_script_size(txinput);
uint32_t size = TXSIZE_DECRED_WITNESS + ser_length_size(input_script_size) + input_script_size;
return 4 * size;
2014-04-29 12:26:51 +00:00
}