/* Save and check signature. */ static Pkt *check_and_save_commit_sig(struct peer *peer, struct commit_info *ci, const Signature *pb) { struct bitcoin_signature *sig = tal(ci, struct bitcoin_signature); assert(!ci->sig); sig->stype = SIGHASH_ALL; if (!proto_to_signature(peer->dstate->secpctx, pb, &sig->sig)) return pkt_err(peer, "Malformed signature"); log_debug(peer->log, "Checking sig for %u/%u msatoshis, %zu/%zu htlcs", ci->cstate->side[OURS].pay_msat, ci->cstate->side[THEIRS].pay_msat, tal_count(ci->cstate->side[OURS].htlcs), tal_count(ci->cstate->side[THEIRS].htlcs)); /* Their sig should sign our commit tx. */ if (!check_tx_sig(peer->dstate->secpctx, ci->tx, 0, NULL, 0, peer->anchor.witnessscript, &peer->remote.commitkey, sig)) return pkt_err(peer, "Bad signature"); ci->sig = sig; return NULL; }
/* Save and check signature. */ static Pkt *check_and_save_commit_sig(struct peer *peer, struct commit_info *ci, const Signature *pb) { assert(!ci->sig); ci->sig = tal(ci, struct bitcoin_signature); ci->sig->stype = SIGHASH_ALL; if (!proto_to_signature(pb, &ci->sig->sig)) return pkt_err(peer, "Malformed signature"); /* Their sig should sign our commit tx. */ if (!check_tx_sig(peer->dstate->secpctx, ci->tx, 0, NULL, 0, peer->anchor.witnessscript, &peer->them.commitkey, ci->sig)) return pkt_err(peer, "Bad signature"); return NULL; }
int main(int argc, char *argv[]) { const tal_t *ctx = tal_arr(NULL, char, 0); OpenChannel *o1, *o2; OpenAnchor *a; struct bitcoin_tx *close_tx; struct bitcoin_signature sig1, sig2; struct pubkey pubkey1, pubkey2; u8 *redeemscript; CloseChannel *close; CloseChannelComplete *closecomplete; uint64_t our_amount, their_amount; err_set_progname(argv[0]); /* FIXME: Take update.pbs to adjust channel */ opt_register_noarg("--help|-h", opt_usage_and_exit, "<open-channel-file1> <open-channel-file2> <open-anchor-file> <close-protobuf> <close-complete-protobuf> [update-protobuf]...\n" "Create the close transaction from the signatures", "Print this message."); opt_parse(&argc, argv, opt_log_stderr_exit); if (argc < 6) opt_usage_exit_fail("Expected 5+ arguments"); o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open; o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open; a = pkt_from_file(argv[3], PKT__PKT_OPEN_ANCHOR)->open_anchor; close = pkt_from_file(argv[4], PKT__PKT_CLOSE)->close; closecomplete = pkt_from_file(argv[5], PKT__PKT_CLOSE_COMPLETE)->close_complete; /* Pubkeys well-formed? */ if (!proto_to_pubkey(o1->commit_key, &pubkey1)) errx(1, "Invalid o1 commit_key"); if (!proto_to_pubkey(o2->commit_key, &pubkey2)) errx(1, "Invalid o2 commit_key"); /* Get delta by accumulting all the updates. */ gather_updates(o1, o2, a, close->close_fee, argv + 6, &our_amount, &their_amount, NULL, NULL, NULL); /* This is what the anchor pays to; figure out which output. */ redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2); /* Now create the close tx to spend 2/2 output of anchor. */ close_tx = create_close_tx(ctx, o1, o2, a, our_amount, their_amount); /* Signatures well-formed? */ sig1.stype = sig2.stype = SIGHASH_ALL; if (!proto_to_signature(close->sig, &sig1.sig)) errx(1, "Invalid close-packet"); if (!proto_to_signature(closecomplete->sig, &sig2.sig)) errx(1, "Invalid closecomplete-packet"); /* Combined signatures must validate correctly. */ if (!check_2of2_sig(close_tx, 0, redeemscript, tal_count(redeemscript), &pubkey1, &pubkey2, &sig1, &sig2)) errx(1, "Signature failed"); /* Create p2sh input for close_tx */ close_tx->input[0].script = scriptsig_p2sh_2of2(close_tx, &sig1, &sig2, &pubkey1, &pubkey2); close_tx->input[0].script_length = tal_count(close_tx->input[0].script); /* Print it out in hex. */ if (!bitcoin_tx_write(STDOUT_FILENO, close_tx)) err(1, "Writing out transaction"); tal_free(ctx); return 0; }
int main(int argc, char *argv[]) { const tal_t *ctx = tal_arr(NULL, char, 0); OpenChannel *o1, *o2; struct bitcoin_tx *anchor, *close_tx; struct sha256_double anchor_txid; struct bitcoin_signature sig1, sig2; struct pubkey pubkey1, pubkey2; u8 *redeemscript, *tx_arr; char *tx_hex; CloseChannel *close; CloseChannelComplete *closecomplete; size_t i; int64_t delta; err_set_progname(argv[0]); /* FIXME: Take update.pbs to adjust channel */ opt_register_noarg("--help|-h", opt_usage_and_exit, "<anchor-tx> <open-channel-file1> <open-channel-file2> <close-protobuf> <close-complete-protobuf> [update-protobuf]...\n" "Create the close transaction from the signatures", "Print this message."); opt_parse(&argc, argv, opt_log_stderr_exit); if (argc < 6) opt_usage_exit_fail("Expected 5+ arguments"); anchor = bitcoin_tx_from_file(ctx, argv[1]); o1 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open; o2 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open; close = pkt_from_file(argv[4], PKT__PKT_CLOSE)->close; closecomplete = pkt_from_file(argv[5], PKT__PKT_CLOSE_COMPLETE)->close_complete; bitcoin_txid(anchor, &anchor_txid); /* Pubkeys well-formed? */ if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey1)) errx(1, "Invalid anchor-1 key"); if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2)) errx(1, "Invalid anchor-2 key"); /* Get delta by accumulting all the updates. */ delta = 0; for (i = 6; i < argc; i++) { Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update; delta += u->delta; } /* This is what the anchor pays to; figure out which output. */ redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2); /* Now create the close tx to spend 2/2 output of anchor. */ close_tx = create_close_tx(ctx, o1, o2, delta, &anchor_txid, find_p2sh_out(anchor, redeemscript)); /* Signatures well-formed? */ sig1.stype = sig2.stype = SIGHASH_ALL; if (!proto_to_signature(close->sig, &sig1.sig)) errx(1, "Invalid close-packet"); if (!proto_to_signature(closecomplete->sig, &sig2.sig)) errx(1, "Invalid closecomplete-packet"); /* Combined signatures must validate correctly. */ if (!check_2of2_sig(close_tx, 0, redeemscript, tal_count(redeemscript), &pubkey1, &pubkey2, &sig1, &sig2)) errx(1, "Signature failed"); /* Create p2sh input for close_tx */ close_tx->input[0].script = scriptsig_p2sh_2of2(close_tx, &sig1, &sig2, &pubkey1, &pubkey2); close_tx->input[0].script_length = tal_count(close_tx->input[0].script); /* Print it out in hex. */ tx_arr = linearize_tx(ctx, close_tx); tx_hex = tal_arr(tx_arr, char, hex_str_size(tal_count(tx_arr))); hex_encode(tx_arr, tal_count(tx_arr), tx_hex, tal_count(tx_hex)); if (!write_all(STDOUT_FILENO, tx_hex, strlen(tx_hex))) err(1, "Writing out transaction"); tal_free(ctx); return 0; }
/* Takes complete update history, gets summary of last state. */ struct channel_state *gather_updates(const tal_t *ctx, const OpenChannel *o1, const OpenChannel *o2, const OpenAnchor *oa, uint64_t fee, char **argv, size_t *num_updates, struct sha256 *our_rhash, struct sha256 *their_rhash, struct signature *their_commit_sig) { Signature *sig = NULL; struct sha256 old_our_rhash, old_their_rhash, rhash1, rhash2; struct channel_state *cstate; /* Start sanity check. */ cstate = initial_funding(NULL, o1, o2, oa, fee); if (!cstate) errx(1, "Invalid open combination (need 1 anchor offer)"); /* If they don't want these, use dummy ones. */ if (!our_rhash) our_rhash = &rhash1; if (!their_rhash) their_rhash = &rhash2; proto_to_sha256(o1->revocation_hash, our_rhash); proto_to_sha256(o2->revocation_hash, their_rhash); assert(tal_count(cstate->a.htlcs) == 0); assert(tal_count(cstate->b.htlcs) == 0); /* If o2 sent anchor, it contains their commit sig. */ if (o2->anch == OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR) sig = oa->commit_sig; if (num_updates) *num_updates = 0; while (*argv) { int64_t delta, amount; size_t n; bool received; Pkt *pkt; /* + marks messages sent by us, - for messages from them */ if (strstarts(*argv, "+")) { received = false; } else if (strstarts(*argv, "-")) { received = true; } else errx(1, "%s does not start with +/-", *argv); pkt = any_pkt_from_file(*argv + 1); switch (pkt->pkt_case) { case PKT__PKT_OPEN_COMMIT_SIG: if (received) sig = pkt->open_commit_sig->sig; break; case PKT__PKT_UPDATE_ADD_HTLC: amount = pkt->update_add_htlc->amount_msat; if (received) { if (!funding_delta(o2, o1, oa, 0, amount, &cstate->b, &cstate->a)) errx(1, "Impossible htlc %llu %s", (long long)amount, *argv); add_htlc(&cstate->b, pkt->update_add_htlc, *argv); } else { if (!funding_delta(o1, o2, oa, 0, amount, &cstate->a, &cstate->b)) errx(1, "Impossible htlc %llu %s", (long long)amount, *argv); add_htlc(&cstate->a, pkt->update_add_htlc, *argv); } update_rhash(pkt->update_add_htlc->revocation_hash, received, num_updates, &old_our_rhash, &old_their_rhash, our_rhash, their_rhash); break; case PKT__PKT_UPDATE_TIMEDOUT_HTLC: if (received) { n = find_htlc(&cstate->b, pkt->update_timedout_htlc->r_hash); if (n == tal_count(cstate->b.htlcs)) errx(1, "Unknown R hash in %s", *argv); amount = cstate->b.htlcs[n]->amount_msat; if (!funding_delta(o2, o1, oa, 0, -amount, &cstate->b, &cstate->a)) errx(1, "Impossible htlc %llu %s", (long long)amount, *argv); remove_htlc(&cstate->b, n); } else { n = find_htlc(&cstate->a, pkt->update_timedout_htlc->r_hash); if (n == tal_count(cstate->a.htlcs)) errx(1, "Unknown R hash in %s", *argv); amount = cstate->a.htlcs[n]->amount_msat; if (!funding_delta(o1, o2, oa, 0, -amount, &cstate->a, &cstate->b)) errx(1, "Impossible htlc %llu %s", (long long)amount, *argv); remove_htlc(&cstate->a, n); } update_rhash(pkt->update_timedout_htlc->revocation_hash, received, num_updates, &old_our_rhash, &old_their_rhash, our_rhash, their_rhash); break; /* HTLC acceptor sends this to initiator. */ case PKT__PKT_UPDATE_ROUTEFAIL_HTLC: if (received) { n = find_htlc(&cstate->a, pkt->update_routefail_htlc->r_hash); if (n == tal_count(cstate->a.htlcs)) errx(1, "Unknown R hash in %s", *argv); amount = cstate->a.htlcs[n]->amount_msat; if (!funding_delta(o1, o2, oa, 0, -amount, &cstate->a, &cstate->b)) errx(1, "Impossible htlc %llu %s", (long long)amount, *argv); remove_htlc(&cstate->a, n); } else { n = find_htlc(&cstate->b, pkt->update_routefail_htlc->r_hash); if (n == tal_count(cstate->b.htlcs)) errx(1, "Unknown R hash in %s", *argv); amount = cstate->b.htlcs[n]->amount_msat; if (!funding_delta(o2, o1, oa, 0, -amount, &cstate->b, &cstate->a)) errx(1, "Impossible htlc %llu %s", (long long)amount, *argv); remove_htlc(&cstate->b, n); } update_rhash(pkt->update_routefail_htlc->revocation_hash, received, num_updates, &old_our_rhash, &old_their_rhash, our_rhash, their_rhash); break; case PKT__PKT_UPDATE_FULFILL_HTLC: { struct sha256 r_hash, r_val; Sha256Hash *rh; /* Get hash, to find the HTLC. */ proto_to_sha256(pkt->update_fulfill_htlc->r, &r_val); sha256(&r_hash, &r_val, sizeof(r_val)); rh = sha256_to_proto(ctx, &r_hash); if (received) { /* HTLC was us->them, funds go to them. */ n = find_htlc(&cstate->a, rh); if (n == tal_count(cstate->a.htlcs)) errx(1, "Unknown R hash in %s", *argv); amount = cstate->a.htlcs[n]->amount_msat; if (!funding_delta(o1, o2, oa, amount, -amount, &cstate->a, &cstate->b)) errx(1, "Impossible htlc %llu %s", (long long)amount, *argv); remove_htlc(&cstate->a, n); } else { /* HTLC was them->us, funds go to us. */ n = find_htlc(&cstate->b, rh); if (n == tal_count(cstate->b.htlcs)) errx(1, "Unknown R hash in %s", *argv); amount = cstate->b.htlcs[n]->amount_msat; if (!funding_delta(o2, o1, oa, amount, -amount, &cstate->b, &cstate->a)) errx(1, "Impossible htlc %llu %s", (long long)amount, *argv); remove_htlc(&cstate->b, n); } update_rhash(pkt->update_fulfill_htlc->revocation_hash, received, num_updates, &old_our_rhash, &old_their_rhash, our_rhash, their_rhash); break; } case PKT__PKT_UPDATE: if (received) delta = -pkt->update->delta_msat; else delta = pkt->update->delta_msat; if (!funding_delta(o1, o2, oa, delta, 0, &cstate->a, &cstate->b)) errx(1, "Impossible funding update %lli %s", (long long)delta, *argv); update_rhash(pkt->update->revocation_hash, received, num_updates, &old_our_rhash, &old_their_rhash, our_rhash, their_rhash); break; case PKT__PKT_UPDATE_ACCEPT: if (received) sig = pkt->update_accept->sig; /* Does not increase num_updates */ update_rhash(pkt->update_accept->revocation_hash, received, NULL, &old_our_rhash, &old_their_rhash, our_rhash, their_rhash); break; case PKT__PKT_UPDATE_SIGNATURE: if (received) { sig = pkt->update_signature->sig; check_preimage(pkt->update_signature ->revocation_preimage, &old_their_rhash, their_rhash, *argv); } else { check_preimage(pkt->update_signature ->revocation_preimage, &old_our_rhash, our_rhash, *argv); } break; case PKT__PKT_UPDATE_COMPLETE: if (received) { check_preimage(pkt->update_complete ->revocation_preimage, &old_their_rhash, their_rhash, *argv); } else { check_preimage(pkt->update_complete ->revocation_preimage, &old_our_rhash, our_rhash, *argv); } break; default: errx(1, "Unexpected packet type %u", pkt->pkt_case); } argv++; } if (their_commit_sig) { if (!sig) errx(1, "No commit signature message found"); if (!proto_to_signature(sig, their_commit_sig)) errx(1, "Invalid signature"); } return cstate; }
Pkt *accept_pkt_close_sig(struct peer *peer, const Pkt *pkt, bool *acked, bool *we_agree) { const CloseSignature *c = pkt->close_signature; struct bitcoin_tx *close_tx; struct bitcoin_signature theirsig; log_info(peer->log, "accept_pkt_close_sig: they offered close fee %" PRIu64, c->close_fee); *acked = *we_agree = false; /* BOLT #2: * * The sender MUST set `close_fee` lower than or equal to the fee of the * final commitment transaction, and MUST set `close_fee` to an even * number of satoshis. */ if ((c->close_fee & 1) || c->close_fee > commit_tx_fee(peer->them.commit->tx, peer->anchor.satoshis)) { return pkt_err(peer, "Invalid close fee"); } /* FIXME: Don't accept tiny fee at all? */ /* BOLT #2: ... otherwise it SHOULD propose a value strictly between the received `close_fee` and its previously-sent `close_fee`. */ if (peer->closing.their_sig) { /* We want more, they should give more. */ if (peer->closing.our_fee > peer->closing.their_fee) { if (c->close_fee <= peer->closing.their_fee) return pkt_err(peer, "Didn't increase close fee"); } else { if (c->close_fee >= peer->closing.their_fee) return pkt_err(peer, "Didn't decrease close fee"); } } /* BOLT #2: * * The receiver MUST check `sig` is valid for the close * transaction, and MUST fail the connection if it is not. */ theirsig.stype = SIGHASH_ALL; if (!proto_to_signature(c->sig, &theirsig.sig)) return pkt_err(peer, "Invalid signature format"); close_tx = peer_create_close_tx(peer, c->close_fee); if (!check_tx_sig(peer->dstate->secpctx, close_tx, 0, NULL, 0, peer->anchor.witnessscript, &peer->them.commitkey, &theirsig)) return pkt_err(peer, "Invalid signature"); tal_free(peer->closing.their_sig); peer->closing.their_sig = tal_dup(peer, struct bitcoin_signature, &theirsig); peer->closing.their_fee = c->close_fee; if (peer->closing.our_fee == peer->closing.their_fee) { log_info(peer->log, "accept_pkt_close_sig: That's an ack"); *acked = true; } else { /* Adjust our fee to close on their fee. */ u64 sum; /* Beware overflow! */ sum = (u64)peer->closing.our_fee + peer->closing.their_fee; peer->closing.our_fee = sum / 2; if (peer->closing.our_fee & 1) peer->closing.our_fee++; log_info(peer->log, "accept_pkt_close_sig: we change to %"PRIu64, peer->closing.our_fee); /* Corner case: we may now agree with them. */ if (peer->closing.our_fee == peer->closing.their_fee) *we_agree = true; } /* FIXME: Dynamic fee! */ return NULL; }