Browse Source

tx: prepare for Elements Alpha.

They sign, hash, and serialize differently.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 10 years ago
parent
commit
20624c049f
  1. 5
      Makefile
  2. 28
      anchor.c
  3. 3
      bitcoin/signature.c
  4. 203
      bitcoin/tx.c
  5. 9
      bitcoin/tx.h
  6. 8
      commit_tx.c

5
Makefile

@ -3,6 +3,9 @@
# Needs to have oneof support: Ubuntu vivid's is too old :(
PROTOCC:=protoc-c
# Alpha has segregated witness, checksequenceverify
#FEATURES := -DHAS_CSV=1 -DALPHA_TXSTYLE=1
PROGRAMS := test-cli/open-channel test-cli/open-anchor-scriptsigs test-cli/leak-anchor-sigs test-cli/open-commit-sig test-cli/check-commit-sig test-cli/check-anchor-scriptsigs test-cli/get-anchor-depth test-cli/create-steal-tx test-cli/create-commit-spend-tx test-cli/close-channel test-cli/create-close-tx test-cli/update-channel test-cli/update-channel-accept test-cli/update-channel-signature test-cli/update-channel-complete test-cli/create-commit-tx
BITCOIN_OBJS := bitcoin/address.o bitcoin/base58.o bitcoin/pubkey.o bitcoin/script.o bitcoin/shadouble.o bitcoin/signature.o bitcoin/tx.o
@ -14,7 +17,7 @@ CCAN_OBJS := ccan-crypto-sha256.o ccan-crypto-shachain.o ccan-err.o ccan-tal.o c
HEADERS := $(wildcard *.h)
CCANDIR := ccan/
CFLAGS := -g -Wall -I $(CCANDIR) -DVALGRIND_HEADERS=1
CFLAGS := -g -Wall -I $(CCANDIR) -DVALGRIND_HEADERS=1 $(FEATURES)
LDLIBS := -lcrypto -lprotobuf-c
$(PROGRAMS): CFLAGS+=-I.

28
anchor.c

