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 <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2015-06-10 20:32:43 +09:30
parent 9caf2c71e8
commit ed3f0115d6
18 changed files with 457 additions and 213 deletions

View File

@ -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

View File

@ -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))

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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))

View File

@ -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,

17
pkt.c
View File

@ -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)
{

16
pkt.h
View File

@ -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.

View File

@ -8,6 +8,62 @@
#include <assert.h>
#include <ccan/cast/cast.h>
#undef DEBUG
#ifdef DEBUG
#include <ccan/err/err.h>
#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,

View File

@ -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,

View File

@ -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");

View File

@ -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,
"<seed> <anchor-tx> <open-channel-file1> <open-channel-file2> <update-accept> [previous-updates]\n"
"<seed> <anchor-tx> <open-channel-file1> <open-channel-file2> <update-protobuf> <update-signature-protobuf> [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))

133
update-channel-signature.c Normal file
View File

@ -0,0 +1,133 @@
#include <ccan/crypto/shachain/shachain.h>
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>
#include <ccan/opt/opt.h>
#include <ccan/str/hex/hex.h>
#include <ccan/err/err.h>
#include <ccan/read_write_all/read_write_all.h>
#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 <openssl/ec.h>
#include <unistd.h>
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,
"<seed> <anchor-tx> <open-channel-file1> <open-channel-file2> <commit-privkey> <update-protobuf> <update-accept-protobuf> [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;
}

View File

@ -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,
"<seed> <anchor-tx> <open-channel-file1> <open-channel-file2> <commit-privkey> [previous-updates]\n"
"<seed> [previous-updates]\n"
"Create a new update message",
"Print this message.");
opt_register_arg("--to-them=<satoshi>",
@ -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");