From 670670f1386625213a7ba32689095635db987399 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2015 07:08:27 +0930 Subject: [PATCH] open-anchor-sig, many fixes for open-channel. Signed-off-by: Rusty Russell --- Makefile | 25 ++- base58.h | 11 +- bitcoin_address.c | 11 ++ bitcoin_address.h | 18 ++ bitcoin_script.c | 161 ++++++++++++++++ bitcoin_script.h | 34 ++++ bitcoin_tx.c | 64 +++++++ bitcoin_tx.h | 38 ++++ getinput.sh | 35 ++++ lightning.pb-c.c | 459 ++++++++++++++++++++++++++++++++++++++-------- lightning.pb-c.h | 206 +++++++++++++++++---- lightning.proto | 52 +++++- open-anchor-sig.c | 197 ++++++++++++++++++++ open-channel.c | 117 ++++++++---- overflows.h | 14 ++ pd_channel.h | 20 -- perturb.c | 186 +++++++++++++++++++ perturb.h | 25 +++ pkt.c | 85 ++++++++- pkt.h | 18 +- signature.c | 45 +++++ signature.h | 19 ++ 22 files changed, 1638 insertions(+), 202 deletions(-) create mode 100644 bitcoin_address.c create mode 100644 bitcoin_address.h create mode 100644 bitcoin_script.c create mode 100644 bitcoin_script.h create mode 100644 bitcoin_tx.c create mode 100644 bitcoin_tx.h create mode 100755 getinput.sh create mode 100644 open-anchor-sig.c create mode 100644 overflows.h delete mode 100644 pd_channel.h create mode 100644 perturb.c create mode 100644 perturb.h create mode 100644 signature.c create mode 100644 signature.h diff --git a/Makefile b/Makefile index f446c889b..a3d81d759 100644 --- a/Makefile +++ b/Makefile @@ -3,37 +3,44 @@ # Needs to have oneof support: Ubuntu vivid's is too old :( PROTOCC:=protoc-c -PROGRAMS := open-channel +PROGRAMS := open-channel open-anchor-sig -HELPER_OBJS := base58.o lightning.pb-c.o shadouble.o pkt.o -CCAN_OBJS := ccan-crypto-sha256.o ccan-crypto-shachain.o ccan-err.o ccan-tal.o ccan-tal-str.o ccan-take.o ccan-list.o ccan-str.o ccan-opt-helpers.o ccan-opt.o ccan-opt-parse.o ccan-opt-usage.o ccan-read_write_all.o ccan-str-hex.o +HELPER_OBJS := base58.o lightning.pb-c.o shadouble.o pkt.o bitcoin_script.o perturb.o signature.o bitcoin_tx.o bitcoin_address.o +CCAN_OBJS := ccan-crypto-sha256.o ccan-crypto-shachain.o ccan-err.o ccan-tal.o ccan-tal-str.o ccan-take.o ccan-list.o ccan-str.o ccan-opt-helpers.o ccan-opt.o ccan-opt-parse.o ccan-opt-usage.o ccan-read_write_all.o ccan-str-hex.o ccan-tal-grab_file.o ccan-noerr.o -OPEN_CHANNEL_OBJS := open-channel.o $(HELPER_OBJS) $(CCAN_OBJS) +OPEN_CHANNEL_OBJS := open-channel.o +OPEN_ANCHOR_SIG_OBJS := open-anchor-sig.o -HEADERS := base58.h lightning.pb-c.h pd_channel.h pkt.h shadouble.h +HEADERS := $(wildcard *.h) CCANDIR := ../ccan/ CFLAGS := -g -Wall -I $(CCANDIR) #-I $(PROTO_INCLUDE_DIR) LDLIBS := -lcrypto -lprotobuf-c -default: open-channel +default: $(PROGRAMS) lightning.pb-c.c lightning.pb-c.h: lightning.proto $(PROTOCC) lightning.proto --c_out=. -open-channel: $(OPEN_CHANNEL_OBJS) +open-channel: $(OPEN_CHANNEL_OBJS) $(HELPER_OBJS) $(CCAN_OBJS) $(OPEN_CHANNEL_OBJS): $(HEADERS) +open-anchor-sig: $(OPEN_ANCHOR_SIG_OBJS) $(HELPER_OBJS) $(CCAN_OBJS) +$(OPEN_ANCHOR_SIG_OBJS): $(HEADERS) + distclean: clean $(RM) lightning.pb-c.c lightning.pb-c.h clean: - $(RM) $(OPEN_CHANNEL_OBJS) + $(RM) $(PROGRAMS) + $(RM) $(OPEN_CHANNEL_OBJS) $(OPEN_ANCHOR_SIG_OBJS) $(HELPER_OBJS) $(CCAN_OBJS) ccan-tal.o: $(CCANDIR)/ccan/tal/tal.c $(CC) $(CFLAGS) -c -o $@ $< ccan-tal-str.o: $(CCANDIR)/ccan/tal/str/str.c $(CC) $(CFLAGS) -c -o $@ $< +ccan-tal-grab_file.o: $(CCANDIR)/ccan/tal/grab_file/grab_file.c + $(CC) $(CFLAGS) -c -o $@ $< ccan-take.o: $(CCANDIR)/ccan/take/take.c $(CC) $(CFLAGS) -c -o $@ $< ccan-list.o: $(CCANDIR)/ccan/list/list.c @@ -52,6 +59,8 @@ ccan-opt-usage.o: $(CCANDIR)/ccan/opt/usage.c $(CC) $(CFLAGS) -c -o $@ $< ccan-err.o: $(CCANDIR)/ccan/err/err.c $(CC) $(CFLAGS) -c -o $@ $< +ccan-noerr.o: $(CCANDIR)/ccan/noerr/noerr.c + $(CC) $(CFLAGS) -c -o $@ $< ccan-str-hex.o: $(CCANDIR)/ccan/str/hex/hex.c $(CC) $(CFLAGS) -c -o $@ $< ccan-crypto-shachain.o: $(CCANDIR)/ccan/crypto/shachain/shachain.c diff --git a/base58.h b/base58.h index 152127e4c..832b2c0d6 100644 --- a/base58.h +++ b/base58.h @@ -8,6 +8,7 @@ #include #include #include +#include "bitcoin_address.h" /* Encoding is version byte + ripemd160 + 4-byte checksum == 200 bits => 2^200. * @@ -20,16 +21,6 @@ * 58^51 < 2^302, but 58^52 > 2^302. So 52 digits, plus one terminator. */ #define BASE58_KEY_MAX_LEN 53 -/* An ECDSA compressed public key. 33 chars long, even on ARM. */ -struct bitcoin_compressed_pubkey { - u8 key[33]; -} __attribute__((aligned(1))); - -/* An address is the RIPEMD160 of the SHA of the public key. */ -struct bitcoin_address { - u8 addr[RIPEMD160_DIGEST_LENGTH]; /* 20 */ -}; - /* Bitcoin address encoded in base58, with version and checksum */ char *bitcoin_to_base58(const tal_t *ctx, bool test_net, const struct bitcoin_address *addr); diff --git a/bitcoin_address.c b/bitcoin_address.c new file mode 100644 index 000000000..763003ced --- /dev/null +++ b/bitcoin_address.c @@ -0,0 +1,11 @@ +#include "bitcoin_address.h" +#include + +void bitcoin_address(const struct bitcoin_compressed_pubkey *key, + struct bitcoin_address *addr) +{ + struct sha256 h; + + sha256(&h, key, sizeof(*key)); + RIPEMD160(h.u.u8, sizeof(h), addr->addr); +} diff --git a/bitcoin_address.h b/bitcoin_address.h new file mode 100644 index 000000000..3f4c0134f --- /dev/null +++ b/bitcoin_address.h @@ -0,0 +1,18 @@ +#ifndef LIGHTNING_BITCOIN_ADDRESS_H +#define LIGHTNING_BITCOIN_ADDRESS_H +#include +#include + +/* An address is the RIPEMD160 of the SHA of the public key. */ +struct bitcoin_address { + u8 addr[RIPEMD160_DIGEST_LENGTH]; /* 20 */ +}; + +/* An ECDSA compressed public key. 33 chars long, even on ARM. */ +struct bitcoin_compressed_pubkey { + u8 key[33]; +} __attribute__((aligned(1))); + +void bitcoin_address(const struct bitcoin_compressed_pubkey *key, + struct bitcoin_address *addr); +#endif /* LIGHTNING_BITCOIN_ADDRESS_H */ diff --git a/bitcoin_script.c b/bitcoin_script.c new file mode 100644 index 000000000..2696c1ad5 --- /dev/null +++ b/bitcoin_script.c @@ -0,0 +1,161 @@ +#include "bitcoin_script.h" +#include "bitcoin_address.h" +#include +#include +#include + +/* Some standard ops */ +#define OP_PUSHBYTES(val) (val) +#define OP_LITERAL(val) (0x51 + (val)) +#define OP_PUSHDATA1 0x4C +#define OP_PUSHDATA2 0x4D +#define OP_PUSHDATA4 0x4E +#define OP_NOP 0x61 +#define OP_DUP 0x76 +#define OP_EQUAL 0x87 +#define OP_EQUALVERIFY 0x88 +#define OP_CHECKSIG 0xAC +#define OP_CHECKMULTISIG 0xAE +#define OP_HASH160 0xA9 + +static void add(u8 **scriptp, const void *mem, size_t len) +{ + size_t oldlen = tal_count(*scriptp); + tal_resize(scriptp, oldlen + len); + memcpy(*scriptp + oldlen, mem, len); +} + +static void add_op(u8 **scriptp, u8 op) +{ + add(scriptp, &op, 1); +} + +static void add_push_bytes(u8 **scriptp, const void *mem, size_t len) +{ + if (len < 76) + add_op(scriptp, OP_PUSHBYTES(len)); + else if (len < 256) { + char c = len; + add_op(scriptp, OP_PUSHDATA1); + add(scriptp, &c, 1); + } else if (len < 65536) { + le16 v = cpu_to_le16(len); + add_op(scriptp, OP_PUSHDATA2); + add(scriptp, &v, 2); + } else { + le32 v = cpu_to_le32(len); + add_op(scriptp, OP_PUSHDATA4); + add(scriptp, &v, 4); + } + + add(scriptp, mem, len); +} + +/* FIXME: permute? */ +/* Is a < b? (If equal we don't care) */ +static bool key_less(const BitcoinPubkey *a, const BitcoinPubkey *b) +{ + size_t len; + int cmp; + + if (a->key.len < b->key.len) + len = a->key.len; + else + len = b->key.len; + + cmp = memcmp(a->key.data, b->key.data, len); + if (cmp < 0) + return true; + else if (cmp > 0) + return false; + + /* Corner case: if it's shorter, it's less. */ + return a->key.len < b->key.len; +} + +/* tal_count() gives the length of the script. */ +u8 *bitcoin_redeem_2of2(const tal_t *ctx, + const BitcoinPubkey *key1, + const BitcoinPubkey *key2) +{ + u8 *script = tal_arr(ctx, u8, 0); + add_op(&script, OP_LITERAL(2)); + if (key_less(key1, key2)) { + add_push_bytes(&script, key1->key.data, key1->key.len); + add_push_bytes(&script, key2->key.data, key2->key.len); + } else { + add_push_bytes(&script, key2->key.data, key2->key.len); + add_push_bytes(&script, key1->key.data, key1->key.len); + } + add_op(&script, OP_CHECKMULTISIG); + return script; +} + +/* tal_count() gives the length of the script. */ +u8 *bitcoin_redeem_single(const tal_t *ctx, const u8 *key, size_t keylen) +{ + u8 *script = tal_arr(ctx, u8, 0); + add_push_bytes(&script, key, keylen); + add_op(&script, OP_CHECKSIG); + return script; +} + +/* Create p2sh for this redeem script. */ +u8 *scriptpubkey_p2sh(const tal_t *ctx, const u8 *redeemscript) +{ + struct sha256 h; + u8 redeemhash[RIPEMD160_DIGEST_LENGTH]; + u8 *script = tal_arr(ctx, u8, 0); + + add_op(&script, OP_HASH160); + sha256(&h, redeemscript, tal_count(redeemscript)); + RIPEMD160(h.u.u8, sizeof(h), redeemhash); + add_push_bytes(&script, redeemhash, sizeof(redeemhash)); + add_op(&script, OP_EQUAL); + return script; +} + +u8 *scriptpubkey_pay_to_pubkeyhash(const tal_t *ctx, + const struct bitcoin_address *addr) +{ + u8 *script = tal_arr(ctx, u8, 0); + + add_op(&script, OP_DUP); + add_op(&script, OP_HASH160); + add_push_bytes(&script, addr, sizeof(addr)); + add_op(&script, OP_EQUALVERIFY); + add_op(&script, OP_CHECKSIG); + + return script; +} + +u8 *scriptsig_pay_to_pubkeyhash(const tal_t *ctx, + const struct bitcoin_address *addr, + const u8 *signature, + size_t sig_len) +{ + u8 *script = tal_arr(ctx, u8, 0); + + add_push_bytes(&script, signature, sig_len); + add_push_bytes(&script, addr, sizeof(*addr)); + + return script; +} + +/* Is this a normal pay to pubkey hash? */ +bool is_pay_to_pubkey_hash(const ProtobufCBinaryData *script) +{ + if (script->len != 25) + return false; + if (script->data[0] != OP_DUP) + return false; + if (script->data[1] != OP_HASH160) + return false; + if (script->data[2] != OP_PUSHBYTES(20)) + return false; + if (script->data[23] != OP_EQUALVERIFY) + return false; + if (script->data[24] != OP_CHECKSIG) + return false; + return true; +} diff --git a/bitcoin_script.h b/bitcoin_script.h new file mode 100644 index 000000000..79950ecee --- /dev/null +++ b/bitcoin_script.h @@ -0,0 +1,34 @@ +#ifndef LIGHTNING_BITCOIN_SCRIPT_H +#define LIGHTNING_BITCOIN_SCRIPT_H +#include +#include +#include "lightning.pb-c.h" + +struct bitcoin_address; +struct bitcoin_compressed_pubkey; + +/* tal_count() gives the length of the script. */ +u8 *bitcoin_redeem_2of2(const tal_t *ctx, + const BitcoinPubkey *key1, + const BitcoinPubkey *key2); + +/* tal_count() gives the length of the script. */ +u8 *bitcoin_redeem_single(const tal_t *ctx, const u8 *key, size_t keylen); + +/* Create an output script using p2sh for this redeem script. */ +u8 *scriptpubkey_p2sh(const tal_t *ctx, const u8 *redeemscript); + +/* Create an output script to pay to pubkey hash */ +u8 *scriptpubkey_pay_to_pubkeyhash(const tal_t *ctx, + const struct bitcoin_address *addr); + +/* Create an input script to accept pay to pubkey */ +u8 *scriptsig_pay_to_pubkeyhash(const tal_t *ctx, + const struct bitcoin_address *addr, + const u8 *signature, + size_t sig_len); + +/* Is this a normal pay to pubkey hash? */ +bool is_pay_to_pubkey_hash(const ProtobufCBinaryData *script); + +#endif /* LIGHTNING_BITCOIN_SCRIPT_H */ diff --git a/bitcoin_tx.c b/bitcoin_tx.c new file mode 100644 index 000000000..e287c1e30 --- /dev/null +++ b/bitcoin_tx.c @@ -0,0 +1,64 @@ +#include "bitcoin_tx.h" +#include + +static void sha256_varint(struct sha256_ctx *ctx, varint_t v) +{ + u8 buf[9], *p = buf; + + if (v < 0xfd) { + *(p++) = v; + } else if (v <= 0xffff) { + (*p++) = 0xfd; + (*p++) = v >> 8; + (*p++) = v; + } else if (v <= 0xffffffff) { + (*p++) = 0xfe; + (*p++) = v >> 24; + (*p++) = v >> 16; + (*p++) = v >> 8; + (*p++) = v; + } else { + (*p++) = 0xff; + (*p++) = v >> 56; + (*p++) = v >> 48; + (*p++) = v >> 40; + (*p++) = v >> 32; + (*p++) = v >> 24; + (*p++) = v >> 16; + (*p++) = v >> 8; + (*p++) = v; + } + sha256_update(ctx, buf, p - buf); +} + +static void sha256_tx_input(struct sha256_ctx *ctx, + const struct bitcoin_tx_input *input) +{ + sha256_update(ctx, &input->txid, sizeof(input->txid)); + sha256_le32(ctx, input->index); + sha256_varint(ctx, input->script_length); + sha256_update(ctx, input->script, input->script_length); + sha256_le32(ctx, input->sequence_number); +} + +static void sha256_tx_output(struct sha256_ctx *ctx, + const struct bitcoin_tx_output *output) +{ + sha256_le64(ctx, output->amount); + sha256_varint(ctx, output->script_length); + sha256_update(ctx, output->script, output->script_length); +} + +void sha256_tx(struct sha256_ctx *ctx, const struct bitcoin_tx *tx) +{ + varint_t i; + + sha256_le32(ctx, tx->version); + sha256_varint(ctx, tx->input_count); + for (i = 0; i < tx->input_count; i++) + sha256_tx_input(ctx, &tx->input[i]); + sha256_varint(ctx, tx->output_count); + for (i = 0; i < tx->output_count; i++) + sha256_tx_output(ctx, &tx->output[i]); + sha256_le32(ctx, tx->lock_time); +} diff --git a/bitcoin_tx.h b/bitcoin_tx.h new file mode 100644 index 000000000..662b16f2f --- /dev/null +++ b/bitcoin_tx.h @@ -0,0 +1,38 @@ +#ifndef LIGHTNING_BITCOIN_TX_H +#define LIGHTNING_BITCOIN_TX_H +#include +#include "shadouble.h" + +#define BITCOIN_TX_VERSION 1 + +/* We unpack varints for our in-memory representation */ +#define varint_t u64 + +struct bitcoin_tx { + u32 version; + varint_t input_count; + struct bitcoin_tx_input *input; + varint_t output_count; + struct bitcoin_tx_output *output; + u32 lock_time; +}; + +struct bitcoin_tx_output { + u64 amount; + varint_t script_length; + u8 *script; +}; + +struct bitcoin_tx_input { + struct sha256_double txid; + u32 index; /* output number referred to by above */ + varint_t script_length; + u8 *script; + u32 sequence_number; +}; + +/* Linearize the tx. This is good for deriving the txid, as well as the + * signature. */ +void sha256_tx(struct sha256_ctx *shactx, const struct bitcoin_tx *tx); + +#endif /* LIGHTNING_BITCOIN_TX_H */ diff --git a/getinput.sh b/getinput.sh new file mode 100755 index 000000000..35f8b3163 --- /dev/null +++ b/getinput.sh @@ -0,0 +1,35 @@ +#! /bin/sh +# Query bitcoind to get (first) unspent output to spend. + +### +# Nobody should *EVER* write code like this. EVER!! +### + +set -e + +if [ n"$1" = n--privkey ]; then + KEY=1 + shift +fi +NUM=1 +if [ $# = 1 ]; then + NUM=$1 + shift +fi + +if [ $# -gt 0 ]; then + echo "Usage: getinput.sh [--privkey] [INPUT-INDEX]" + exit 1 +fi + +if [ -n "$KEY" ]; then + ADDR=`bitcoin-cli -testnet listunspent | sed -n 's/^ "address" : "\([0-9a-zA-Z]*\)",$/\1/p' | tail -n +$NUM | head -n1` + bitcoin-cli dumpprivkey $ADDR +else + TXID=`bitcoin-cli -testnet listunspent | sed -n 's/^ "txid" : "\([0-9a-f]*\)",$/\1/p' | tail -n +$NUM | head -n1` + OUTNUM=`bitcoin-cli -testnet listunspent | sed -n 's/^ "vout" : \([0-9]*\),$/\1/p' | tail -n +$NUM | head -n1` + AMOUNT=`bitcoin-cli -testnet listunspent | sed -n 's/^ "amount" : \([0-9.]*\),$/\1/p' | tail -n +$NUM | head -n1 | tr -d . | sed 's/^0*//'` + SCRIPT=`bitcoin-cli -testnet listunspent | sed -n 's/^ "scriptPubKey" : "\([0-9a-f]*\)",$/\1/p' | tail -n +$NUM | head -n1` + + echo $TXID/$OUTNUM/$AMOUNT/$SCRIPT +fi diff --git a/lightning.pb-c.c b/lightning.pb-c.c index 31523655b..cd3a91a39 100644 --- a/lightning.pb-c.c +++ b/lightning.pb-c.c @@ -50,47 +50,47 @@ void sha256_hash__free_unpacked assert(message->base.descriptor == &sha256_hash__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } -void bitcoin_output_id__init - (BitcoinOutputId *message) +void bitcoin_input__init + (BitcoinInput *message) { - static BitcoinOutputId init_value = BITCOIN_OUTPUT_ID__INIT; + static BitcoinInput init_value = BITCOIN_INPUT__INIT; *message = init_value; } -size_t bitcoin_output_id__get_packed_size - (const BitcoinOutputId *message) +size_t bitcoin_input__get_packed_size + (const BitcoinInput *message) { - assert(message->base.descriptor == &bitcoin_output_id__descriptor); + assert(message->base.descriptor == &bitcoin_input__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } -size_t bitcoin_output_id__pack - (const BitcoinOutputId *message, +size_t bitcoin_input__pack + (const BitcoinInput *message, uint8_t *out) { - assert(message->base.descriptor == &bitcoin_output_id__descriptor); + assert(message->base.descriptor == &bitcoin_input__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } -size_t bitcoin_output_id__pack_to_buffer - (const BitcoinOutputId *message, +size_t bitcoin_input__pack_to_buffer + (const BitcoinInput *message, ProtobufCBuffer *buffer) { - assert(message->base.descriptor == &bitcoin_output_id__descriptor); + assert(message->base.descriptor == &bitcoin_input__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } -BitcoinOutputId * - bitcoin_output_id__unpack +BitcoinInput * + bitcoin_input__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { - return (BitcoinOutputId *) - protobuf_c_message_unpack (&bitcoin_output_id__descriptor, + return (BitcoinInput *) + protobuf_c_message_unpack (&bitcoin_input__descriptor, allocator, len, data); } -void bitcoin_output_id__free_unpacked - (BitcoinOutputId *message, +void bitcoin_input__free_unpacked + (BitcoinInput *message, ProtobufCAllocator *allocator) { - assert(message->base.descriptor == &bitcoin_output_id__descriptor); + assert(message->base.descriptor == &bitcoin_input__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void bitcoin_output__init @@ -179,6 +179,49 @@ void bitcoin_signature__free_unpacked assert(message->base.descriptor == &bitcoin_signature__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } +void bitcoin_pubkey__init + (BitcoinPubkey *message) +{ + static BitcoinPubkey init_value = BITCOIN_PUBKEY__INIT; + *message = init_value; +} +size_t bitcoin_pubkey__get_packed_size + (const BitcoinPubkey *message) +{ + assert(message->base.descriptor == &bitcoin_pubkey__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t bitcoin_pubkey__pack + (const BitcoinPubkey *message, + uint8_t *out) +{ + assert(message->base.descriptor == &bitcoin_pubkey__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t bitcoin_pubkey__pack_to_buffer + (const BitcoinPubkey *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &bitcoin_pubkey__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +BitcoinPubkey * + bitcoin_pubkey__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (BitcoinPubkey *) + protobuf_c_message_unpack (&bitcoin_pubkey__descriptor, + allocator, len, data); +} +void bitcoin_pubkey__free_unpacked + (BitcoinPubkey *message, + ProtobufCAllocator *allocator) +{ + assert(message->base.descriptor == &bitcoin_pubkey__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} void anchor__init (Anchor *message) { @@ -351,6 +394,49 @@ void open_anchor_sig__free_unpacked assert(message->base.descriptor == &open_anchor_sig__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } +void give_early_anchor_sig_and_pretend_we_didnt__init + (GiveEarlyAnchorSigAndPretendWeDidnt *message) +{ + static GiveEarlyAnchorSigAndPretendWeDidnt init_value = GIVE_EARLY_ANCHOR_SIG_AND_PRETEND_WE_DIDNT__INIT; + *message = init_value; +} +size_t give_early_anchor_sig_and_pretend_we_didnt__get_packed_size + (const GiveEarlyAnchorSigAndPretendWeDidnt *message) +{ + assert(message->base.descriptor == &give_early_anchor_sig_and_pretend_we_didnt__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t give_early_anchor_sig_and_pretend_we_didnt__pack + (const GiveEarlyAnchorSigAndPretendWeDidnt *message, + uint8_t *out) +{ + assert(message->base.descriptor == &give_early_anchor_sig_and_pretend_we_didnt__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t give_early_anchor_sig_and_pretend_we_didnt__pack_to_buffer + (const GiveEarlyAnchorSigAndPretendWeDidnt *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &give_early_anchor_sig_and_pretend_we_didnt__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +GiveEarlyAnchorSigAndPretendWeDidnt * + give_early_anchor_sig_and_pretend_we_didnt__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (GiveEarlyAnchorSigAndPretendWeDidnt *) + protobuf_c_message_unpack (&give_early_anchor_sig_and_pretend_we_didnt__descriptor, + allocator, len, data); +} +void give_early_anchor_sig_and_pretend_we_didnt__free_unpacked + (GiveEarlyAnchorSigAndPretendWeDidnt *message, + ProtobufCAllocator *allocator) +{ + assert(message->base.descriptor == &give_early_anchor_sig_and_pretend_we_didnt__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} void open_complete__init (OpenComplete *message) { @@ -609,6 +695,49 @@ void new_anchor_ack__free_unpacked assert(message->base.descriptor == &new_anchor_ack__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } +void new_anchor_commit_sig__init + (NewAnchorCommitSig *message) +{ + static NewAnchorCommitSig init_value = NEW_ANCHOR_COMMIT_SIG__INIT; + *message = init_value; +} +size_t new_anchor_commit_sig__get_packed_size + (const NewAnchorCommitSig *message) +{ + assert(message->base.descriptor == &new_anchor_commit_sig__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t new_anchor_commit_sig__pack + (const NewAnchorCommitSig *message, + uint8_t *out) +{ + assert(message->base.descriptor == &new_anchor_commit_sig__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t new_anchor_commit_sig__pack_to_buffer + (const NewAnchorCommitSig *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &new_anchor_commit_sig__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +NewAnchorCommitSig * + new_anchor_commit_sig__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (NewAnchorCommitSig *) + protobuf_c_message_unpack (&new_anchor_commit_sig__descriptor, + allocator, len, data); +} +void new_anchor_commit_sig__free_unpacked + (NewAnchorCommitSig *message, + ProtobufCAllocator *allocator) +{ + assert(message->base.descriptor == &new_anchor_commit_sig__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} void new_anchor_accept__init (NewAnchorAccept *message) { @@ -944,7 +1073,7 @@ const ProtobufCMessageDescriptor sha256_hash__descriptor = (ProtobufCMessageInit) sha256_hash__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor bitcoin_output_id__field_descriptors[2] = +static const ProtobufCFieldDescriptor bitcoin_input__field_descriptors[4] = { { "txid", @@ -952,7 +1081,7 @@ static const ProtobufCFieldDescriptor bitcoin_output_id__field_descriptors[2] = PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ - offsetof(BitcoinOutputId, txid), + offsetof(BitcoinInput, txid), &sha256_hash__descriptor, NULL, 0, /* flags */ @@ -964,35 +1093,61 @@ static const ProtobufCFieldDescriptor bitcoin_output_id__field_descriptors[2] = PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_UINT32, 0, /* quantifier_offset */ - offsetof(BitcoinOutputId, output), + offsetof(BitcoinInput, output), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "subscript", + 3, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_BYTES, + 0, /* quantifier_offset */ + offsetof(BitcoinInput, subscript), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "amount", + 4, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_UINT64, + 0, /* quantifier_offset */ + offsetof(BitcoinInput, amount), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; -static const unsigned bitcoin_output_id__field_indices_by_name[] = { +static const unsigned bitcoin_input__field_indices_by_name[] = { + 3, /* field[3] = amount */ 1, /* field[1] = output */ + 2, /* field[2] = subscript */ 0, /* field[0] = txid */ }; -static const ProtobufCIntRange bitcoin_output_id__number_ranges[1 + 1] = +static const ProtobufCIntRange bitcoin_input__number_ranges[1 + 1] = { { 1, 0 }, - { 0, 2 } + { 0, 4 } }; -const ProtobufCMessageDescriptor bitcoin_output_id__descriptor = +const ProtobufCMessageDescriptor bitcoin_input__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "bitcoin_output_id", - "BitcoinOutputId", - "BitcoinOutputId", + "bitcoin_input", + "BitcoinInput", + "BitcoinInput", "", - sizeof(BitcoinOutputId), - 2, - bitcoin_output_id__field_descriptors, - bitcoin_output_id__field_indices_by_name, - 1, bitcoin_output_id__number_ranges, - (ProtobufCMessageInit) bitcoin_output_id__init, + sizeof(BitcoinInput), + 4, + bitcoin_input__field_descriptors, + bitcoin_input__field_indices_by_name, + 1, bitcoin_input__number_ranges, + (ProtobufCMessageInit) bitcoin_input__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor bitcoin_output__field_descriptors[2] = @@ -1084,7 +1239,45 @@ const ProtobufCMessageDescriptor bitcoin_signature__descriptor = (ProtobufCMessageInit) bitcoin_signature__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor anchor__field_descriptors[4] = +static const ProtobufCFieldDescriptor bitcoin_pubkey__field_descriptors[1] = +{ + { + "key", + 1, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_BYTES, + 0, /* quantifier_offset */ + offsetof(BitcoinPubkey, key), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned bitcoin_pubkey__field_indices_by_name[] = { + 0, /* field[0] = key */ +}; +static const ProtobufCIntRange bitcoin_pubkey__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 1 } +}; +const ProtobufCMessageDescriptor bitcoin_pubkey__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "bitcoin_pubkey", + "BitcoinPubkey", + "BitcoinPubkey", + "", + sizeof(BitcoinPubkey), + 1, + bitcoin_pubkey__field_descriptors, + bitcoin_pubkey__field_indices_by_name, + 1, bitcoin_pubkey__number_ranges, + (ProtobufCMessageInit) bitcoin_pubkey__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor anchor__field_descriptors[6] = { { "inputs", @@ -1093,23 +1286,47 @@ static const ProtobufCFieldDescriptor anchor__field_descriptors[4] = PROTOBUF_C_TYPE_MESSAGE, offsetof(Anchor, n_inputs), offsetof(Anchor, inputs), - &bitcoin_output_id__descriptor, + &bitcoin_input__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { - "anchor_change", + "change", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ - offsetof(Anchor, anchor_change), + offsetof(Anchor, change), &bitcoin_output__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, + { + "total", + 4, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_UINT64, + 0, /* quantifier_offset */ + offsetof(Anchor, total), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "pubkey", + 5, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_MESSAGE, + 0, /* quantifier_offset */ + offsetof(Anchor, pubkey), + &bitcoin_pubkey__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, { "fee", 8, @@ -1136,17 +1353,20 @@ static const ProtobufCFieldDescriptor anchor__field_descriptors[4] = }, }; static const unsigned anchor__field_indices_by_name[] = { - 1, /* field[1] = anchor_change */ - 2, /* field[2] = fee */ + 1, /* field[1] = change */ + 4, /* field[4] = fee */ 0, /* field[0] = inputs */ - 3, /* field[3] = min_confirms */ + 5, /* field[5] = min_confirms */ + 3, /* field[3] = pubkey */ + 2, /* field[2] = total */ }; -static const ProtobufCIntRange anchor__number_ranges[3 + 1] = +static const ProtobufCIntRange anchor__number_ranges[4 + 1] = { { 1, 0 }, - { 8, 2 }, - { 10, 3 }, - { 0, 4 } + { 4, 2 }, + { 8, 4 }, + { 10, 5 }, + { 0, 6 } }; const ProtobufCMessageDescriptor anchor__descriptor = { @@ -1156,10 +1376,10 @@ const ProtobufCMessageDescriptor anchor__descriptor = "Anchor", "", sizeof(Anchor), - 4, + 6, anchor__field_descriptors, anchor__field_indices_by_name, - 3, anchor__number_ranges, + 4, anchor__number_ranges, (ProtobufCMessageInit) anchor__init, NULL,NULL,NULL /* reserved[123] */ }; @@ -1333,20 +1553,20 @@ const ProtobufCMessageDescriptor open_commit_sig__descriptor = static const ProtobufCFieldDescriptor open_anchor_sig__field_descriptors[1] = { { - "sig", + "script", 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_MESSAGE, - 0, /* quantifier_offset */ - offsetof(OpenAnchorSig, sig), - &bitcoin_signature__descriptor, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_BYTES, + offsetof(OpenAnchorSig, n_script), + offsetof(OpenAnchorSig, script), + NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned open_anchor_sig__field_indices_by_name[] = { - 0, /* field[0] = sig */ + 0, /* field[0] = script */ }; static const ProtobufCIntRange open_anchor_sig__number_ranges[1 + 1] = { @@ -1368,6 +1588,44 @@ const ProtobufCMessageDescriptor open_anchor_sig__descriptor = (ProtobufCMessageInit) open_anchor_sig__init, NULL,NULL,NULL /* reserved[123] */ }; +static const ProtobufCFieldDescriptor give_early_anchor_sig_and_pretend_we_didnt__field_descriptors[1] = +{ + { + "anchor_scriptsigs", + 1, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_MESSAGE, + 0, /* quantifier_offset */ + offsetof(GiveEarlyAnchorSigAndPretendWeDidnt, anchor_scriptsigs), + &open_anchor_sig__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned give_early_anchor_sig_and_pretend_we_didnt__field_indices_by_name[] = { + 0, /* field[0] = anchor_scriptsigs */ +}; +static const ProtobufCIntRange give_early_anchor_sig_and_pretend_we_didnt__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 1 } +}; +const ProtobufCMessageDescriptor give_early_anchor_sig_and_pretend_we_didnt__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "give_early_anchor_sig_and_pretend_we_didnt", + "GiveEarlyAnchorSigAndPretendWeDidnt", + "GiveEarlyAnchorSigAndPretendWeDidnt", + "", + sizeof(GiveEarlyAnchorSigAndPretendWeDidnt), + 1, + give_early_anchor_sig_and_pretend_we_didnt__field_descriptors, + give_early_anchor_sig_and_pretend_we_didnt__field_indices_by_name, + 1, give_early_anchor_sig_and_pretend_we_didnt__number_ranges, + (ProtobufCMessageInit) give_early_anchor_sig_and_pretend_we_didnt__init, + NULL,NULL,NULL /* reserved[123] */ +}; static const ProtobufCFieldDescriptor open_complete__field_descriptors[1] = { { @@ -1626,20 +1884,20 @@ const ProtobufCMessageDescriptor new_anchor__descriptor = static const ProtobufCFieldDescriptor new_anchor_ack__field_descriptors[1] = { { - "sig", + "anchor", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ - offsetof(NewAnchorAck, sig), - &bitcoin_signature__descriptor, + offsetof(NewAnchorAck, anchor), + &anchor__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned new_anchor_ack__field_indices_by_name[] = { - 0, /* field[0] = sig */ + 0, /* field[0] = anchor */ }; static const ProtobufCIntRange new_anchor_ack__number_ranges[1 + 1] = { @@ -1661,7 +1919,7 @@ const ProtobufCMessageDescriptor new_anchor_ack__descriptor = (ProtobufCMessageInit) new_anchor_ack__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor new_anchor_accept__field_descriptors[1] = +static const ProtobufCFieldDescriptor new_anchor_commit_sig__field_descriptors[1] = { { "sig", @@ -1669,16 +1927,54 @@ static const ProtobufCFieldDescriptor new_anchor_accept__field_descriptors[1] = PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ - offsetof(NewAnchorAccept, sig), + offsetof(NewAnchorCommitSig, sig), &bitcoin_signature__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; -static const unsigned new_anchor_accept__field_indices_by_name[] = { +static const unsigned new_anchor_commit_sig__field_indices_by_name[] = { 0, /* field[0] = sig */ }; +static const ProtobufCIntRange new_anchor_commit_sig__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 1 } +}; +const ProtobufCMessageDescriptor new_anchor_commit_sig__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "new_anchor_commit_sig", + "NewAnchorCommitSig", + "NewAnchorCommitSig", + "", + sizeof(NewAnchorCommitSig), + 1, + new_anchor_commit_sig__field_descriptors, + new_anchor_commit_sig__field_indices_by_name, + 1, new_anchor_commit_sig__number_ranges, + (ProtobufCMessageInit) new_anchor_commit_sig__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor new_anchor_accept__field_descriptors[1] = +{ + { + "script", + 1, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_BYTES, + offsetof(NewAnchorAccept, n_script), + offsetof(NewAnchorAccept, script), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned new_anchor_accept__field_indices_by_name[] = { + 0, /* field[0] = script */ +}; static const ProtobufCIntRange new_anchor_accept__number_ranges[1 + 1] = { { 1, 0 }, @@ -1851,7 +2147,7 @@ const ProtobufCMessageDescriptor error__descriptor = (ProtobufCMessageInit) error__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor pkt__field_descriptors[14] = +static const ProtobufCFieldDescriptor pkt__field_descriptors[15] = { { "update", @@ -1937,6 +2233,18 @@ static const ProtobufCFieldDescriptor pkt__field_descriptors[14] = 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, + { + "omg_fail", + 205, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(Pkt, pkt_case), + offsetof(Pkt, omg_fail), + &give_early_anchor_sig_and_pretend_we_didnt__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, { "new_anchor", 301, @@ -2023,13 +2331,14 @@ static const ProtobufCFieldDescriptor pkt__field_descriptors[14] = }, }; static const unsigned pkt__field_indices_by_name[] = { - 11, /* field[11] = close */ - 12, /* field[12] = close_complete */ - 13, /* field[13] = error */ - 7, /* field[7] = new_anchor */ - 9, /* field[9] = new_anchor_accept */ - 8, /* field[8] = new_anchor_ack */ - 10, /* field[10] = new_anchor_complete */ + 12, /* field[12] = close */ + 13, /* field[13] = close_complete */ + 14, /* field[14] = error */ + 8, /* field[8] = new_anchor */ + 10, /* field[10] = new_anchor_accept */ + 9, /* field[9] = new_anchor_ack */ + 11, /* field[11] = new_anchor_complete */ + 7, /* field[7] = omg_fail */ 3, /* field[3] = open */ 5, /* field[5] = open_anchor_sig */ 4, /* field[4] = open_commit_sig */ @@ -2042,10 +2351,10 @@ static const ProtobufCIntRange pkt__number_ranges[5 + 1] = { { 1, 0 }, { 201, 3 }, - { 301, 7 }, - { 401, 11 }, - { 1000, 13 }, - { 0, 14 } + { 301, 8 }, + { 401, 12 }, + { 1000, 14 }, + { 0, 15 } }; const ProtobufCMessageDescriptor pkt__descriptor = { @@ -2055,7 +2364,7 @@ const ProtobufCMessageDescriptor pkt__descriptor = "Pkt", "", sizeof(Pkt), - 14, + 15, pkt__field_descriptors, pkt__field_indices_by_name, 5, pkt__number_ranges, diff --git a/lightning.pb-c.h b/lightning.pb-c.h index e23a06223..011ed233e 100644 --- a/lightning.pb-c.h +++ b/lightning.pb-c.h @@ -16,19 +16,22 @@ PROTOBUF_C__BEGIN_DECLS typedef struct _Sha256Hash Sha256Hash; -typedef struct _BitcoinOutputId BitcoinOutputId; +typedef struct _BitcoinInput BitcoinInput; typedef struct _BitcoinOutput BitcoinOutput; typedef struct _BitcoinSignature BitcoinSignature; +typedef struct _BitcoinPubkey BitcoinPubkey; typedef struct _Anchor Anchor; typedef struct _OpenChannel OpenChannel; typedef struct _OpenCommitSig OpenCommitSig; typedef struct _OpenAnchorSig OpenAnchorSig; +typedef struct _GiveEarlyAnchorSigAndPretendWeDidnt GiveEarlyAnchorSigAndPretendWeDidnt; typedef struct _OpenComplete OpenComplete; typedef struct _Update Update; typedef struct _UpdateAccept UpdateAccept; typedef struct _UpdateComplete UpdateComplete; typedef struct _NewAnchor NewAnchor; typedef struct _NewAnchorAck NewAnchorAck; +typedef struct _NewAnchorCommitSig NewAnchorCommitSig; typedef struct _NewAnchorAccept NewAnchorAccept; typedef struct _NewAnchorComplete NewAnchorComplete; typedef struct _CloseChannel CloseChannel; @@ -59,9 +62,9 @@ struct _Sha256Hash /* - * Identifies a bitcoin output. + * Identifies consumption of a bitcoin output. */ -struct _BitcoinOutputId +struct _BitcoinInput { ProtobufCMessage base; /* @@ -72,10 +75,18 @@ struct _BitcoinOutputId * This is the output number. */ uint32_t output; + /* + * And the subscript we're signing. + */ + ProtobufCBinaryData subscript; + /* + * The amount this input is worth. + */ + uint64_t amount; }; -#define BITCOIN_OUTPUT_ID__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&bitcoin_output_id__descriptor) \ - , NULL, 0 } +#define BITCOIN_INPUT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&bitcoin_input__descriptor) \ + , NULL, 0, {0,NULL}, 0 } /* @@ -105,6 +116,22 @@ struct _BitcoinSignature , {0,NULL} } +/* + * Pubkey for commitment transaction input. + */ +struct _BitcoinPubkey +{ + ProtobufCMessage base; + /* + * Either 65 or 33 bytes. + */ + ProtobufCBinaryData key; +}; +#define BITCOIN_PUBKEY__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&bitcoin_pubkey__descriptor) \ + , {0,NULL} } + + /* * All about an anchor transaction. */ @@ -115,15 +142,23 @@ struct _Anchor * 0 or more unspent inputs we want to use for anchor. */ size_t n_inputs; - BitcoinOutputId **inputs; + BitcoinInput **inputs; + /* + * Pubkey for anchor to pay to for commitment tx (p2sh) + */ + BitcoinPubkey *pubkey; /* * Any change from anchor (in case we don't want to use them all) */ - BitcoinOutput *anchor_change; + BitcoinOutput *change; /* * How much transaction fee we'll pay in the anchor tx. */ uint64_t fee; + /* + * How much we'll be putting into channel (== sum(inputs) - change - fee) + */ + uint64_t total; /* * How many confirmations on anchor before we'll use channel. */ @@ -131,7 +166,7 @@ struct _Anchor }; #define ANCHOR__INIT \ { PROTOBUF_C_MESSAGE_INIT (&anchor__descriptor) \ - , 0,NULL, NULL, 0, 0 } + , 0,NULL, NULL, NULL, 0, 0, 0 } typedef enum { @@ -155,7 +190,7 @@ struct _OpenChannel */ Sha256Hash *revocation_hash; /* - * How to pay money to us. + * How to pay money to us from commit_tx. */ ProtobufCBinaryData script_to_me; /* @@ -195,15 +230,35 @@ struct _OpenCommitSig /* - * Supply signature for anchor tx + * Supply ScriptSig for each anchor tx inputs. */ struct _OpenAnchorSig { ProtobufCMessage base; - BitcoinSignature *sig; + size_t n_script; + ProtobufCBinaryData *script; }; #define OPEN_ANCHOR_SIG__INIT \ { PROTOBUF_C_MESSAGE_INIT (&open_anchor_sig__descriptor) \ + , 0,NULL } + + +/* + * BROKEN AND INSECURE!!! + * This should not exist; it's completely insecure! But we need to sign + * the commitment transaction before we sign the anchor transaction, which + * doesn't work at all with current bitcoin (as we don't know the anchor + * txid until it's signed by both sides, and then we'd have to worry about + * malleability anyway). So for testing, we send the scriptsigs for the + * anchor transaction's inputs immediately. + */ +struct _GiveEarlyAnchorSigAndPretendWeDidnt +{ + ProtobufCMessage base; + OpenAnchorSig *anchor_scriptsigs; +}; +#define GIVE_EARLY_ANCHOR_SIG_AND_PRETEND_WE_DIDNT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&give_early_anchor_sig_and_pretend_we_didnt__descriptor) \ , NULL } @@ -314,12 +369,12 @@ struct _NewAnchor /* - * That seems OK to me! + * That seems OK to me, let's add these too (if any). */ struct _NewAnchorAck { ProtobufCMessage base; - BitcoinSignature *sig; + Anchor *anchor; }; #define NEW_ANCHOR_ACK__INIT \ { PROTOBUF_C_MESSAGE_INIT (&new_anchor_ack__descriptor) \ @@ -327,16 +382,30 @@ struct _NewAnchorAck /* - * Here's my signature on the new anchor to complete it. + * Now we both send signatures for new commit sig. */ -struct _NewAnchorAccept +struct _NewAnchorCommitSig { ProtobufCMessage base; BitcoinSignature *sig; }; +#define NEW_ANCHOR_COMMIT_SIG__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&new_anchor_commit_sig__descriptor) \ + , NULL } + + +/* + * Here are the script sigs for the new anchor's new inputs. + */ +struct _NewAnchorAccept +{ + ProtobufCMessage base; + size_t n_script; + ProtobufCBinaryData *script; +}; #define NEW_ANCHOR_ACCEPT__INIT \ { PROTOBUF_C_MESSAGE_INIT (&new_anchor_accept__descriptor) \ - , NULL } + , 0,NULL } /* @@ -403,6 +472,7 @@ struct _Error typedef enum { PKT__PKT__NOT_SET = 0, PKT__PKT_OPEN = 201, + PKT__PKT_OMG_FAIL = 205, PKT__PKT_OPEN_COMMIT_SIG = 202, PKT__PKT_OPEN_ANCHOR_SIG = 203, PKT__PKT_OPEN_COMPLETE = 204, @@ -430,6 +500,7 @@ struct _Pkt * Opening */ OpenChannel *open; + GiveEarlyAnchorSigAndPretendWeDidnt *omg_fail; OpenCommitSig *open_commit_sig; OpenAnchorSig *open_anchor_sig; OpenComplete *open_complete; @@ -481,24 +552,24 @@ Sha256Hash * void sha256_hash__free_unpacked (Sha256Hash *message, ProtobufCAllocator *allocator); -/* BitcoinOutputId methods */ -void bitcoin_output_id__init - (BitcoinOutputId *message); -size_t bitcoin_output_id__get_packed_size - (const BitcoinOutputId *message); -size_t bitcoin_output_id__pack - (const BitcoinOutputId *message, +/* BitcoinInput methods */ +void bitcoin_input__init + (BitcoinInput *message); +size_t bitcoin_input__get_packed_size + (const BitcoinInput *message); +size_t bitcoin_input__pack + (const BitcoinInput *message, uint8_t *out); -size_t bitcoin_output_id__pack_to_buffer - (const BitcoinOutputId *message, +size_t bitcoin_input__pack_to_buffer + (const BitcoinInput *message, ProtobufCBuffer *buffer); -BitcoinOutputId * - bitcoin_output_id__unpack +BitcoinInput * + bitcoin_input__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); -void bitcoin_output_id__free_unpacked - (BitcoinOutputId *message, +void bitcoin_input__free_unpacked + (BitcoinInput *message, ProtobufCAllocator *allocator); /* BitcoinOutput methods */ void bitcoin_output__init @@ -538,6 +609,25 @@ BitcoinSignature * void bitcoin_signature__free_unpacked (BitcoinSignature *message, ProtobufCAllocator *allocator); +/* BitcoinPubkey methods */ +void bitcoin_pubkey__init + (BitcoinPubkey *message); +size_t bitcoin_pubkey__get_packed_size + (const BitcoinPubkey *message); +size_t bitcoin_pubkey__pack + (const BitcoinPubkey *message, + uint8_t *out); +size_t bitcoin_pubkey__pack_to_buffer + (const BitcoinPubkey *message, + ProtobufCBuffer *buffer); +BitcoinPubkey * + bitcoin_pubkey__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void bitcoin_pubkey__free_unpacked + (BitcoinPubkey *message, + ProtobufCAllocator *allocator); /* Anchor methods */ void anchor__init (Anchor *message); @@ -614,6 +704,25 @@ OpenAnchorSig * void open_anchor_sig__free_unpacked (OpenAnchorSig *message, ProtobufCAllocator *allocator); +/* GiveEarlyAnchorSigAndPretendWeDidnt methods */ +void give_early_anchor_sig_and_pretend_we_didnt__init + (GiveEarlyAnchorSigAndPretendWeDidnt *message); +size_t give_early_anchor_sig_and_pretend_we_didnt__get_packed_size + (const GiveEarlyAnchorSigAndPretendWeDidnt *message); +size_t give_early_anchor_sig_and_pretend_we_didnt__pack + (const GiveEarlyAnchorSigAndPretendWeDidnt *message, + uint8_t *out); +size_t give_early_anchor_sig_and_pretend_we_didnt__pack_to_buffer + (const GiveEarlyAnchorSigAndPretendWeDidnt *message, + ProtobufCBuffer *buffer); +GiveEarlyAnchorSigAndPretendWeDidnt * + give_early_anchor_sig_and_pretend_we_didnt__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void give_early_anchor_sig_and_pretend_we_didnt__free_unpacked + (GiveEarlyAnchorSigAndPretendWeDidnt *message, + ProtobufCAllocator *allocator); /* OpenComplete methods */ void open_complete__init (OpenComplete *message); @@ -728,6 +837,25 @@ NewAnchorAck * void new_anchor_ack__free_unpacked (NewAnchorAck *message, ProtobufCAllocator *allocator); +/* NewAnchorCommitSig methods */ +void new_anchor_commit_sig__init + (NewAnchorCommitSig *message); +size_t new_anchor_commit_sig__get_packed_size + (const NewAnchorCommitSig *message); +size_t new_anchor_commit_sig__pack + (const NewAnchorCommitSig *message, + uint8_t *out); +size_t new_anchor_commit_sig__pack_to_buffer + (const NewAnchorCommitSig *message, + ProtobufCBuffer *buffer); +NewAnchorCommitSig * + new_anchor_commit_sig__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void new_anchor_commit_sig__free_unpacked + (NewAnchorCommitSig *message, + ProtobufCAllocator *allocator); /* NewAnchorAccept methods */ void new_anchor_accept__init (NewAnchorAccept *message); @@ -847,8 +975,8 @@ void pkt__free_unpacked typedef void (*Sha256Hash_Closure) (const Sha256Hash *message, void *closure_data); -typedef void (*BitcoinOutputId_Closure) - (const BitcoinOutputId *message, +typedef void (*BitcoinInput_Closure) + (const BitcoinInput *message, void *closure_data); typedef void (*BitcoinOutput_Closure) (const BitcoinOutput *message, @@ -856,6 +984,9 @@ typedef void (*BitcoinOutput_Closure) typedef void (*BitcoinSignature_Closure) (const BitcoinSignature *message, void *closure_data); +typedef void (*BitcoinPubkey_Closure) + (const BitcoinPubkey *message, + void *closure_data); typedef void (*Anchor_Closure) (const Anchor *message, void *closure_data); @@ -868,6 +999,9 @@ typedef void (*OpenCommitSig_Closure) typedef void (*OpenAnchorSig_Closure) (const OpenAnchorSig *message, void *closure_data); +typedef void (*GiveEarlyAnchorSigAndPretendWeDidnt_Closure) + (const GiveEarlyAnchorSigAndPretendWeDidnt *message, + void *closure_data); typedef void (*OpenComplete_Closure) (const OpenComplete *message, void *closure_data); @@ -886,6 +1020,9 @@ typedef void (*NewAnchor_Closure) typedef void (*NewAnchorAck_Closure) (const NewAnchorAck *message, void *closure_data); +typedef void (*NewAnchorCommitSig_Closure) + (const NewAnchorCommitSig *message, + void *closure_data); typedef void (*NewAnchorAccept_Closure) (const NewAnchorAccept *message, void *closure_data); @@ -911,19 +1048,22 @@ typedef void (*Pkt_Closure) /* --- descriptors --- */ extern const ProtobufCMessageDescriptor sha256_hash__descriptor; -extern const ProtobufCMessageDescriptor bitcoin_output_id__descriptor; +extern const ProtobufCMessageDescriptor bitcoin_input__descriptor; extern const ProtobufCMessageDescriptor bitcoin_output__descriptor; extern const ProtobufCMessageDescriptor bitcoin_signature__descriptor; +extern const ProtobufCMessageDescriptor bitcoin_pubkey__descriptor; extern const ProtobufCMessageDescriptor anchor__descriptor; extern const ProtobufCMessageDescriptor open_channel__descriptor; extern const ProtobufCMessageDescriptor open_commit_sig__descriptor; extern const ProtobufCMessageDescriptor open_anchor_sig__descriptor; +extern const ProtobufCMessageDescriptor give_early_anchor_sig_and_pretend_we_didnt__descriptor; extern const ProtobufCMessageDescriptor open_complete__descriptor; extern const ProtobufCMessageDescriptor update__descriptor; extern const ProtobufCMessageDescriptor update_accept__descriptor; extern const ProtobufCMessageDescriptor update_complete__descriptor; extern const ProtobufCMessageDescriptor new_anchor__descriptor; extern const ProtobufCMessageDescriptor new_anchor_ack__descriptor; +extern const ProtobufCMessageDescriptor new_anchor_commit_sig__descriptor; extern const ProtobufCMessageDescriptor new_anchor_accept__descriptor; extern const ProtobufCMessageDescriptor new_anchor_complete__descriptor; extern const ProtobufCMessageDescriptor close_channel__descriptor; diff --git a/lightning.proto b/lightning.proto index 82347e401..31e865fdf 100644 --- a/lightning.proto +++ b/lightning.proto @@ -13,12 +13,16 @@ message sha256_hash { required fixed64 d = 4; } -// Identifies a bitcoin output. -message bitcoin_output_id { +// Identifies consumption of a bitcoin output. +message bitcoin_input { // This is the transaction ID. required sha256_hash txid = 1; // This is the output number. required uint32 output = 2; + // And the subscript we're signing. + required bytes subscript = 3; + // The amount this input is worth. + required uint64 amount = 4; } // A bitcoin output @@ -32,14 +36,24 @@ message bitcoin_signature { required bytes der_then_sigtype = 1; }; +// Pubkey for commitment transaction input. +message bitcoin_pubkey { + // Either 65 or 33 bytes. + required bytes key = 1; +}; + // All about an anchor transaction. message anchor { // 0 or more unspent inputs we want to use for anchor. - repeated bitcoin_output_id inputs = 1; + repeated bitcoin_input inputs = 1; + // Pubkey for anchor to pay to for commitment tx (p2sh) + required bitcoin_pubkey pubkey = 5; // Any change from anchor (in case we don't want to use them all) - optional bitcoin_output anchor_change = 2; + optional bitcoin_output change = 2; // How much transaction fee we'll pay in the anchor tx. required uint64 fee = 8; + // How much we'll be putting into channel (== sum(inputs) - change - fee) + required uint64 total = 4; // How many confirmations on anchor before we'll use channel. required uint32 min_confirms = 10; } @@ -59,7 +73,7 @@ message open_channel { } // Hash seed for revoking commitment transactions. required sha256_hash revocation_hash = 4; - // How to pay money to us. + // How to pay money to us from commit_tx. required bytes script_to_me = 5; // How much transaction fee we'll pay for commitment txs. required uint64 commitment_fee = 6; @@ -74,9 +88,21 @@ message open_commit_sig { required bitcoin_signature sig = 1; } -// Supply signature for anchor tx +// Supply ScriptSig for each anchor tx inputs. message open_anchor_sig { - required bitcoin_signature sig = 1; + repeated bytes script = 1; +} + +// BROKEN AND INSECURE!!! +// +// This should not exist; it's completely insecure! But we need to sign +// the commitment transaction before we sign the anchor transaction, which +// doesn't work at all with current bitcoin (as we don't know the anchor +// txid until it's signed by both sides, and then we'd have to worry about +// malleability anyway). So for testing, we send the scriptsigs for the +// anchor transaction's inputs immediately. +message give_early_anchor_sig_and_pretend_we_didnt { + required open_anchor_sig anchor_scriptsigs = 1; } // Indicates we've seen transaction reach min-depth. @@ -121,14 +147,19 @@ message new_anchor { required anchor anchor = 1; } -// That seems OK to me! +// That seems OK to me, let's add these too (if any). message new_anchor_ack { + required anchor anchor = 1; +} + +// Now we both send signatures for new commit sig. +message new_anchor_commit_sig { required bitcoin_signature sig = 1; } -// Here's my signature on the new anchor to complete it. +// Here are the script sigs for the new anchor's new inputs. message new_anchor_accept { - required bitcoin_signature sig = 1; + repeated bytes script = 1; } // Complete the transfer to new anchor (both ends need to send this, @@ -161,6 +192,7 @@ message pkt { oneof pkt { // Opening open_channel open = 201; + give_early_anchor_sig_and_pretend_we_didnt omg_fail = 205; open_commit_sig open_commit_sig = 202; open_anchor_sig open_anchor_sig = 203; open_complete open_complete = 204; diff --git a/open-anchor-sig.c b/open-anchor-sig.c new file mode 100644 index 000000000..1dec773c9 --- /dev/null +++ b/open-anchor-sig.c @@ -0,0 +1,197 @@ +/* My example: + * ./open-anchor-sig A-open.pb B-open.pb cUjoranStkpgTRumAJZNiNEkknJv5UA7wzW1nZ7aPsm9ZWjkxypZ > A-anchor-scriptsigs.pb + * ./open-anchor-sig B-open.pb A-open.pb cNggXygY8fPHWHEdoDqRa6xALau8gVMLq6q6vzMs2eNegLrJGNAW > B-anchor-scriptsigs.pb + */ +#include +#include +#include +#include "bitcoin_tx.h" +#include "signature.h" +#include "lightning.pb-c.h" +#include "overflows.h" +#include "pkt.h" +#include "bitcoin_script.h" +#include "perturb.h" +#include "bitcoin_address.h" +#include "base58.h" + +#include +#include + +/* Produce an anchor transaction from what both sides want. */ +static struct bitcoin_tx *merge_transaction(const tal_t *ctx, + const OpenChannel *o1, + const OpenChannel *o2, + size_t *inmap) +{ + uint64_t i; + struct bitcoin_tx *tx = tal(ctx, struct bitcoin_tx); + u8 *redeemscript; + + /* Use lesser of two versions. */ + if (o1->tx_version < o2->tx_version) + tx->version = o1->tx_version; + else + tx->version = o2->tx_version; + + if (add_overflows_size_t(o1->anchor->n_inputs, o2->anchor->n_inputs)) + return tal_free(tx); + tx->input_count = o1->anchor->n_inputs + o2->anchor->n_inputs; + + tx->input = tal_arr(tx, struct bitcoin_tx_input, tx->input_count); + /* Populate inputs. */ + for (i = 0; i < o1->anchor->n_inputs; i++) { + BitcoinInput *pb = o1->anchor->inputs[i]; + struct bitcoin_tx_input *in = &tx->input[i]; + proto_to_sha256(pb->txid, &in->txid.sha); + in->index = pb->output; + in->sequence_number = 0xFFFFFFFF; + /* Leave inputs as stubs for now, for signing. */ + in->script_length = 0; + in->script = NULL; + } + for (i = 0; i < o2->anchor->n_inputs; i++) { + BitcoinInput *pb = o2->anchor->inputs[i]; + struct bitcoin_tx_input *in + = &tx->input[o1->anchor->n_inputs + i]; + proto_to_sha256(pb->txid, &in->txid.sha); + in->index = pb->output; + in->sequence_number = 0xFFFFFFFF; + /* Leave inputs as stubs for now, for signing. */ + in->script_length = 0; + in->script = NULL; + } + + /* Populate outputs. */ + tx->output_count = 1; + /* Allocate for worst case. */ + tx->output = tal_arr(tx, struct bitcoin_tx_output, 3); + + if (add_overflows_u64(o1->anchor->total, o2->anchor->total)) + return tal_free(tx); + + /* Make the 2 of 2 payment for the commitment txs. */ + redeemscript = bitcoin_redeem_2of2(tx, o1->anchor->pubkey, + o2->anchor->pubkey); + tx->output[0].amount = o1->anchor->total + o2->anchor->total; + tx->output[0].script = scriptpubkey_p2sh(tx, redeemscript); + tx->output[0].script_length = tal_count(tx->output[0].script); + + /* Add change transactions (if any) */ + if (o1->anchor->change) { + struct bitcoin_tx_output *out = &tx->output[tx->output_count++]; + out->amount = o1->anchor->change->amount; + out->script_length = o1->anchor->change->script.len; + out->script = o1->anchor->change->script.data; + } + if (o2->anchor->change) { + struct bitcoin_tx_output *out = &tx->output[tx->output_count++]; + out->amount = o2->anchor->change->amount; + out->script_length = o2->anchor->change->script.len; + out->script = o2->anchor->change->script.data; + } + + perturb_inputs(o1->seed, o2->seed, 0, tx->input, tx->input_count, inmap); + perturb_outputs(o1->seed, o2->seed, 0, tx->output, tx->output_count, NULL); + return tx; +} + +/* All the input scripts are already set to 0. We just need to make this one. */ +static u8 *sign_tx_input(const tal_t *ctx, + struct bitcoin_tx *tx, + unsigned int i, + const BitcoinInput *input, + EC_KEY *privkey, + const struct bitcoin_compressed_pubkey *pubkey) +{ + struct sha256_double hash; + struct sha256_ctx shactx; + struct bitcoin_address addr; + u8 *sig; + + /* Transaction gets signed as if the output subscript is the + * only input script. */ + tx->input[i].script_length = input->subscript.len; + tx->input[i].script = input->subscript.data; + + sha256_init(&shactx); + sha256_tx(&shactx, tx); + sha256_le32(&shactx, SIGHASH_ALL); + sha256_double_done(&shactx, &hash); + + /* Reset it for next time. */ + tx->input[i].script_length = 0; + tx->input[i].script = NULL; + + sig = sign_hash(ctx, privkey, &hash); + if (!sig) + return NULL; + + if (!is_pay_to_pubkey_hash(&input->subscript)) + errx(1, "FIXME: Don't know how to handle input"); + bitcoin_address(pubkey, &addr); + return scriptsig_pay_to_pubkeyhash(ctx, &addr, sig, tal_count(sig)); +} + +int main(int argc, char *argv[]) +{ + OpenChannel *o1, *o2; + const tal_t *ctx = tal_arr(NULL, char, 0); + struct bitcoin_tx *anchor; + struct pkt *pkt; + size_t i; + u8 **sigs; + size_t *map; + + err_set_progname(argv[0]); + + opt_register_noarg("--help|-h", opt_usage_and_exit, + " ...\n" + "Create signatures for transactions, and output to stdout", + "Print this message."); + + opt_parse(&argc, argv, opt_log_stderr_exit); + + if (argc < 3) + opt_usage_and_exit(NULL); + + o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open; + o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open; + map = tal_arr(ctx, size_t, o1->anchor->n_inputs + o2->anchor->n_inputs); + + /* Create merged transaction */ + anchor = merge_transaction(ctx, o1, o2, map); + if (!anchor) + errx(1, "Failed transaction merge"); + + /* Sign our inputs. */ + if (o1->anchor->n_inputs != argc - 3) + errx(1, "Expected %zu private keys", o1->anchor->n_inputs); + + sigs = tal_arr(ctx, u8 *, o1->anchor->n_inputs); + for (i = 0; i < o1->anchor->n_inputs; i++) { + /* FIXME: Support non-compressed keys? */ + struct bitcoin_compressed_pubkey pubkey; + EC_KEY *privkey; + bool testnet; + + privkey = key_from_base58(argv[3+i], strlen(argv[3+i]), + &testnet, &pubkey); + if (!privkey) + errx(1, "Invalid private key '%s'", argv[3+i]); + if (!testnet) + errx(1, "Private key '%s' not on testnet!", argv[3+i]); + + sigs[i] = sign_tx_input(sigs, anchor, map[i], + o1->anchor->inputs[i], + privkey, &pubkey); + } + + pkt = open_anchor_sig_pkt(ctx, sigs, o1->anchor->n_inputs); + if (!write_all(STDOUT_FILENO, pkt, + sizeof(pkt->len) + le32_to_cpu(pkt->len))) + err(1, "Writing out packet"); + + tal_free(ctx); + return 0; +} diff --git a/open-channel.c b/open-channel.c index 8e3534da4..c24b3989f 100644 --- a/open-channel.c +++ b/open-channel.c @@ -1,3 +1,7 @@ +/* My example: + * ./open-channel 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff 50000000000 mzqiPPbjTdcgM6NpNWJLHFt29tWD69bciE cUBCjrdJu8tfvM7FT8So6aqs6G6bZS1Cax6Rc9rFzYL6nYG4XNEC mi1BzT4tCB7K4kZH3yK1hM517bXH4pNmEH 08ffaf638849198f9c8f04aa75d225a5a104d5e7c540770ca55ad08b9a32d10c/1/100000000000/76a9148d2d939aa2aff2d341cde3e61a89bf9c2c21d12388ac > A-open.pb + * ./open-channel 112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00 9795000 mpDyc5kPAJZB7Zz9iW9acq3Jk8yiTJ7HKj cQXhbUnNRsFcdzTQwjbCrud5yVskHTEas7tZPUWoJYNk5htGQrpi mrvw5JC5SKcEsRpSaRss6A3jLR6DMwpxep 8cb044605f33ca907b966701f49e0bd80b4294696b57f8cf45f22398a1e63a23/0/9800000/76a9143b2aab840afb327a12c8a90fb4ed45b6892eb80988ac > B-open.pb + */ #include #include #include @@ -8,6 +12,7 @@ #include "lightning.pb-c.h" #include "base58.h" #include "pkt.h" +#include "bitcoin_script.h" #include #include @@ -32,40 +37,41 @@ static void opt_show_bits(char buf[OPT_SHOW_LEN], const u64 *bits) opt_show_ulonglongval_si(buf, &ll); } -static BitcoinOutputId *parse_anchor_input(const tal_t *ctx, const char *spec) +static BitcoinInput *parse_anchor_input(const tal_t *ctx, const char *spec) { - BitcoinOutputId *o = tal(ctx, BitcoinOutputId); + BitcoinInput *in = tal(ctx, BitcoinInput); struct sha256 txid; const char *slash; char *end; long l; - bitcoin_output_id__init(o); + bitcoin_input__init(in); slash = strchr(spec, '/'); if (!slash) - errx(1, "Expected / in /"); - o->output = l = strtol(slash + 1, &end, 10); - if (end == slash + 1 || *end || (int64_t)o->output != (int64_t)l) - errx(1, "Expected after /"); + errx(1, "Expected / in ///"); if (!hex_decode(spec, slash - spec, &txid, sizeof(txid))) errx(1, "Expected 256-bit hex txid before /"); + in->txid = sha256_to_proto(in, &txid); - o->txid = proto_sha256_hash(o, &txid); - return o; -} + in->output = l = strtol(slash + 1, &end, 10); + if (end == slash + 1 || *end != '/' || (int64_t)in->output != (int64_t)l) + errx(1, "Expected after /"); -static u8 *pay_to_pubkey(const tal_t *ctx, const struct bitcoin_address *addr) -{ - u8 *script = tal_arr(ctx, u8, 2 + 20 + 2); - script[0] = 0x76; /* OP_DUP */ - script[1] = 0xA9; /* OP_HASH160 */ - memcpy(script+2, addr, 20); - script[22] = 0x88; /* OP_EQUALVERIFY */ - script[23] = 0xAC; /* OP_CHECKSIG */ + slash = end; + in->amount = l = strtol(slash + 1, &end, 10); + if (end == slash + 1 || *end != '/' || (int64_t)in->amount != (int64_t)l) + errx(1, "Expected after second /"); - return script; + slash = end; + in->subscript.len = strlen(slash + 1) / 2; + in->subscript.data = tal_arr(in, u8, in->subscript.len); + if (!hex_decode(slash + 1, strlen(slash + 1), + in->subscript.data, in->subscript.len)) + errx(1, "Expected hex string after third /"); + + return in; } /* FIXME: This is too weak, even for us! */ @@ -78,17 +84,17 @@ static u64 weak_random64(void) int main(int argc, char *argv[]) { struct sha256 seed, revocation_hash; - struct bitcoin_address ouraddr; - EC_KEY *privkey; + struct bitcoin_address changeaddr, returnaddr; struct pkt *pkt; const tal_t *ctx = tal_arr(NULL, char, 0); Anchor anchor = ANCHOR__INIT; - u64 commit_tx_fee; + u64 commit_tx_fee, total_in; unsigned int locktime_seconds; bool testnet; - struct bitcoin_compressed_pubkey pubkey; u8 *script_to_me; size_t i; + struct bitcoin_compressed_pubkey commitkey; + EC_KEY *commitprivkey; err_set_progname(argv[0]); @@ -102,7 +108,7 @@ int main(int argc, char *argv[]) locktime_seconds = LOCKTIME_MIN + 24 * 60 * 60; opt_register_noarg("--help|-h", opt_usage_and_exit, - " /...\n" + " ///...\n" "A test program to output openchannel on stdout.", "Print this message."); opt_register_arg("--min-anchor-confirms", @@ -111,44 +117,75 @@ int main(int argc, char *argv[]) opt_register_arg("--anchor-fee=", opt_set_bits, opt_show_bits, &anchor.fee, "100's of satoshi to pay for anchor"); - opt_register_arg("--commitment-fee=", - opt_set_bits, opt_show_bits, &commit_tx_fee, - "100's of satoshi to pay for commitment"); opt_register_arg("--locktime=", opt_set_uintval, opt_show_uintval, &locktime_seconds, "Seconds to lock out our transaction redemption"); - /* FIXME: Implement change address and amount. */ opt_parse(&argc, argv, opt_log_stderr_exit); - if (argc < 5) + if (argc < 7) opt_usage_and_exit(NULL); if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed))) errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]); - privkey = key_from_base58(argv[2], strlen(argv[2]), &testnet, &pubkey); - if (!privkey) - errx(1, "Invalid private key '%s'", argv[2]); - if (!testnet) - errx(1, "Private key '%s' not a testnet key!", argv[2]); + anchor.total = atol(argv[2]); + if (!anchor.total) + errx(1, "Invalid total: must be > 0"); - if (!bitcoin_from_base58(&testnet, &ouraddr, argv[3], strlen(argv[3]))) + if (!bitcoin_from_base58(&testnet, &changeaddr, argv[3], strlen(argv[3]))) errx(1, "Invalid bitcoin address '%s'", argv[3]); if (!testnet) errx(1, "Bitcoin address '%s' not on testnet!", argv[3]); + + /* We don't really need the privkey here, but it's the most + * convenient way to get the pubkey from bitcoind. */ + commitprivkey = key_from_base58(argv[4], strlen(argv[4]), &testnet, + &commitkey); + if (!commitprivkey) + errx(1, "Invalid private key '%s'", argv[4]); + if (!testnet) + errx(1, "Private key '%s' not on testnet!", argv[4]); + + if (!bitcoin_from_base58(&testnet, &returnaddr, argv[5], strlen(argv[5]))) + errx(1, "Invalid bitcoin address '%s'", argv[5]); + if (!testnet) + errx(1, "Bitcoin address '%s' not on testnet!", argv[5]); - anchor.n_inputs = (argc - 4); - anchor.inputs = tal_arr(ctx, BitcoinOutputId *, anchor.n_inputs); + anchor.n_inputs = (argc - 6); + anchor.inputs = tal_arr(ctx, BitcoinInput *, anchor.n_inputs); + anchor.pubkey = pubkey_to_proto(ctx, &commitkey); - for (i = 0; i < anchor.n_inputs; i++) - anchor.inputs[i] = parse_anchor_input(anchor.inputs, argv[i+4]); + total_in = 0; + for (i = 0; i < anchor.n_inputs; i++) { + anchor.inputs[i] = parse_anchor_input(anchor.inputs, argv[i+6]); + total_in += anchor.inputs[i]->amount; + } + if (total_in < anchor.total + anchor.fee) + errx(1, "Only %llu satoshi in, and %llu out (+%llu fee)", + (unsigned long long)total_in, + (unsigned long long)anchor.total, + (unsigned long long)anchor.fee); + + /* If there's change, say where to send it. */ + if (total_in != anchor.total + anchor.fee) { + anchor.change = tal(ctx, BitcoinOutput); + bitcoin_output__init(anchor.change); + anchor.change->amount = total_in - (anchor.total + anchor.fee); + /* FIXME: Use p2sh? */ + anchor.change->script.data + = scriptpubkey_pay_to_pubkeyhash(anchor.change, + &changeaddr); + anchor.change->script.len + = tal_count(anchor.change->script.data); + } + /* Get first revocation hash. */ shachain_from_seed(&seed, 0, &revocation_hash); /* Make simple output script to pay to my pubkey. */ - script_to_me = pay_to_pubkey(ctx, &ouraddr); + script_to_me = scriptpubkey_pay_to_pubkeyhash(ctx, &returnaddr); pkt = openchannel_pkt(ctx, weak_random64(), &revocation_hash, tal_count(script_to_me), script_to_me, diff --git a/overflows.h b/overflows.h new file mode 100644 index 000000000..1af031538 --- /dev/null +++ b/overflows.h @@ -0,0 +1,14 @@ +#ifndef LIGHTNING_OVERFLOWS_H +#define LIGHTNING_OVERFLOWS_H + +static inline bool add_overflows_size_t(uint64_t a, uint64_t b) +{ + return (size_t)a != a || (size_t)b != b || (a + b) < (size_t)a; +} + +static inline bool add_overflows_u64(uint64_t a, uint64_t b) +{ + return (a + b) < a; +} + +#endif /* LIGHTNING_OVERFLOWS_H */ diff --git a/pd_channel.h b/pd_channel.h deleted file mode 100644 index 4926eb8e6..000000000 --- a/pd_channel.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Poon-Dryja Generalized Channel Implementation. - * - * It's fairly symmetrical, but for clarity the api divides into - * client and server. - */ - -/* Construct the inputs they want to use. */ -struct input *pd_ask_anchor_inputs(void); - - - - -/* Client creates an unsigned transaction using their own funds: */ -struct tx *client_anchor_tx(struct input *spend, u64 amount); - -/* Then, from that we create an updatable commitment transaction, - * with two outputs (one is zero val). */ - - diff --git a/perturb.c b/perturb.c new file mode 100644 index 000000000..078ae9aef --- /dev/null +++ b/perturb.c @@ -0,0 +1,186 @@ +#include "perturb.h" +#include +#include +#include + +static u32 get_next_rand(struct sha256 *h, size_t *randidx) +{ + u32 ret = h->u.u32[(*randidx)++]; + if (*randidx == 8) { + *randidx = 0; + sha256(h, h, sizeof(*h)); + } + return ret; +} + +static void init_rand(struct sha256 *h, size_t *randidx, + uint64_t seed1, uint64_t seed2, + uint64_t transaction_num, + enum perturb_style style) +{ + struct sha256_ctx shactx; + + sha256_init(&shactx); + if (seed1 < seed2) { + sha256_le64(&shactx, seed1); + sha256_le64(&shactx, seed2); + } else { + sha256_le64(&shactx, seed2); + sha256_le64(&shactx, seed1); + } + sha256_le64(&shactx, transaction_num); + sha256_u8(&shactx, style); + sha256_done(&shactx, h); + *randidx = 0; +} + +static void init_map(size_t *map, size_t len) +{ + size_t i; + + if (!map) + return; + + for (i = 0; i < len; i++) + map[i] = i; +} + +static bool input_better(const struct bitcoin_tx_input *a, + const struct bitcoin_tx_input *b) +{ + int cmp; + + cmp = memcmp(&a->txid, &b->txid, sizeof(a->txid)); + if (cmp != 0) + return cmp < 0; + if (a->index != b->index) + return a->index < b->index; + + /* These shouldn't happen, but let's get a canonical order anyway. */ + if (a->script_length != b->script_length) + return a->script_length < b->script_length; + cmp = memcmp(a->script, b->script, a->script_length); + if (cmp != 0) + return cmp < 0; + return a->sequence_number < b->sequence_number; +} + +static size_t find_best_in(struct bitcoin_tx_input *inputs, size_t num) +{ + size_t i, best = 0; + + for (i = 1; i < num; i++) { + if (input_better(&inputs[i], &inputs[best])) + best = i; + } + return best; +} + +static void swap_inputs(struct bitcoin_tx_input *inputs, size_t *map, + size_t i1, size_t i2) +{ + struct bitcoin_tx_input tmpinput; + size_t tmpidx; + + tmpinput = inputs[i1]; + inputs[i1] = inputs[i2]; + inputs[i2] = tmpinput; + + if (map) { + tmpidx = map[i1]; + map[i1] = map[i2]; + map[i2] = tmpidx; + } +} + +void perturb_inputs(uint64_t seed1, uint64_t seed2, uint64_t tx_num, + struct bitcoin_tx_input *inputs, + size_t num_inputs, + size_t *map) +{ + struct sha256 h; + size_t i, randidx; + + init_map(map, num_inputs); + + /* Now do a dumb sort (num_inputs is small). */ + for (i = 0; i < num_inputs; i++) { + /* Swap best into first place. */ + swap_inputs(inputs, map, + i, i + find_best_in(inputs + i, num_inputs - i)); + } + + init_rand(&h, &randidx, seed1, seed2, tx_num, PERTURB_INPUT_STYLE); + + /* Now, Fisher-Yates shuffle, but using SHA256 as "random" source. */ + for (i = 0; i + 1 < num_inputs; i++) { + size_t r = get_next_rand(&h, &randidx) % (num_inputs - i - 1); + swap_inputs(inputs, map, i, i + 1 + r); + } +} + +static void swap_outputs(struct bitcoin_tx_output *outputs, size_t *map, + size_t i1, size_t i2) +{ + struct bitcoin_tx_output tmpoutput; + size_t tmpidx; + + tmpoutput = outputs[i1]; + outputs[i1] = outputs[i2]; + outputs[i2] = tmpoutput; + + if (map) { + tmpidx = map[i1]; + map[i1] = map[i2]; + map[i2] = tmpidx; + } +} + +static bool output_better(const struct bitcoin_tx_output *a, + const struct bitcoin_tx_output *b) +{ + if (a->amount != b->amount) + return a->amount < b->amount; + + if (a->script_length != b->script_length) + return a->script_length < b->script_length; + + return memcmp(a->script, b->script, a->script_length) < 0; +} + +static size_t find_best_out(struct bitcoin_tx_output *outputs, size_t num) +{ + size_t i, best = 0; + + for (i = 1; i < num; i++) { + if (output_better(&outputs[i], &outputs[best])) + best = i; + } + return best; +} + +void perturb_outputs(uint64_t seed1, uint64_t seed2, size_t tx_num, + struct bitcoin_tx_output *outputs, + size_t num_outputs, + size_t *map) +{ + struct sha256 h; + size_t i, randidx; + + init_map(map, num_outputs); + + /* Now do a dumb sort (num_outputs is small). */ + for (i = 0; i < num_outputs; i++) { + /* Swap best into first place. */ + swap_outputs(outputs, map, + i, i + find_best_out(outputs + i, num_outputs - i)); + } + + init_rand(&h, &randidx, seed1, seed2, tx_num, PERTURB_OUTPUT_STYLE); + + /* Now, Fisher-Yates shuffle, but using SHA256 as "random" source. */ + for (i = 0; i + 1 < num_outputs; i++) { + size_t r = get_next_rand(&h, &randidx) % (num_outputs - i - 1); + swap_outputs(outputs, map, i, i + 1 + r); + } +} diff --git a/perturb.h b/perturb.h new file mode 100644 index 000000000..9072c3fb5 --- /dev/null +++ b/perturb.h @@ -0,0 +1,25 @@ +#ifndef LIGHTNING_PERTURB_H +#define LIGHTNING_PERTURB_H +#include "bitcoin_tx.h" + +/* Given the two seeds, perturb the transaction inputs. + * map[0] is set to the new index of input 0, etc. + */ +void perturb_inputs(uint64_t seed1, uint64_t seed2, + size_t transaction_num, + struct bitcoin_tx_input *inputs, + size_t num_inputs, + size_t *map); + +void perturb_outputs(uint64_t seed1, uint64_t seed2, + size_t transaction_num, + struct bitcoin_tx_output *outputs, + size_t num_outputs, + size_t *map); + +enum perturb_style { + PERTURB_INPUT_STYLE = 0, + PERTURB_OUTPUT_STYLE = 1 +}; + +#endif /* LIGHTNING_PERTURB_H */ diff --git a/pkt.c b/pkt.c index a06a9a5f5..a0f5e0b08 100644 --- a/pkt.c +++ b/pkt.c @@ -1,6 +1,11 @@ #include +#include +#include #include "pkt.h" +#include "bitcoin_tx.h" +#include "bitcoin_address.h" +#include static struct pkt *to_pkt(const tal_t *ctx, Pkt__PktCase type, void *msg) { struct pkt *ret; @@ -14,11 +19,12 @@ static struct pkt *to_pkt(const tal_t *ctx, Pkt__PktCase type, void *msg) len = pkt__get_packed_size(&p); ret = (struct pkt *)tal_arr(ctx, u8, sizeof(ret->len) + len); ret->len = cpu_to_le32(len); + pkt__pack(&p, ret->data); return ret; } -Sha256Hash *proto_sha256_hash(const tal_t *ctx, const struct sha256 *hash) +Sha256Hash *sha256_to_proto(const tal_t *ctx, const struct sha256 *hash) { Sha256Hash *h = tal(ctx, Sha256Hash); sha256_hash__init(h); @@ -31,6 +37,26 @@ Sha256Hash *proto_sha256_hash(const tal_t *ctx, const struct sha256 *hash) return h; } +void proto_to_sha256(const Sha256Hash *pb, struct sha256 *hash) +{ + /* Kill me again. */ + memcpy(hash->u.u8, &pb->a, 8); + memcpy(hash->u.u8 + 8, &pb->b, 8); + memcpy(hash->u.u8 + 16, &pb->c, 8); + memcpy(hash->u.u8 + 24, &pb->d, 8); +} + +BitcoinPubkey *pubkey_to_proto(const tal_t *ctx, + const struct bitcoin_compressed_pubkey *key) +{ + BitcoinPubkey *p = tal(ctx, BitcoinPubkey); + + bitcoin_pubkey__init(p); + p->key.data = tal_dup_arr(ctx, u8, key->key, sizeof(key->key), 0); + p->key.len = sizeof(key->key); + return p; +} + struct pkt *openchannel_pkt(const tal_t *ctx, u64 seed, const struct sha256 *revocation_hash, @@ -42,15 +68,66 @@ struct pkt *openchannel_pkt(const tal_t *ctx, { OpenChannel o = OPEN_CHANNEL__INIT; + /* Required fields must be set: pack functions don't check! */ + assert(anchor->inputs); + assert(anchor->pubkey); + o.seed = seed; - o.revocation_hash = proto_sha256_hash(ctx, revocation_hash); + o.revocation_hash = sha256_to_proto(ctx, revocation_hash); o.script_to_me.len = script_len; o.script_to_me.data = (void *)script; o.commitment_fee = commitment_fee; o.anchor = anchor; o.locktime_case = OPEN_CHANNEL__LOCKTIME_LOCKTIME_SECONDS; o.locktime_seconds = rel_locktime_seconds; - o.tx_version = 1; - + o.tx_version = BITCOIN_TX_VERSION; + + { + size_t len = open_channel__get_packed_size(&o); + unsigned char *pb = malloc(len); + open_channel__pack(&o, pb); + assert(open_channel__unpack(NULL, len, pb)); + } + return to_pkt(ctx, PKT__PKT_OPEN, &o); } + +Pkt *pkt_from_file(const char *filename, Pkt__PktCase expect) +{ + struct pkt *pkt; + Pkt *ret; + size_t len; + + pkt = grab_file(NULL, filename); + if (!pkt) + err(1, "Opening %s", filename); + + len = tal_count(pkt) - 1; + if (len < sizeof(pkt->len) + || len != sizeof(pkt->len) + le32_to_cpu(pkt->len)) + errx(1, "%s length is wrong", filename); + len -= sizeof(pkt->len); + + ret = pkt__unpack(NULL, len, pkt->data); + if (!ret) + errx(1, "Unpack failed for %s", filename); + + if (ret->pkt_case != expect) + errx(1, "Unexpected type %i in %s", ret->pkt_case, filename); + return ret; +} + +struct pkt *open_anchor_sig_pkt(const tal_t *ctx, u8 **sigs, size_t num_sigs) +{ + OpenAnchorSig o = OPEN_ANCHOR_SIG__INIT; + size_t i; + + o.n_script = num_sigs; + o.script = tal_arr(ctx, ProtobufCBinaryData, num_sigs); + for (i = 0; i < num_sigs; i++) { + o.script[i].data = sigs[i]; + o.script[i].len = tal_count(sigs[i]); + } + + return to_pkt(ctx, PKT__PKT_OPEN_ANCHOR_SIG, &o); +} diff --git a/pkt.h b/pkt.h index 84aded907..3e91397ee 100644 --- a/pkt.h +++ b/pkt.h @@ -16,10 +16,14 @@ struct pkt { u8 data[]; }; +/* Utility helper: dies if there's a problem. */ +Pkt *pkt_from_file(const char *filename, Pkt__PktCase expect); + struct sha256; +struct bitcoin_compressed_pubkey; /** - * tal_openchannel - create an openchannel message + * openchannel_pkt - create an openchannel message * @ctx: tal context to allocate off. * @seed: psuedo-random seed to shuffle inputs. * @revocation_hash: first hash value generated from seed. @@ -37,8 +41,18 @@ struct pkt *openchannel_pkt(const tal_t *ctx, u32 rel_locktime_seconds, Anchor *anchor); +/** + * open_anchor_sig_pkt - create an open_anchor_sig message + * @ctx: tal context to allocate off. + * @sigs: the der-encoded signatures (tal_count() gives len). + * @num_sigs: the number of sigs. + */ +struct pkt *open_anchor_sig_pkt(const tal_t *ctx, u8 **sigs, size_t num_sigs); /* Useful helper for allocating & populating a protobuf Sha256Hash */ -Sha256Hash *proto_sha256_hash(const tal_t *ctx, const struct sha256 *hash); +Sha256Hash *sha256_to_proto(const tal_t *ctx, const struct sha256 *hash); +void proto_to_sha256(const Sha256Hash *pb, struct sha256 *hash); +BitcoinPubkey *pubkey_to_proto(const tal_t *ctx, + const struct bitcoin_compressed_pubkey *key); #endif /* LIGHTNING_PKT_H */ diff --git a/signature.c b/signature.c new file mode 100644 index 000000000..d9cd51941 --- /dev/null +++ b/signature.c @@ -0,0 +1,45 @@ +#include "signature.h" +#include "shadouble.h" +#include +#include +#include + +u8 *sign_hash(const tal_t *ctx, EC_KEY *private_key, + const struct sha256_double *h) +{ + ECDSA_SIG *sig; + int len; + unsigned char *der, *ret; + + sig = ECDSA_do_sign(h->sha.u.u8, sizeof(*h), private_key); + if (!sig) + return NULL; + + /* See https://github.com/sipa/bitcoin/commit/a81cd9680. + * There can only be one signature with an even S, so make sure we + * get that one. */ + if (BN_is_odd(sig->s)) { + const EC_GROUP *group; + BIGNUM order; + + BN_init(&order); + group = EC_KEY_get0_group(private_key); + EC_GROUP_get_order(group, &order, NULL); + BN_sub(sig->s, &order, sig->s); + BN_free(&order); + + assert(!BN_is_odd(sig->s)); + } + + /* This tells it to allocate for us. */ + der = NULL; + len = i2d_ECDSA_SIG(sig, &der); + ECDSA_SIG_free(sig); + + if (len <= 0) + return NULL; + + ret = tal_dup_arr(ctx, u8, der, len, 0); + OPENSSL_free(der); + return ret; +} diff --git a/signature.h b/signature.h new file mode 100644 index 000000000..a819e741a --- /dev/null +++ b/signature.h @@ -0,0 +1,19 @@ +#ifndef LIGHTNING_SIGNATURE_H +#define LIGHTNING_SIGNATURE_H +#include +#include +#include + +enum sighash_type { + SIGHASH_ALL = 1, + SIGHASH_NONE = 2, + SIGHASH_SINGLE = 3, + SIGHASH_ANYONECANPAY = 0x80 +}; + +struct sha256_double; + +u8 *sign_hash(const tal_t *ctx, EC_KEY *private_key, + const struct sha256_double *h); + +#endif /* LIGHTNING_SIGNATURE_H */