diff --git a/lightningd/hsm/hsm.c b/lightningd/hsm/hsm.c index 67d803581..5496f049a 100644 --- a/lightningd/hsm/hsm.c +++ b/lightningd/hsm/hsm.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include @@ -8,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -198,7 +202,7 @@ static void populate_secretstuff(void) "Can't derive private bip32 key"); } -static inline void bitcoin_pubkey(struct pubkey *pubkey, u32 index) +static void bitcoin_pubkey(struct pubkey *pubkey, u32 index) { struct ext_key ext; @@ -217,9 +221,9 @@ static inline void bitcoin_pubkey(struct pubkey *pubkey, u32 index) "Parse of BIP32 child %u pubkey failed", index); } -static inline void bitcoin_keypair(struct privkey *privkey, - struct pubkey *pubkey, - u32 index) +static void bitcoin_keypair(struct privkey *privkey, + struct pubkey *pubkey, + u32 index) { struct ext_key ext; @@ -340,6 +344,82 @@ static u8 *pass_hsmfd_ecdh(struct io_conn *conn, return towire_hsmctl_hsmfd_fd_response(control); } +/* Note that it's the main daemon that asks for the funding signature so it + * can broadcast it. */ +static u8 *sign_funding_tx(const tal_t *ctx, const u8 *data) +{ + const tal_t *tmpctx = tal_tmpctx(ctx); + u64 satoshi_out, change_out; + u32 change_keyindex; + struct privkey local_privkey; + struct pubkey local_pubkey, remote_pubkey; + struct utxo *inputs; + struct bitcoin_tx *tx; + u8 *wscript, *msg_out; + secp256k1_ecdsa_signature *sig; + const void **inmap; + size_t i; + + /* FIXME: Check fee is "reasonable" */ + if (!fromwire_hsmctl_sign_funding(tmpctx, data, NULL, + &satoshi_out, &change_out, + &change_keyindex, &local_privkey, + &local_pubkey, &inputs)) + status_failed(WIRE_HSMSTATUS_BAD_REQUEST, "Bad SIGN_FUNDING"); + + if (!secp256k1_ec_pubkey_create(secp256k1_ctx, + &local_pubkey.pubkey, + local_privkey.secret)) + status_failed(WIRE_HSMSTATUS_BAD_REQUEST, + "Bad SIGN_FUNDING privkey"); + + tx = bitcoin_tx(tmpctx, tal_count(inputs), 1 + !!change_out); + inmap = tal_arr(tmpctx, const void *, tal_count(inputs)); + for (i = 0; i < tal_count(inputs); i++) { + tx->input[i].txid = inputs[i].txid; + tx->input[i].index = inputs[i].outnum; + tx->input[i].amount = tal_dup(tx->input, u64, &inputs[i].amount); + inmap[i] = int2ptr(i); + } + tx->output[0].amount = satoshi_out; + wscript = bitcoin_redeem_2of2(tx, &local_pubkey, &remote_pubkey); + tx->output[0].script = scriptpubkey_p2wsh(tx, wscript); + if (change_out) { + struct pubkey changekey; + bitcoin_pubkey(&changekey, change_keyindex); + + tx->output[1].amount = change_out; + tx->output[1].script = scriptpubkey_p2wpkh(tx, &changekey); + } + + /* Now permute. */ + permute_outputs(tx->output, tal_count(tx->output), NULL); + permute_inputs(tx->input, tal_count(tx->input), inmap); + + /* Now generate signatures. */ + sig = tal_arr(tmpctx, secp256k1_ecdsa_signature, tal_count(inputs)); + for (i = 0; i < tal_count(inputs); i++) { + struct pubkey inkey; + struct privkey inprivkey; + const struct utxo *in = &inputs[ptr2int(inmap[i])]; + u8 *subscript; + + bitcoin_keypair(&inprivkey, &inkey, in->keyindex); + if (in->is_p2sh) + subscript = bitcoin_redeem_p2wpkh(tmpctx, &inkey); + else + subscript = NULL; + wscript = p2wpkh_scriptcode(tmpctx, &inkey); + + sign_tx_input(tx, i, subscript, wscript, + &inprivkey, &inkey, &sig[i]); + } + + msg_out = towire_hsmctl_sign_funding_response(ctx, sig); + tal_free(tmpctx); + return msg_out; +} + static struct io_plan *control_received_req(struct io_conn *conn, struct conn_info *control) { @@ -359,9 +439,13 @@ static struct io_plan *control_received_req(struct io_conn *conn, control->out = pass_hsmfd_ecdh(conn, control, control->in, &control->out_fd); goto send_out; + case WIRE_HSMCTL_SIGN_FUNDING: + control->out = sign_funding_tx(control, control->in); + goto send_out; case WIRE_HSMCTL_INIT_RESPONSE: case WIRE_HSMCTL_HSMFD_FD_RESPONSE: + case WIRE_HSMCTL_SIGN_FUNDING_RESPONSE: break; } diff --git a/lightningd/hsm/hsm_control_wire_csv b/lightningd/hsm/hsm_control_wire_csv index 33137e2c8..9815c92fe 100644 --- a/lightningd/hsm/hsm_control_wire_csv +++ b/lightningd/hsm/hsm_control_wire_csv @@ -11,5 +11,21 @@ hsmctl_init_response,35,bip32_seed,bip32_len*1,u8 hsmctl_hsmfd_ecdh,3 hsmctl_hsmfd_ecdh,0,unique_id,8 +# Return signature for a funding tx. +#include +# FIXME: This should also take their commit sig & details, to verify. +hsmctl_sign_funding,4 +hsmctl_sign_funding,0,satoshi_out,8 +hsmctl_sign_funding,8,change_out,8 +hsmctl_sign_funding,16,change_keyindex,4 +hsmctl_sign_funding,20,our_privkey,32,struct privkey +hsmctl_sign_funding,52,their_pubkey,33 +hsmctl_sign_funding,85,num_inputs,2 +hsmctl_sign_funding,87,inputs,num_inputs*49,struct utxo + +hsmctl_sign_funding_response,104 +hsmctl_sign_funding_response,0,num_sigs,2 +hsmctl_sign_funding_response,0,sig,num_sigs*64,secp256k1_ecdsa_signature + # No message, just an fd. hsmctl_hsmfd_fd_response,103