From ed3f0115d6a60c05463f97c7e4ca5116e63ff652 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 10 Jun 2015 20:32:43 +0930 Subject: [PATCH] protocol: fix horribly thinko, keep own secrets. I had each side using the other side's hash secret. That's a very dumb idea, since it means you can steal from a unilateral close! A's secret applies to A's commit transaction: it needs the secret and B's final signature to steal funds, and that should never happen (since A doesn't have the B's final signature, and once A has given B the secret, they never broadcast the commit tx). This makes the update a 4 step dance, since you need the new revocation hash to make the other side's TX to sign. Signed-off-by: Rusty Russell --- Makefile | 2 +- check-commit-sig.c | 4 +- close-channel.c | 2 +- create-commit-spend-tx.c | 2 +- create-steal-tx.c | 2 +- lightning.pb-c.c | 200 +++++++++++++++++++++++++------------ lightning.pb-c.h | 66 +++++++++--- lightning.proto | 19 ++-- open-anchor-scriptsigs.c | 2 +- open-commit-sig.c | 4 +- pkt.c | 17 +++- pkt.h | 16 ++- signature.c | 68 ++++++++++++- signature.h | 3 +- update-channel-accept.c | 29 +----- update-channel-complete.c | 33 +++--- update-channel-signature.c | 133 ++++++++++++++++++++++++ update-channel.c | 68 ++----------- 18 files changed, 457 insertions(+), 213 deletions(-) create mode 100644 update-channel-signature.c diff --git a/Makefile b/Makefile index 3369854c0..7dd9690d1 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # Needs to have oneof support: Ubuntu vivid's is too old :( PROTOCC:=protoc-c -PROGRAMS := open-channel open-anchor-scriptsigs leak-anchor-sigs open-commit-sig check-commit-sig check-anchor-scriptsigs get-anchor-depth create-steal-tx create-commit-spend-tx close-channel create-close-tx update-channel update-channel-accept update-channel-complete +PROGRAMS := open-channel open-anchor-scriptsigs leak-anchor-sigs open-commit-sig check-commit-sig check-anchor-scriptsigs get-anchor-depth create-steal-tx create-commit-spend-tx close-channel create-close-tx update-channel update-channel-accept update-channel-signature update-channel-complete HELPER_OBJS := base58.o lightning.pb-c.o shadouble.o pkt.o bitcoin_script.o permute_tx.o signature.o bitcoin_tx.o bitcoin_address.o anchor.o commit_tx.o pubkey.o opt_bits.o close_tx.o find_p2sh_out.o diff --git a/check-commit-sig.c b/check-commit-sig.c index bba360ce6..2bf9bae13 100644 --- a/check-commit-sig.c +++ b/check-commit-sig.c @@ -70,7 +70,7 @@ int main(int argc, char *argv[]) anchor_txid(anchor, argv[5], argv[6], inmap, &txid); /* Now create our commitment tx. */ - proto_to_sha256(o2->revocation_hash, &rhash); + proto_to_sha256(o1->revocation_hash, &rhash); commit = create_commit_tx(ctx, o1, o2, &rhash, 0, &txid, outmap[0]); /* If contributions don't exceed fees, this fails. */ @@ -87,7 +87,7 @@ int main(int argc, char *argv[]) sig1.stype = SIGHASH_ALL; subscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2); sign_tx_input(ctx, commit, 0, subscript, tal_count(subscript), - privkey, &sig1.sig); + privkey, &pubkey1, &sig1.sig); /* Signatures well-formed? */ if (!proto_to_signature(cs2->sig, &sig2.sig)) diff --git a/close-channel.c b/close-channel.c index fb82ef25d..8f69d1701 100644 --- a/close-channel.c +++ b/close-channel.c @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) /* Sign it for them. */ sign_tx_input(ctx, close_tx, 0, redeemscript, tal_count(redeemscript), - privkey, &sig); + privkey, &pubkey1, &sig); if (complete) pkt = close_channel_complete_pkt(ctx, &sig); diff --git a/create-commit-spend-tx.c b/create-commit-spend-tx.c index 3fb1098db..c9c643104 100644 --- a/create-commit-spend-tx.c +++ b/create-commit-spend-tx.c @@ -105,7 +105,7 @@ int main(int argc, char *argv[]) /* Now get signature, to set up input script. */ if (!sign_tx_input(tx, tx, 0, redeemscript, tal_count(redeemscript), - privkey, &sig.sig)) + privkey, &pubkey1, &sig.sig)) errx(1, "Could not sign tx"); sig.stype = SIGHASH_ALL; tx->input[0].script = scriptsig_p2sh_single_sig(tx, redeemscript, diff --git a/create-steal-tx.c b/create-steal-tx.c index 36f25c514..a0164e85e 100644 --- a/create-steal-tx.c +++ b/create-steal-tx.c @@ -94,7 +94,7 @@ int main(int argc, char *argv[]) /* Now get signature, to set up input script. */ if (!sign_tx_input(tx, tx, 0, redeemscript, tal_count(redeemscript), - privkey, &sig.sig)) + privkey, &pubkey1, &sig.sig)) errx(1, "Could not sign tx"); sig.stype = SIGHASH_ALL; tx->input[0].script = scriptsig_p2sh_revoke(tx, &revoke, &sig, diff --git a/lightning.pb-c.c b/lightning.pb-c.c index 3476e4694..1970eed12 100644 --- a/lightning.pb-c.c +++ b/lightning.pb-c.c @@ -566,6 +566,49 @@ void update_accept__free_unpacked assert(message->base.descriptor == &update_accept__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } +void update_signature__init + (UpdateSignature *message) +{ + static UpdateSignature init_value = UPDATE_SIGNATURE__INIT; + *message = init_value; +} +size_t update_signature__get_packed_size + (const UpdateSignature *message) +{ + assert(message->base.descriptor == &update_signature__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t update_signature__pack + (const UpdateSignature *message, + uint8_t *out) +{ + assert(message->base.descriptor == &update_signature__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t update_signature__pack_to_buffer + (const UpdateSignature *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &update_signature__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +UpdateSignature * + update_signature__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (UpdateSignature *) + protobuf_c_message_unpack (&update_signature__descriptor, + allocator, len, data); +} +void update_signature__free_unpacked + (UpdateSignature *message, + ProtobufCAllocator *allocator) +{ + assert(message->base.descriptor == &update_signature__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} void update_complete__init (UpdateComplete *message) { @@ -1743,7 +1786,7 @@ const ProtobufCMessageDescriptor open_complete__descriptor = (ProtobufCMessageInit) open_complete__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor update__field_descriptors[4] = +static const ProtobufCFieldDescriptor update__field_descriptors[2] = { { "revocation_hash", @@ -1769,41 +1812,15 @@ static const ProtobufCFieldDescriptor update__field_descriptors[4] = 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, - { - "sig", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_MESSAGE, - 0, /* quantifier_offset */ - offsetof(Update, sig), - &signature__descriptor, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "old_anchor_sig", - 4, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_MESSAGE, - 0, /* quantifier_offset */ - offsetof(Update, old_anchor_sig), - &signature__descriptor, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, }; static const unsigned update__field_indices_by_name[] = { 1, /* field[1] = delta */ - 3, /* field[3] = old_anchor_sig */ 0, /* field[0] = revocation_hash */ - 2, /* field[2] = sig */ }; static const ProtobufCIntRange update__number_ranges[1 + 1] = { { 1, 0 }, - { 0, 4 } + { 0, 2 } }; const ProtobufCMessageDescriptor update__descriptor = { @@ -1813,14 +1830,14 @@ const ProtobufCMessageDescriptor update__descriptor = "Update", "", sizeof(Update), - 4, + 2, update__field_descriptors, update__field_indices_by_name, 1, update__number_ranges, (ProtobufCMessageInit) update__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor update_accept__field_descriptors[4] = +static const ProtobufCFieldDescriptor update_accept__field_descriptors[3] = { { "sig", @@ -1858,29 +1875,16 @@ static const ProtobufCFieldDescriptor update_accept__field_descriptors[4] = 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, - { - "revocation_preimage", - 4, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_MESSAGE, - 0, /* quantifier_offset */ - offsetof(UpdateAccept, revocation_preimage), - &sha256_hash__descriptor, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, }; static const unsigned update_accept__field_indices_by_name[] = { 1, /* field[1] = old_anchor_sig */ 2, /* field[2] = revocation_hash */ - 3, /* field[3] = revocation_preimage */ 0, /* field[0] = sig */ }; static const ProtobufCIntRange update_accept__number_ranges[1 + 1] = { { 1, 0 }, - { 0, 4 } + { 0, 3 } }; const ProtobufCMessageDescriptor update_accept__descriptor = { @@ -1890,13 +1894,64 @@ const ProtobufCMessageDescriptor update_accept__descriptor = "UpdateAccept", "", sizeof(UpdateAccept), - 4, + 3, update_accept__field_descriptors, update_accept__field_indices_by_name, 1, update_accept__number_ranges, (ProtobufCMessageInit) update_accept__init, NULL,NULL,NULL /* reserved[123] */ }; +static const ProtobufCFieldDescriptor update_signature__field_descriptors[2] = +{ + { + "sig", + 1, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_MESSAGE, + 0, /* quantifier_offset */ + offsetof(UpdateSignature, sig), + &signature__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "revocation_preimage", + 2, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_MESSAGE, + 0, /* quantifier_offset */ + offsetof(UpdateSignature, revocation_preimage), + &sha256_hash__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned update_signature__field_indices_by_name[] = { + 1, /* field[1] = revocation_preimage */ + 0, /* field[0] = sig */ +}; +static const ProtobufCIntRange update_signature__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor update_signature__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "update_signature", + "UpdateSignature", + "UpdateSignature", + "", + sizeof(UpdateSignature), + 2, + update_signature__field_descriptors, + update_signature__field_indices_by_name, + 1, update_signature__number_ranges, + (ProtobufCMessageInit) update_signature__init, + NULL,NULL,NULL /* reserved[123] */ +}; static const ProtobufCFieldDescriptor update_complete__field_descriptors[1] = { { @@ -2239,7 +2294,7 @@ const ProtobufCMessageDescriptor error__descriptor = (ProtobufCMessageInit) error__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor pkt__field_descriptors[15] = +static const ProtobufCFieldDescriptor pkt__field_descriptors[16] = { { "update", @@ -2266,11 +2321,23 @@ static const ProtobufCFieldDescriptor pkt__field_descriptors[15] = 0,NULL,NULL /* reserved1,reserved2, etc */ }, { - "update_complete", + "update_signature", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, offsetof(Pkt, pkt_case), + offsetof(Pkt, update_signature), + &update_signature__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "update_complete", + 4, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(Pkt, pkt_case), offsetof(Pkt, update_complete), &update_complete__descriptor, NULL, @@ -2423,30 +2490,31 @@ static const ProtobufCFieldDescriptor pkt__field_descriptors[15] = }, }; static const unsigned pkt__field_indices_by_name[] = { - 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_scriptsigs */ - 4, /* field[4] = open_commit_sig */ - 6, /* field[6] = open_complete */ + 13, /* field[13] = close */ + 14, /* field[14] = close_complete */ + 15, /* field[15] = error */ + 9, /* field[9] = new_anchor */ + 11, /* field[11] = new_anchor_accept */ + 10, /* field[10] = new_anchor_ack */ + 12, /* field[12] = new_anchor_complete */ + 8, /* field[8] = omg_fail */ + 4, /* field[4] = open */ + 6, /* field[6] = open_anchor_scriptsigs */ + 5, /* field[5] = open_commit_sig */ + 7, /* field[7] = open_complete */ 0, /* field[0] = update */ 1, /* field[1] = update_accept */ - 2, /* field[2] = update_complete */ + 3, /* field[3] = update_complete */ + 2, /* field[2] = update_signature */ }; static const ProtobufCIntRange pkt__number_ranges[5 + 1] = { { 1, 0 }, - { 201, 3 }, - { 301, 8 }, - { 401, 12 }, - { 1000, 14 }, - { 0, 15 } + { 201, 4 }, + { 301, 9 }, + { 401, 13 }, + { 1000, 15 }, + { 0, 16 } }; const ProtobufCMessageDescriptor pkt__descriptor = { @@ -2456,7 +2524,7 @@ const ProtobufCMessageDescriptor pkt__descriptor = "Pkt", "", sizeof(Pkt), - 15, + 16, 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 ff978e5fe..95154e7ea 100644 --- a/lightning.pb-c.h +++ b/lightning.pb-c.h @@ -28,6 +28,7 @@ typedef struct _LeakAnchorSigsAndPretendWeDidnt LeakAnchorSigsAndPretendWeDidnt; typedef struct _OpenComplete OpenComplete; typedef struct _Update Update; typedef struct _UpdateAccept UpdateAccept; +typedef struct _UpdateSignature UpdateSignature; typedef struct _UpdateComplete UpdateComplete; typedef struct _NewAnchor NewAnchor; typedef struct _NewAnchorAck NewAnchorAck; @@ -291,32 +292,24 @@ struct _Update /* * Change in current payment to-me (implies reverse to-you). */ - int64_t delta; - /* - * Signature for new commitment tx. - */ - Signature *sig; - /* - * Signature for old anchor (if any) - */ /* * FIXME: optional HTLC ops. */ - Signature *old_anchor_sig; + int64_t delta; }; #define UPDATE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&update__descriptor) \ - , NULL, 0, NULL, NULL } + , NULL, 0 } /* - * OK, I accept that update. + * OK, I accept that update; here's your signature. */ struct _UpdateAccept { ProtobufCMessage base; /* - * Signature for new commitment tx. + * Signature for your new commitment tx. */ Signature *sig; /* @@ -327,14 +320,30 @@ struct _UpdateAccept * Hash for which I will supply preimage to revoke this new commit tx. */ Sha256Hash *revocation_hash; +}; +#define UPDATE_ACCEPT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&update_accept__descriptor) \ + , NULL, NULL, NULL } + + +/* + * Thanks for accepting, here's my last bit. + */ +struct _UpdateSignature +{ + ProtobufCMessage base; + /* + * Signature for your new commitment tx. + */ + Signature *sig; /* * Hash preimage which revokes old commitment tx. */ Sha256Hash *revocation_preimage; }; -#define UPDATE_ACCEPT__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&update_accept__descriptor) \ - , NULL, NULL, NULL, NULL } +#define UPDATE_SIGNATURE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&update_signature__descriptor) \ + , NULL, NULL } /* @@ -479,7 +488,8 @@ typedef enum { PKT__PKT_OPEN_COMPLETE = 204, PKT__PKT_UPDATE = 1, PKT__PKT_UPDATE_ACCEPT = 2, - PKT__PKT_UPDATE_COMPLETE = 3, + PKT__PKT_UPDATE_SIGNATURE = 3, + PKT__PKT_UPDATE_COMPLETE = 4, PKT__PKT_NEW_ANCHOR = 301, PKT__PKT_NEW_ANCHOR_ACK = 302, PKT__PKT_NEW_ANCHOR_ACCEPT = 303, @@ -510,6 +520,7 @@ struct _Pkt */ Update *update; UpdateAccept *update_accept; + UpdateSignature *update_signature; UpdateComplete *update_complete; /* * Topping up @@ -781,6 +792,25 @@ UpdateAccept * void update_accept__free_unpacked (UpdateAccept *message, ProtobufCAllocator *allocator); +/* UpdateSignature methods */ +void update_signature__init + (UpdateSignature *message); +size_t update_signature__get_packed_size + (const UpdateSignature *message); +size_t update_signature__pack + (const UpdateSignature *message, + uint8_t *out); +size_t update_signature__pack_to_buffer + (const UpdateSignature *message, + ProtobufCBuffer *buffer); +UpdateSignature * + update_signature__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void update_signature__free_unpacked + (UpdateSignature *message, + ProtobufCAllocator *allocator); /* UpdateComplete methods */ void update_complete__init (UpdateComplete *message); @@ -1012,6 +1042,9 @@ typedef void (*Update_Closure) typedef void (*UpdateAccept_Closure) (const UpdateAccept *message, void *closure_data); +typedef void (*UpdateSignature_Closure) + (const UpdateSignature *message, + void *closure_data); typedef void (*UpdateComplete_Closure) (const UpdateComplete *message, void *closure_data); @@ -1061,6 +1094,7 @@ extern const ProtobufCMessageDescriptor leak_anchor_sigs_and_pretend_we_didnt__d extern const ProtobufCMessageDescriptor open_complete__descriptor; extern const ProtobufCMessageDescriptor update__descriptor; extern const ProtobufCMessageDescriptor update_accept__descriptor; +extern const ProtobufCMessageDescriptor update_signature__descriptor; extern const ProtobufCMessageDescriptor update_complete__descriptor; extern const ProtobufCMessageDescriptor new_anchor__descriptor; extern const ProtobufCMessageDescriptor new_anchor_ack__descriptor; diff --git a/lightning.proto b/lightning.proto index a9cd7e36a..a2fb9f51c 100644 --- a/lightning.proto +++ b/lightning.proto @@ -121,23 +121,25 @@ message update { required sha256_hash revocation_hash = 1; // Change in current payment to-me (implies reverse to-you). required sint64 delta = 2; - // Signature for new commitment tx. - required signature sig = 3; - // Signature for old anchor (if any) - optional signature old_anchor_sig = 4; // FIXME: optional HTLC ops. } -// OK, I accept that update. +// OK, I accept that update; here's your signature. message update_accept { - // Signature for new commitment tx. + // Signature for your new commitment tx. required signature sig = 1; // Signature for old anchor (if any) optional signature old_anchor_sig = 2; // Hash for which I will supply preimage to revoke this new commit tx. required sha256_hash revocation_hash = 3; +} + +// Thanks for accepting, here's my last bit. +message update_signature { + // Signature for your new commitment tx. + required signature sig = 1; // Hash preimage which revokes old commitment tx. - required sha256_hash revocation_preimage = 4; + required sha256_hash revocation_preimage = 2; } // Complete the update. @@ -204,7 +206,8 @@ message pkt { // Updating (most common) update update = 1; update_accept update_accept = 2; - update_complete update_complete = 3; + update_signature update_signature = 3; + update_complete update_complete = 4; // Topping up new_anchor new_anchor = 301; new_anchor_ack new_anchor_ack = 302; diff --git a/open-anchor-scriptsigs.c b/open-anchor-scriptsigs.c index ab245a8ce..1e72c489a 100644 --- a/open-anchor-scriptsigs.c +++ b/open-anchor-scriptsigs.c @@ -31,7 +31,7 @@ static u8 *tx_scriptsig(const tal_t *ctx, sig.stype = SIGHASH_ALL; if (!sign_tx_input(ctx, tx, i, input->subscript.data, input->subscript.len, - privkey, &sig.sig)) + privkey, pubkey, &sig.sig)) return NULL; if (!is_pay_to_pubkey_hash(input->subscript.data, input->subscript.len)) diff --git a/open-commit-sig.c b/open-commit-sig.c index f4b512553..623cfff89 100644 --- a/open-commit-sig.c +++ b/open-commit-sig.c @@ -66,7 +66,7 @@ int main(int argc, char *argv[]) anchor_txid(anchor, argv[4], argv[5], inmap, &txid); /* Now create THEIR commitment tx to spend 2/2 output of anchor. */ - proto_to_sha256(o1->revocation_hash, &rhash); + proto_to_sha256(o2->revocation_hash, &rhash); commit = create_commit_tx(ctx, o2, o1, &rhash, 0, &txid, outmap[0]); /* If contributions don't exceed fees, this fails. */ @@ -84,7 +84,7 @@ int main(int argc, char *argv[]) /* Sign it for them. */ subscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2); sign_tx_input(ctx, commit, 0, subscript, tal_count(subscript), - privkey, &sig); + privkey, &pubkey1, &sig); pkt = open_commit_sig_pkt(ctx, &sig); if (!write_all(STDOUT_FILENO, pkt, diff --git a/pkt.c b/pkt.c index c0a2b2fcb..96a5fb6f0 100644 --- a/pkt.c +++ b/pkt.c @@ -161,27 +161,34 @@ struct pkt *close_channel_complete_pkt(const tal_t *ctx, struct pkt *update_pkt(const tal_t *ctx, const struct sha256 *revocation_hash, - s64 delta, struct signature *sig) + s64 delta) { Update u = UPDATE__INIT; u.revocation_hash = sha256_to_proto(ctx, revocation_hash); u.delta = delta; - u.sig = signature_to_proto(ctx, sig); return to_pkt(ctx, PKT__PKT_UPDATE, &u); } struct pkt *update_accept_pkt(const tal_t *ctx, struct signature *sig, - const struct sha256 *revocation_hash, - const struct sha256 *revocation_preimage) + const struct sha256 *revocation_hash) { UpdateAccept ua = UPDATE_ACCEPT__INIT; ua.sig = signature_to_proto(ctx, sig); ua.revocation_hash = sha256_to_proto(ctx, revocation_hash); - ua.revocation_preimage = sha256_to_proto(ctx, revocation_preimage); return to_pkt(ctx, PKT__PKT_UPDATE_ACCEPT, &ua); } +struct pkt *update_signature_pkt(const tal_t *ctx, + const struct signature *sig, + const struct sha256 *revocation_preimage) +{ + UpdateSignature us = UPDATE_SIGNATURE__INIT; + us.sig = signature_to_proto(ctx, sig); + us.revocation_preimage = sha256_to_proto(ctx, revocation_preimage); + return to_pkt(ctx, PKT__PKT_UPDATE_SIGNATURE, &us); +} + struct pkt *update_complete_pkt(const tal_t *ctx, const struct sha256 *revocation_preimage) { diff --git a/pkt.h b/pkt.h index 3e6e5d1fa..6f5607d31 100644 --- a/pkt.h +++ b/pkt.h @@ -87,24 +87,30 @@ struct pkt *close_channel_complete_pkt(const tal_t *ctx, * @ctx: tal context to allocate off. * @revocation_hash: the revocation hash for the next tx. * @delta: the change in satoshis (to me). - * @sig: the signature for the close transaction input. */ struct pkt *update_pkt(const tal_t *ctx, const struct sha256 *revocation_hash, - s64 delta, struct signature *sig); + s64 delta); /** * update_accept_pkt - create an update_accept message * @ctx: tal context to allocate off. * @sig: the signature for the close transaction input. * @revocation_hash: hash to revoke the next tx. - * @revocation_preimage: preimage to revoke existing (now-obsolete) tx. */ struct pkt *update_accept_pkt(const tal_t *ctx, struct signature *sig, - const struct sha256 *revocation_hash, - const struct sha256 *revocation_preimage); + const struct sha256 *revocation_hash); +/** + * update_signature_pkt - create an update_signature message + * @ctx: tal context to allocate off. + * @sig: the signature for the close transaction input. + * @revocation_preimage: preimage to revoke existing (now-obsolete) tx. + */ +struct pkt *update_signature_pkt(const tal_t *ctx, + const struct signature *sig, + const struct sha256 *revocation_preimage); /** * update_complete_pkt - create an update_accept message * @ctx: tal context to allocate off. diff --git a/signature.c b/signature.c index 9c7a0541d..f98bd2436 100644 --- a/signature.c +++ b/signature.c @@ -8,6 +8,62 @@ #include #include +#undef DEBUG +#ifdef DEBUG +#include +#define SHA_FMT \ + "%02x%02x%02x%02x%02x%02x%02x%02x" \ + "%02x%02x%02x%02x%02x%02x%02x%02x" \ + "%02x%02x%02x%02x%02x%02x%02x%02x" \ + "%02x%02x%02x%02x%02x%02x%02x%02x" + +#define SHA_VALS(e) \ + e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], \ + e[8], e[9], e[10], e[11], e[12], e[13], e[14], e[15], \ + e[16], e[17], e[18], e[19], e[20], e[21], e[22], e[23], \ + e[24], e[25], e[25], e[26], e[28], e[29], e[30], e[31] + +static void dump_tx(const char *msg, + const struct bitcoin_tx *tx, size_t inputnum, + const u8 *script, size_t script_len, + const struct pubkey *key) +{ + size_t i, j; + warnx("%s tx version %u locktime %#x:", + msg, tx->version, tx->lock_time); + for (i = 0; i < tx->input_count; i++) { + warnx("input[%zu].txid = "SHA_FMT, i, + SHA_VALS(tx->input[i].txid.sha.u.u8)); + warnx("input[%zu].index = %u", i, tx->input[i].index); + } + for (i = 0; i < tx->output_count; i++) { + warnx("output[%zu].amount = %llu", + i, (long long)tx->output[i].amount); + warnx("output[%zu].script = %llu", + i, (long long)tx->output[i].script_length); + for (j = 0; j < tx->output[i].script_length; j++) + fprintf(stderr, "%02x", tx->output[i].script[j]); + fprintf(stderr, "\n"); + } + warnx("input[%zu].script = %zu", inputnum, script_len); + for (i = 0; i < script_len; i++) + fprintf(stderr, "%02x", script[i]); + if (key) { + fprintf(stderr, "\nPubkey: "); + for (i = 0; i < pubkey_len(key); i++) + fprintf(stderr, "%02x", key->key[i]); + fprintf(stderr, "\n"); + } +} +#else +static void dump_tx(const char *msg, + const struct bitcoin_tx *tx, size_t inputnum, + const u8 *script, size_t script_len, + const struct pubkey *key) +{ +} +#endif + bool sign_hash(const tal_t *ctx, EC_KEY *private_key, const struct sha256_double *h, struct signature *s) @@ -82,11 +138,13 @@ static void sha256_tx_one_input(struct bitcoin_tx *tx, bool sign_tx_input(const tal_t *ctx, struct bitcoin_tx *tx, unsigned int in, const u8 *subscript, size_t subscript_len, - EC_KEY *privkey, struct signature *sig) + EC_KEY *privkey, const struct pubkey *key, + struct signature *sig) { struct sha256_double hash; sha256_tx_one_input(tx, in, subscript, subscript_len, &hash); + dump_tx("Signing", tx, in, subscript, subscript_len, key); return sign_hash(ctx, privkey, &hash, sig); } @@ -142,6 +200,8 @@ bool check_tx_sig(struct bitcoin_tx *tx, size_t input_num, const struct bitcoin_signature *sig) { struct sha256_double hash; + bool ret; + assert(input_num < tx->input_count); sha256_tx_one_input(tx, input_num, redeemscript, redeemscript_len, @@ -151,7 +211,11 @@ bool check_tx_sig(struct bitcoin_tx *tx, size_t input_num, if (sig->stype != SIGHASH_ALL) return false; - return check_signed_hash(&hash, &sig->sig, key); + ret = check_signed_hash(&hash, &sig->sig, key); + if (!ret) + dump_tx("Sig failed", tx, input_num, + redeemscript, redeemscript_len, key); + return ret; } bool check_2of2_sig(struct bitcoin_tx *tx, size_t input_num, diff --git a/signature.h b/signature.h index d3b0c5af1..4e0e8184e 100644 --- a/signature.h +++ b/signature.h @@ -32,7 +32,8 @@ bool sign_hash(const tal_t *ctx, EC_KEY *private_key, bool sign_tx_input(const tal_t *ctx, struct bitcoin_tx *tx, unsigned int in, const u8 *subscript, size_t subscript_len, - EC_KEY *privkey, struct signature *sig); + EC_KEY *privkey, const struct pubkey *pubkey, + struct signature *sig); /* Does this sig sign the tx with this input for this pubkey. */ bool check_tx_sig(struct bitcoin_tx *tx, size_t input_num, diff --git a/update-channel-accept.c b/update-channel-accept.c index 415bbf284..366d94ce2 100644 --- a/update-channel-accept.c +++ b/update-channel-accept.c @@ -24,7 +24,7 @@ int main(int argc, char *argv[]) { const tal_t *ctx = tal_arr(NULL, char, 0); - struct sha256 seed, revocation_hash, revocation_preimage, their_rhash; + struct sha256 seed, revocation_hash, their_rhash; OpenChannel *o1, *o2; Update *update; struct bitcoin_tx *anchor, *commit; @@ -66,10 +66,6 @@ int main(int argc, char *argv[]) update = pkt_from_file(argv[6], PKT__PKT_UPDATE)->update; - sig.stype = SIGHASH_ALL; - if (!proto_to_signature(update->sig, &sig.sig)) - errx(1, "Invalid update signature"); - /* Figure out cumulative delta since anchor. */ delta = update->delta; for (i = 7; i < argc; i++) { @@ -95,20 +91,9 @@ int main(int argc, char *argv[]) redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2); p2sh_out = find_p2sh_out(anchor, redeemscript); - /* Check our new commit is signed correctly by them. */ - proto_to_sha256(update->revocation_hash, &their_rhash); - commit = create_commit_tx(ctx, o1, o2, &their_rhash, delta, - &anchor_txid, p2sh_out); - if (!commit) - errx(1, "Delta too large"); - - /* Check their signature signs this input correctly. */ - if (!check_tx_sig(commit, 0, redeemscript, tal_count(redeemscript), - &pubkey2, &sig)) - errx(1, "Invalid signature."); - /* Now create THEIR new commitment tx to spend 2/2 output of anchor. */ - commit = create_commit_tx(ctx, o2, o1, &revocation_hash, delta, + proto_to_sha256(update->revocation_hash, &their_rhash); + commit = create_commit_tx(ctx, o2, o1, &their_rhash, delta, &anchor_txid, p2sh_out); /* If contributions don't exceed fees, this fails. */ @@ -117,13 +102,9 @@ int main(int argc, char *argv[]) /* Sign it for them. */ sign_tx_input(ctx, commit, 0, redeemscript, tal_count(redeemscript), - privkey, &sig.sig); + privkey, &pubkey1, &sig.sig); - /* Give up revocation preimage for old tx. */ - shachain_from_seed(&seed, argc - 6 - 1, &revocation_preimage); - - pkt = update_accept_pkt(ctx, &sig.sig, - &revocation_hash, &revocation_preimage); + pkt = update_accept_pkt(ctx, &sig.sig, &revocation_hash); if (!write_all(STDOUT_FILENO, pkt, sizeof(pkt->len) + le32_to_cpu(pkt->len))) err(1, "Writing out packet"); diff --git a/update-channel-complete.c b/update-channel-complete.c index 2a994ae51..a1663cfe8 100644 --- a/update-channel-complete.c +++ b/update-channel-complete.c @@ -25,9 +25,10 @@ int main(int argc, char *argv[]) { const tal_t *ctx = tal_arr(NULL, char, 0); - struct sha256 seed, revocation_hash, their_rhash, preimage; + struct sha256 seed, revocation_hash, our_rhash, their_rhash, preimage; OpenChannel *o1, *o2; - UpdateAccept *ua; + UpdateSignature *us; + Update *update; struct pkt *pkt; struct bitcoin_tx *anchor, *commit; struct pubkey pubkey1, pubkey2; @@ -40,14 +41,14 @@ int main(int argc, char *argv[]) err_set_progname(argv[0]); opt_register_noarg("--help|-h", opt_usage_and_exit, - " [previous-updates]\n" + " [previous-updates]\n" "Create a new update-complete message", "Print this message."); opt_parse(&argc, argv, opt_log_stderr_exit); - if (argc < 6) - opt_usage_exit_fail("Expected 5+ arguments"); + if (argc < 7) + opt_usage_exit_fail("Expected 6+ arguments"); if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed))) errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]); @@ -56,15 +57,15 @@ int main(int argc, char *argv[]) bitcoin_txid(anchor, &anchor_txid); o1 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open; o2 = pkt_from_file(argv[4], PKT__PKT_OPEN)->open; - ua = pkt_from_file(argv[5], PKT__PKT_UPDATE_ACCEPT)->update_accept; - proto_to_sha256(ua->revocation_preimage, &preimage); + update = pkt_from_file(argv[5], PKT__PKT_UPDATE)->update; + us = pkt_from_file(argv[6], PKT__PKT_UPDATE_SIGNATURE)->update_signature; /* We need last revocation hash (either in update or update-accept), * and the delta */ proto_to_sha256(o2->revocation_hash, &revocation_hash); num_updates = 0; - delta = 0; - for (i = 6; i < argc; i++) { + delta = update->delta; + for (i = 7; i < argc; i++) { Pkt *p = any_pkt_from_file(argv[i]); switch (p->pkt_case) { case PKT__PKT_UPDATE: @@ -84,7 +85,8 @@ int main(int argc, char *argv[]) } } - /* They gave us right preimage? */ + /* They gave us right preimage to match rhash of previous commit tx? */ + proto_to_sha256(us->revocation_preimage, &preimage); sha256(&their_rhash, preimage.u.u8, sizeof(preimage.u.u8)); if (!structeq(&their_rhash, &revocation_hash)) errx(1, "Their preimage was incorrect"); @@ -100,15 +102,16 @@ int main(int argc, char *argv[]) p2sh_out = find_p2sh_out(anchor, redeemscript); /* Check their signature signs our new commit tx correctly. */ - proto_to_sha256(ua->revocation_hash, &their_rhash); - commit = create_commit_tx(ctx, o1, o2, &their_rhash, delta, - &anchor_txid, p2sh_out); + shachain_from_seed(&seed, num_updates + 1, &preimage); + sha256(&our_rhash, &preimage, sizeof(preimage)); + commit = create_commit_tx(ctx, o1, o2, &our_rhash, delta, + &anchor_txid, p2sh_out); if (!commit) errx(1, "Delta too large"); sig.stype = SIGHASH_ALL; - if (!proto_to_signature(ua->sig, &sig.sig)) - errx(1, "Invalid update signature"); + if (!proto_to_signature(us->sig, &sig.sig)) + errx(1, "Invalid update-signature signature"); if (!check_tx_sig(commit, 0, redeemscript, tal_count(redeemscript), &pubkey2, &sig)) diff --git a/update-channel-signature.c b/update-channel-signature.c new file mode 100644 index 000000000..cd38100a1 --- /dev/null +++ b/update-channel-signature.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include +#include +#include "lightning.pb-c.h" +#include "anchor.h" +#include "base58.h" +#include "pkt.h" +#include "bitcoin_script.h" +#include "permute_tx.h" +#include "signature.h" +#include "commit_tx.h" +#include "pubkey.h" +#include "find_p2sh_out.h" +#include +#include + +int main(int argc, char *argv[]) +{ + const tal_t *ctx = tal_arr(NULL, char, 0); + struct sha256 seed, revocation_hash, preimage; + OpenChannel *o1, *o2; + UpdateAccept *ua; + Update *update; + struct bitcoin_tx *anchor, *commit; + struct sha256_double anchor_txid; + struct pkt *pkt; + struct bitcoin_signature sig; + EC_KEY *privkey; + bool testnet; + struct pubkey pubkey1, pubkey2; + u8 *redeemscript; + int64_t delta; + size_t i, p2sh_out; + + err_set_progname(argv[0]); + + opt_register_noarg("--help|-h", opt_usage_and_exit, + " [previous-updates]...\n" + "Create a new update-channel-signature message", + "Print this message."); + + opt_parse(&argc, argv, opt_log_stderr_exit); + + if (argc < 8) + opt_usage_exit_fail("Expected 7+ arguments"); + + if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed))) + errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]); + + anchor = bitcoin_tx_from_file(ctx, argv[2]); + bitcoin_txid(anchor, &anchor_txid); + o1 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open; + o2 = pkt_from_file(argv[4], PKT__PKT_OPEN)->open; + + privkey = key_from_base58(argv[5], strlen(argv[5]), &testnet, &pubkey1); + if (!privkey) + errx(1, "Invalid private key '%s'", argv[5]); + if (!testnet) + errx(1, "Private key '%s' not on testnet!", argv[5]); + + update = pkt_from_file(argv[6], PKT__PKT_UPDATE)->update; + ua = pkt_from_file(argv[7], PKT__PKT_UPDATE_ACCEPT)->update_accept; + + sig.stype = SIGHASH_ALL; + if (!proto_to_signature(ua->sig, &sig.sig)) + errx(1, "Invalid update signature"); + + /* Figure out cumulative delta since anchor. */ + delta = 0; + for (i = 8; i < argc; i++) { + Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update; + delta += u->delta; + } + + /* Give up revocation preimage for old tx. */ + shachain_from_seed(&seed, argc - 7 - 1, &preimage); + + /* Get pubkeys */ + if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey2)) + errx(1, "Invalid o1 commit pubkey"); + if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2) + || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0) + errx(1, "o1 pubkey != this privkey"); + if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2)) + errx(1, "Invalid o2 final pubkey"); + + /* This is what the anchor pays to; figure out whick output. */ + redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2); + p2sh_out = find_p2sh_out(anchor, redeemscript); + + /* Check our new commit is signed correctly by them. */ + proto_to_sha256(update->revocation_hash, &revocation_hash); + commit = create_commit_tx(ctx, o1, o2, &revocation_hash, delta, + &anchor_txid, p2sh_out); + if (!commit) + errx(1, "Delta too large"); + + /* Check their signature signs this input correctly. */ + if (!check_tx_sig(commit, 0, redeemscript, tal_count(redeemscript), + &pubkey2, &sig)) + errx(1, "Invalid signature."); + + /* Now create THEIR new commitment tx to spend 2/2 output of anchor. */ + proto_to_sha256(ua->revocation_hash, &revocation_hash); + commit = create_commit_tx(ctx, o2, o1, &revocation_hash, -delta, + &anchor_txid, + find_p2sh_out(anchor, redeemscript)); + + /* If contributions don't exceed fees, this fails. */ + if (!commit) + errx(1, "Delta too large"); + + /* Their pubkey must be valid */ + if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2)) + errx(1, "Invalid public open-channel-file2"); + + /* Sign it for them. */ + sign_tx_input(ctx, commit, 0, redeemscript, tal_count(redeemscript), + privkey, &pubkey1, &sig.sig); + + pkt = update_signature_pkt(ctx, &sig.sig, &preimage); + 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/update-channel.c b/update-channel.c index 454cf722b..a8347b80a 100644 --- a/update-channel.c +++ b/update-channel.c @@ -25,23 +25,14 @@ int main(int argc, char *argv[]) { const tal_t *ctx = tal_arr(NULL, char, 0); struct sha256 seed, revocation_hash; - OpenChannel *o1, *o2; - struct bitcoin_tx *anchor, *commit; - struct sha256_double anchor_txid; struct pkt *pkt; - struct signature sig; - EC_KEY *privkey; - bool testnet; - struct pubkey pubkey1, pubkey2; - u8 *redeemscript; unsigned long long to_them = 0, from_them = 0; - int64_t delta, this_delta; - size_t i; + int64_t this_delta; err_set_progname(argv[0]); opt_register_noarg("--help|-h", opt_usage_and_exit, - " [previous-updates]\n" + " [previous-updates]\n" "Create a new update message", "Print this message."); opt_register_arg("--to-them=", @@ -56,8 +47,8 @@ int main(int argc, char *argv[]) if (!from_them && !to_them) opt_usage_exit_fail("Must use --to-them or --from-them"); - if (argc < 5) - opt_usage_exit_fail("Expected 4+ arguments"); + if (argc < 2) + opt_usage_exit_fail("Expected 1+ arguments"); if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed))) errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]); @@ -66,59 +57,12 @@ int main(int argc, char *argv[]) if (!this_delta) errx(1, "Delta must not be zero"); - anchor = bitcoin_tx_from_file(ctx, argv[2]); - bitcoin_txid(anchor, &anchor_txid); - o1 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open; - o2 = pkt_from_file(argv[4], PKT__PKT_OPEN)->open; - - privkey = key_from_base58(argv[5], strlen(argv[5]), &testnet, &pubkey1); - if (!privkey) - errx(1, "Invalid private key '%s'", argv[5]); - if (!testnet) - errx(1, "Private key '%s' not on testnet!", argv[5]); - - /* Figure out cumulative delta since anchor. */ - delta = this_delta; - for (i = 6; i < argc; i++) { - Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update; - delta += u->delta; - } - /* Get next revocation hash. */ - shachain_from_seed(&seed, argc - 5, &revocation_hash); + shachain_from_seed(&seed, argc - 2 + 1, &revocation_hash); sha256(&revocation_hash, revocation_hash.u.u8, sizeof(revocation_hash.u.u8)); - /* Get pubkeys */ - if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey2)) - errx(1, "Invalid o1 commit pubkey"); - if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2) - || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0) - errx(1, "o1 pubkey != this privkey"); - if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2)) - errx(1, "Invalid o2 final pubkey"); - - /* This is what the anchor pays to; figure out whick output. */ - redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2); - - /* Now create THEIR new commitment tx to spend 2/2 output of anchor. */ - commit = create_commit_tx(ctx, o2, o1, &revocation_hash, delta, - &anchor_txid, - find_p2sh_out(anchor, redeemscript)); - - /* If contributions don't exceed fees, this fails. */ - if (!commit) - errx(1, "Delta too large"); - - /* Their pubkey must be valid */ - if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2)) - errx(1, "Invalid public open-channel-file2"); - - /* Sign it for them. */ - sign_tx_input(ctx, commit, 0, redeemscript, tal_count(redeemscript), - privkey, &sig); - - pkt = update_pkt(ctx, &revocation_hash, this_delta, &sig); + pkt = update_pkt(ctx, &revocation_hash, this_delta); if (!write_all(STDOUT_FILENO, pkt, sizeof(pkt->len) + le32_to_cpu(pkt->len))) err(1, "Writing out packet");