@ -18,6 +18,7 @@ struct bitcoin_tx *anchor_tx_create(const tal_t *ctx,
u8 *redeemscript;
size_t *inmap, *outmap;
struct pubkey key1, key2;
uint64_t total_in = 0, total_change = 0;
if (add_overflows_size_t(o1->anchor->n_inputs, o2->anchor->n_inputs))
return NULL;
@ -37,6 +38,10 @@ struct bitcoin_tx *anchor_tx_create(const tal_t *ctx,
struct bitcoin_tx_input *in = &tx->input[i];
proto_to_sha256(pb->txid, &in->txid.sha);
in->index = pb->output;
in->input_amount = pb->amount;
if (add_overflows_u64(total_in, in->input_amount))
return tal_free(tx);
total_in += in->input_amount;
/* Leave inputs as stubs for now, for signing. */
}
for (i = 0; i < o2->anchor->n_inputs; i++) {
@ -45,6 +50,10 @@ struct bitcoin_tx *anchor_tx_create(const tal_t *ctx,
= &tx->input[o1->anchor->n_inputs + i];
proto_to_sha256(pb->txid, &in->txid.sha);
in->index = pb->output;
in->input_amount = pb->amount;
if (add_overflows_u64(total_in, in->input_amount))
return tal_free(tx);
total_in += in->input_amount;
/* Leave inputs as stubs for now, for signing. */
}
@ -76,6 +85,7 @@ struct bitcoin_tx *anchor_tx_create(const tal_t *ctx,
out->script = scriptpubkey_p2sh(tx,
bitcoin_redeem_single(tx, &key));
out->script_length = tal_count(out->script);
total_change += out->amount;
}
if (o2->anchor->change) {
struct bitcoin_tx_output *out = &tx->output[n_out++];
@ -88,9 +98,25 @@ struct bitcoin_tx *anchor_tx_create(const tal_t *ctx,
out->script = scriptpubkey_p2sh(tx,
bitcoin_redeem_single(tx, &key));
out->script_length = tal_count(out->script);
if (add_overflows_u64(total_change, out->amount))
return tal_free(tx);
total_change += out->amount;
}
assert(n_out == tx->output_count);
/* Figure out fee we're paying; check for over and underflow */
if (add_overflows_u64(total_change, tx->output[0].amount))
return tal_free(tx);
if (total_in < total_change + tx->output[0].amount)
return tal_free(tx);
tx->fee = total_in - (total_change + tx->output[0].amount);
/* Check that the fees add up correctly. */
if (add_overflows_u64(o1->anchor->fee, o2->anchor->fee))
return tal_free(tx);
if (tx->fee != o1->anchor->fee + o2->anchor->fee)
return tal_free(tx);
if (inmapp)
inmap = *inmapp = tal_arr(ctx, size_t, tx->input_count);
else

3
bitcoin/signature.c

@ -125,8 +125,9 @@ static void sha256_tx_one_input(struct bitcoin_tx *tx,
tx->input[input_num].script = cast_const(u8 *, script);
sha256_init(&ctx);
sha256_tx(&ctx, tx);
sha256_tx_for_sig(&ctx, tx);
sha256_le32(&ctx, SIGHASH_ALL);
sha256_double_done(&ctx, hash);
/* Reset it for next time. */

203
bitcoin/tx.c

@ -7,8 +7,50 @@
#include "tx.h"
#include "valgrind.h"
enum styles {
/* Add the CT padding stuff to amount. */
TX_AMOUNT_CT_STYLE = 1,
/* Whether to process CT rangeproof and noncecommitment. */
TX_AMOUNT_INCLUDE_CT = 2,
/* Process the txfee field. */
TX_FEE = 4,
/* Process the input script sig. */
TX_INPUT_SCRIPTSIG = 8,
/* Process the amounts for each input. */
TX_INPUT_AMOUNT = 16,
/* Process hash of rangeproof and noncecommitment in *output* amount,
* instead of rangeproof and noncecommitment themselves. */
TX_OUTPUT_AMOUNT_HASHPROOF = 32
};
#ifdef ALPHA_TXSTYLE
/* Linearizing has everything, except input amount (which is implied) */
#define LINEARIZE_STYLE (TX_AMOUNT_CT_STYLE | TX_AMOUNT_INCLUDE_CT | TX_FEE | TX_INPUT_SCRIPTSIG)
/* Alpha txids don't include input scripts, or rangeproof/txcommit in output */
#define TXID_STYLE (TX_AMOUNT_CT_STYLE | TX_FEE)
/* Alpha signatures sign the input script (assuming others are set to
* 0-len), as well as the input fee.
* They sign a hash of the rangeproof and noncecommitment for inputs,
* rather than the non rangeproof and noncecommitment themselves.
*
* For some reason they skip the txfee. */
#define SIG_STYLE (TX_AMOUNT_CT_STYLE | TX_AMOUNT_INCLUDE_CT | TX_INPUT_SCRIPTSIG | TX_INPUT_AMOUNT | TX_OUTPUT_AMOUNT_HASHPROOF)
#else /* BITCOIN */
/* Process all the bitcoin fields. Works for txid, serialization and signing */
#define LINEARIZE_STYLE (TX_INPUT_SCRIPTSIG)
#define TXID_STYLE (TX_INPUT_SCRIPTSIG)
#define SIG_STYLE (TX_INPUT_SCRIPTSIG)
#endif
static void add_varint(varint_t v,
void (*add)(const void *, size_t, void *), void *addp)
void (*add)(const void *, size_t, void *), void *addp,
enum styles style)
{
u8 buf[9], *p = buf;
@ -39,50 +81,109 @@ static void add_varint(varint_t v,
}
static void add_le32(u32 v,
void (*add)(const void *, size_t, void *), void *addp)
void (*add)(const void *, size_t, void *), void *addp,
enum styles style)
{
le32 l = cpu_to_le32(v);
add(&l, sizeof(l), addp);
}
static void add_le64(u64 v,
void (*add)(const void *, size_t, void *), void *addp)
void (*add)(const void *, size_t, void *), void *addp,
enum styles style)
{
le64 l = cpu_to_le64(v);
add(&l, sizeof(l), addp);
}
static void add_value(u64 amount,
void (*add)(const void *, size_t, void *),
void *addp,
bool output,
enum styles style)
{
if (style & TX_AMOUNT_CT_STYLE) {
/* The input is hashed as a 33 byte value (for CT); 25 0, then
* the big-endian value. */
static u8 zeroes[25];
be64 b = cpu_to_be64(amount);
add(zeroes, sizeof(zeroes), addp);
add(&b, sizeof(b), addp);
if (style & TX_AMOUNT_INCLUDE_CT) {
/* Two more zeroes: Rangeproof and Noncecommitment */
if (output && (style & TX_OUTPUT_AMOUNT_HASHPROOF)) {
struct sha256_double h;
sha256_double(&h, zeroes, 2);
add(&h, sizeof(h), addp);
} else {
add_varint(0, add, addp, style);
add_varint(0, add, addp, style);
}
}
} else {
add_le64(amount, add, addp, style);
}
}
static void add_input_value(u64 amount,
void (*add)(const void *, size_t, void *),
void *addp,
enum styles style)
{
return add_value(amount, add, addp, false, style);
}
static void add_output_value(u64 amount,
void (*add)(const void *, size_t, void *),
void *addp,
enum styles style)
{
return add_value(amount, add, addp, true, style);
}
static void add_tx_input(const struct bitcoin_tx_input *input,
void (*add)(const void *, size_t, void *), void *addp)
void (*add)(const void *, size_t, void *), void *addp,
enum styles style)
{
add(&input->txid, sizeof(input->txid), addp);
add_le32(input->index, add, addp);
add_varint(input->script_length, add, addp);
add(input->script, input->script_length, addp);
add_le32(input->sequence_number, add, addp);
add_le32(input->index, add, addp, style);
if (style & TX_INPUT_AMOUNT) {
add_input_value(input->input_amount, add, addp, style);
}
if (style & TX_INPUT_SCRIPTSIG) {
add_varint(input->script_length, add, addp, style);
add(input->script, input->script_length, addp);
}
add_le32(input->sequence_number, add, addp, style);
}
static void add_tx_output(const struct bitcoin_tx_output *output,
void (*add)(const void *, size_t, void *), void *addp)
void (*add)(const void *, size_t, void *), void *addp,
enum styles style)
{
add_le64(output->amount, add, addp);
add_varint(output->script_length, add, addp);
add_output_value(output->amount, add, addp, style);
add_varint(output->script_length, add, addp, style);
add(output->script, output->script_length, addp);
}
static void add_tx(const struct bitcoin_tx *tx,
void (*add)(const void *, size_t, void *), void *addp)
void (*add)(const void *, size_t, void *), void *addp,
enum styles style)
{
varint_t i;
add_le32(tx->version, add, addp);
add_varint(tx->input_count, add, addp);
add_le32(tx->version, add, addp, style);
add_varint(tx->input_count, add, addp, style);
for (i = 0; i < tx->input_count; i++)
add_tx_input(&tx->input[i], add, addp);
add_varint(tx->output_count, add, addp);
add_tx_input(&tx->input[i], add, addp, style);
if (style & TX_FEE)
add_le64(tx->fee, add, addp, style);
add_varint(tx->output_count, add, addp, style);
for (i = 0; i < tx->output_count; i++)
add_tx_output(&tx->output[i], add, addp);
add_le32(tx->lock_time, add, addp);
add_tx_output(&tx->output[i], add, addp, style);
add_le32(tx->lock_time, add, addp, style);
}
static void add_sha(const void *data, size_t len, void *shactx_)
@ -91,9 +192,9 @@ static void add_sha(const void *data, size_t len, void *shactx_)
sha256_update(ctx, check_mem(data, len), len);
}
void sha256_tx(struct sha256_ctx *ctx, const struct bitcoin_tx *tx)
void sha256_tx_for_sig(struct sha256_ctx *ctx, const struct bitcoin_tx *tx)
{
add_tx(tx, add_sha, ctx);
add_tx(tx, add_sha, ctx, SIG_STYLE);
}
static void add_linearize(const void *data, size_t len, void *pptr_)
@ -108,7 +209,7 @@ static void add_linearize(const void *data, size_t len, void *pptr_)
u8 *linearize_tx(const tal_t *ctx, const struct bitcoin_tx *tx)
{
u8 *arr = tal_arr(ctx, u8, 0);
add_tx(tx, add_linearize, &arr);
add_tx(tx, add_linearize, &arr, LINEARIZE_STYLE);
return arr;
}
@ -116,7 +217,7 @@ void bitcoin_txid(const struct bitcoin_tx *tx, struct sha256_double *txid)
{
struct sha256_ctx ctx = SHA256_INIT;
sha256_tx(&ctx, tx);
add_tx(tx, add_sha, &ctx, TXID_STYLE);
sha256_double_done(&ctx, txid);
}
@ -219,21 +320,67 @@ static bool pull_sha256_double(const u8 **cursor, size_t *max,
return pull(cursor, max, h, sizeof(*h));
}
static u64 pull_value(const u8 **cursor, size_t *max)
{
u64 amount;
if (LINEARIZE_STYLE & TX_AMOUNT_CT_STYLE) {
/* The input is hashed as a 33 byte value (for CT); 25 0, then
* the big-endian value. */
u8 zeroes[25];
be64 b;
if (!pull(cursor, max, zeroes, sizeof(zeroes)))
return 0;
/* We don't handle CT amounts. */
if (zeroes[0] != 0)
goto fail;
if (!pull(cursor, max, &b, sizeof(b)))
return 0;
amount = be64_to_cpu(b);
if (LINEARIZE_STYLE & TX_AMOUNT_INCLUDE_CT) {
varint_t rp, nc;
rp = pull_varint(cursor, max);
nc = pull_varint(cursor, max);
if (rp != 0 || nc != 0)
goto fail;
}
} else {
amount = pull_le64(cursor, max);
}
return amount;
fail:
/* Simulate EOF */
*cursor = NULL;
*max = 0;
return 0;
}
static void pull_input(const tal_t *ctx, const u8 **cursor, size_t *max,
struct bitcoin_tx_input *input)
{
pull_sha256_double(cursor, max, &input->txid);
input->index = pull_le32(cursor, max);
input->script_length = pull_varint(cursor, max);
input->script = tal_arr(ctx, u8, input->script_length);
pull(cursor, max, input->script, input->script_length);
if (LINEARIZE_STYLE & TX_INPUT_AMOUNT) {
input->input_amount = pull_value(cursor, max);
}
if (LINEARIZE_STYLE & TX_INPUT_SCRIPTSIG) {
input->script_length = pull_varint(cursor, max);
input->script = tal_arr(ctx, u8, input->script_length);
pull(cursor, max, input->script, input->script_length);
}
input->sequence_number = pull_le32(cursor, max);
}
static void pull_output(const tal_t *ctx, const u8 **cursor, size_t *max,
struct bitcoin_tx_output *output)
{
output->amount = pull_le64(cursor, max);
output->amount = pull_value(cursor, max);
output->script_length = pull_varint(cursor, max);
output->script = tal_arr(ctx, u8, output->script_length);
pull(cursor, max, output->script, output->script_length);
@ -250,6 +397,10 @@ static struct bitcoin_tx *pull_bitcoin_tx(const tal_t *ctx,
tx->input = tal_arr(tx, struct bitcoin_tx_input, tx->input_count);
for (i = 0; i < tx->input_count; i++)
pull_input(tx, cursor, max, tx->input + i);
if (LINEARIZE_STYLE & TX_FEE)
tx->fee = pull_le64(cursor, max);
tx->output_count = pull_varint(cursor, max);
tx->output = tal_arr(ctx, struct bitcoin_tx_output, tx->output_count);
for (i = 0; i < tx->output_count; i++)

9
bitcoin/tx.h

@ -13,6 +13,10 @@ struct bitcoin_tx {
u32 version;
varint_t input_count;
struct bitcoin_tx_input *input;
/* Only in alpha. */
u64 fee;
varint_t output_count;
struct bitcoin_tx_output *output;
u32 lock_time;
@ -25,6 +29,9 @@ struct bitcoin_tx_output {
};
struct bitcoin_tx_input {
/* In alpha, this is hashed for signature */
u64 input_amount;
struct sha256_double txid;
u32 index; /* output number referred to by above */
varint_t script_length;
@ -37,7 +44,7 @@ struct bitcoin_tx_input {
void bitcoin_txid(const struct bitcoin_tx *tx, struct sha256_double *txid);
/* Useful for signature code. */
void sha256_tx(struct sha256_ctx *ctx, const struct bitcoin_tx *tx);
void sha256_tx_for_sig(struct sha256_ctx *ctx, const struct bitcoin_tx *tx);
/* Linear bytes of tx. */
u8 *linearize_tx(const tal_t *ctx, const struct bitcoin_tx *tx);

8
commit_tx.c

@ -3,6 +3,7 @@
#include "bitcoin/shadouble.h"
#include "bitcoin/tx.h"
#include "commit_tx.h"
#include "overflows.h"
#include "permute_tx.h"
#include "pkt.h"
#include "protobuf_convert.h"
@ -26,6 +27,9 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
/* Our input spends the anchor tx output. */
tx->input[0].txid = *anchor_txid;
tx->input[0].index = anchor_output;
if (add_overflows_u64(ours->anchor->total, theirs->anchor->total))
return tal_free(tx);
tx->input[0].input_amount = ours->anchor->total + theirs->anchor->total;
/* Output goes to our final pubkeys */
if (!proto_to_pubkey(ours->final, &ourkey))
@ -68,6 +72,10 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
return tal_free(tx);
tx->output[0].amount -= delta;
/* Calculate fee; difference of inputs and outputs. */
tx->fee = tx->input[0].input_amount
- (tx->output[0].amount + tx->output[1].amount);
permute_outputs(ours->seed, theirs->seed, 1, tx->output, 2, NULL);
return tx;
}

Loading…
Cancel
Save