Skip to content

Commit b59efad

Browse files
authored
Merge pull request #444 from lightning-signer/funding-script
Construct funding redeem script in signer
2 parents 9c572a9 + 6200302 commit b59efad

File tree

6 files changed

+62
-22
lines changed

6 files changed

+62
-22
lines changed

fuzz/src/chanmon_consistency.rs

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ impl KeysInterface for KeyProvider {
158158
delayed_payment_base_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, self.node_id]).unwrap(),
159159
htlc_base_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, self.node_id]).unwrap(),
160160
commitment_seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, self.node_id],
161+
remote_funding_pubkey: None,
161162
})
162163
}
163164

fuzz/src/full_stack.rs

+2
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ impl KeysInterface for KeyProvider {
257257
delayed_payment_base_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, ctr]).unwrap(),
258258
htlc_base_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, ctr]).unwrap(),
259259
commitment_seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, ctr],
260+
remote_funding_pubkey: None,
260261
}
261262
} else {
262263
InMemoryChannelKeys {
@@ -266,6 +267,7 @@ impl KeysInterface for KeyProvider {
266267
delayed_payment_base_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, ctr]).unwrap(),
267268
htlc_base_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, ctr]).unwrap(),
268269
commitment_seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, ctr],
270+
remote_funding_pubkey: None,
269271
}
270272
})
271273
}

lightning/src/chain/keysinterface.rs

+24-4
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use util::logger::Logger;
2424
use util::ser::Writeable;
2525

2626
use ln::chan_utils;
27-
use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment};
27+
use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment, make_funding_redeemscript};
2828
use ln::msgs;
2929

3030
use std::sync::Arc;
@@ -142,7 +142,7 @@ pub trait ChannelKeys : Send {
142142
/// TODO: Document the things someone using this interface should enforce before signing.
143143
/// TODO: Add more input vars to enable better checking (preferably removing commitment_tx and
144144
/// making the callee generate it via some util function we expose)!
145-
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
145+
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
146146

147147
/// Create a signature for a (proposed) closing transaction.
148148
///
@@ -157,6 +157,12 @@ pub trait ChannelKeys : Send {
157157
/// our counterparty may (though likely will not) close the channel on us for violating the
158158
/// protocol.
159159
fn sign_channel_announcement<T: secp256k1::Signing>(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()>;
160+
161+
/// Set the remote funding key. This is done immediately on incoming channels
162+
/// and as soon as the channel is accepted on outgoing channels.
163+
///
164+
/// Will be called before any signatures are applied.
165+
fn set_remote_funding_pubkey(&mut self, key: &PublicKey);
160166
}
161167

162168
#[derive(Clone)]
@@ -174,6 +180,8 @@ pub struct InMemoryChannelKeys {
174180
pub htlc_base_key: SecretKey,
175181
/// Commitment seed
176182
pub commitment_seed: [u8; 32],
183+
/// Remote funding pubkey
184+
pub remote_funding_pubkey: Option<PublicKey>,
177185
}
178186

179187
impl ChannelKeys for InMemoryChannelKeys {
@@ -184,8 +192,13 @@ impl ChannelKeys for InMemoryChannelKeys {
184192
fn htlc_base_key(&self) -> &SecretKey { &self.htlc_base_key }
185193
fn commitment_seed(&self) -> &[u8; 32] { &self.commitment_seed }
186194

187-
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
195+
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
188196
if commitment_tx.input.len() != 1 { return Err(()); }
197+
198+
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
199+
let remote_funding_pubkey = self.remote_funding_pubkey.as_ref().expect("must set remote funding key before signing");
200+
let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, remote_funding_pubkey);
201+
189202
let commitment_sighash = hash_to_message!(&bip143::SighashComponents::new(&commitment_tx).sighash_all(&commitment_tx.input[0], &channel_funding_redeemscript, channel_value_satoshis)[..]);
190203
let commitment_sig = secp_ctx.sign(&commitment_sighash, &self.funding_key);
191204

@@ -222,6 +235,11 @@ impl ChannelKeys for InMemoryChannelKeys {
222235
let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
223236
Ok(secp_ctx.sign(&msghash, &self.funding_key))
224237
}
238+
239+
fn set_remote_funding_pubkey(&mut self, key: &PublicKey) {
240+
assert!(self.remote_funding_pubkey.is_none(), "Already set remote funding key");
241+
self.remote_funding_pubkey = Some(*key);
242+
}
225243
}
226244

227245
impl_writeable!(InMemoryChannelKeys, 0, {
@@ -230,7 +248,8 @@ impl_writeable!(InMemoryChannelKeys, 0, {
230248
payment_base_key,
231249
delayed_payment_base_key,
232250
htlc_base_key,
233-
commitment_seed
251+
commitment_seed,
252+
remote_funding_pubkey
234253
});
235254

236255
/// Simple KeysInterface implementor that takes a 32-byte seed for use as a BIP 32 extended key
@@ -379,6 +398,7 @@ impl KeysInterface for KeysManager {
379398
delayed_payment_base_key,
380399
htlc_base_key,
381400
commitment_seed,
401+
remote_funding_pubkey: None,
382402
}
383403
}
384404

lightning/src/ln/chan_utils.rs

+16
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,22 @@ pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, keys: &TxCreationKey
255255
get_htlc_redeemscript_with_explicit_keys(htlc, &keys.a_htlc_key, &keys.b_htlc_key, &keys.revocation_key)
256256
}
257257

258+
/// Gets the redeemscript for a funding output from the two funding public keys.
259+
/// Note that the order of funding public keys does not matter.
260+
pub fn make_funding_redeemscript(a: &PublicKey, b: &PublicKey) -> Script {
261+
let our_funding_key = a.serialize();
262+
let their_funding_key = b.serialize();
263+
264+
let builder = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2);
265+
if our_funding_key[..] < their_funding_key[..] {
266+
builder.push_slice(&our_funding_key)
267+
.push_slice(&their_funding_key)
268+
} else {
269+
builder.push_slice(&their_funding_key)
270+
.push_slice(&our_funding_key)
271+
}.push_opcode(opcodes::all::OP_PUSHNUM_2).push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script()
272+
}
273+
258274
/// panics if htlc.transaction_output_index.is_none()!
259275
pub fn build_htlc_transaction(prev_hash: &Sha256dHash, feerate_per_kw: u64, to_self_delay: u16, htlc: &HTLCOutputInCommitment, a_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction {
260276
let mut txins: Vec<TxIn> = Vec::new();

lightning/src/ln/channel.rs

+12-15
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use ln::msgs;
2020
use ln::msgs::{DecodeError, OptionalField, DataLossProtect};
2121
use ln::channelmonitor::ChannelMonitor;
2222
use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingForwardHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT};
23-
use ln::chan_utils::{LocalCommitmentTransaction,TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT};
23+
use ln::chan_utils::{LocalCommitmentTransaction, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript};
2424
use ln::chan_utils;
2525
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
2626
use chain::transaction::OutPoint;
@@ -545,7 +545,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
545545
/// Creates a new channel from a remote sides' request for one.
546546
/// Assumes chain_hash has already been checked and corresponds with what we expect!
547547
pub fn new_from_req(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface<ChanKeySigner = ChanSigner>>, their_node_id: PublicKey, their_features: InitFeatures, msg: &msgs::OpenChannel, user_id: u64, logger: Arc<Logger>, config: &UserConfig) -> Result<Channel<ChanSigner>, ChannelError> {
548-
let chan_keys = keys_provider.get_channel_keys(true);
548+
let mut chan_keys = keys_provider.get_channel_keys(true);
549+
chan_keys.set_remote_funding_pubkey(&msg.funding_pubkey);
549550
let mut local_config = (*config).channel_options.clone();
550551

551552
if config.own_channel_config.our_to_self_delay < BREAKDOWN_TIMEOUT {
@@ -1111,16 +1112,9 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
11111112
/// pays to get_funding_redeemscript().to_v0_p2wsh()).
11121113
/// Panics if called before accept_channel/new_from_req
11131114
pub fn get_funding_redeemscript(&self) -> Script {
1114-
let builder = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2);
1115-
let our_funding_key = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key()).serialize();
1116-
let their_funding_key = self.their_funding_pubkey.expect("get_funding_redeemscript only allowed after accept_channel").serialize();
1117-
if our_funding_key[..] < their_funding_key[..] {
1118-
builder.push_slice(&our_funding_key)
1119-
.push_slice(&their_funding_key)
1120-
} else {
1121-
builder.push_slice(&their_funding_key)
1122-
.push_slice(&our_funding_key)
1123-
}.push_opcode(opcodes::all::OP_PUSHNUM_2).push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script()
1115+
let our_funding_key = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key());
1116+
let their_funding_key = self.their_funding_pubkey.expect("get_funding_redeemscript only allowed after accept_channel");
1117+
make_funding_redeemscript(&our_funding_key, &their_funding_key)
11241118
}
11251119

11261120
/// Builds the htlc-success or htlc-timeout transaction which spends a given HTLC output
@@ -1407,6 +1401,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
14071401
self.channel_monitor.set_basic_channel_info(&msg.htlc_basepoint, &msg.delayed_payment_basepoint, msg.to_self_delay, funding_redeemscript, self.channel_value_satoshis, obscure_factor);
14081402

14091403
self.channel_state = ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32;
1404+
self.local_keys.set_remote_funding_pubkey(&msg.funding_pubkey);
14101405

14111406
Ok(())
14121407
}
@@ -1425,7 +1420,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
14251420

14261421
let remote_keys = self.build_remote_transaction_keys()?;
14271422
let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw).0;
1428-
let remote_signature = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx)
1423+
let remote_signature = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx)
14291424
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?.0;
14301425

14311426
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
@@ -2645,6 +2640,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
26452640

26462641
self.channel_state |= ChannelState::LocalShutdownSent as u32;
26472642
self.channel_update_count += 1;
2643+
26482644
Ok((our_shutdown, self.maybe_propose_first_closing_signed(fee_estimator), dropped_outbound_htlcs))
26492645
}
26502646

@@ -3151,7 +3147,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
31513147
fn get_outbound_funding_created_signature(&mut self) -> Result<(Signature, Transaction), ChannelError> {
31523148
let remote_keys = self.build_remote_transaction_keys()?;
31533149
let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw).0;
3154-
Ok((self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx)
3150+
Ok((self.local_keys.sign_remote_commitment(self.channel_value_satoshis, self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx)
31553151
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?.0, remote_initial_commitment_tx))
31563152
}
31573153

@@ -3459,7 +3455,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
34593455
htlcs.push(htlc);
34603456
}
34613457

3462-
let res = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), feerate_per_kw, &remote_commitment_tx.0, &remote_keys, &htlcs, self.our_to_self_delay, &self.secp_ctx)
3458+
let res = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, feerate_per_kw, &remote_commitment_tx.0, &remote_keys, &htlcs, self.our_to_self_delay, &self.secp_ctx)
34633459
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?;
34643460
signature = res.0;
34653461
htlc_signatures = res.1;
@@ -4131,6 +4127,7 @@ mod tests {
41314127
// These aren't set in the test vectors:
41324128
revocation_base_key: SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
41334129
commitment_seed: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
4130+
remote_funding_pubkey: None,
41344131
};
41354132
assert_eq!(PublicKey::from_secret_key(&secp_ctx, chan_keys.funding_key()).serialize()[..],
41364133
hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);

lightning/src/util/enforcing_trait_impls.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use bitcoin::blockdata::transaction::Transaction;
99
use bitcoin::blockdata::script::Script;
1010

1111
use secp256k1;
12-
use secp256k1::key::SecretKey;
12+
use secp256k1::key::{SecretKey, PublicKey};
1313
use secp256k1::{Secp256k1, Signature};
1414

1515
/// Enforces some rules on ChannelKeys calls. Eventually we will probably want to expose a variant
@@ -35,7 +35,7 @@ impl ChannelKeys for EnforcingChannelKeys {
3535
fn htlc_base_key(&self) -> &SecretKey { self.inner.htlc_base_key() }
3636
fn commitment_seed(&self) -> &[u8; 32] { self.inner.commitment_seed() }
3737

38-
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_script: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
38+
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
3939
if commitment_tx.input.len() != 1 { panic!(); }
4040
let obscured_commitment_transaction_number = (commitment_tx.lock_time & 0xffffff) as u64 | ((commitment_tx.input[0].sequence as u64 & 0xffffff) << 3*8);
4141

@@ -49,7 +49,7 @@ impl ChannelKeys for EnforcingChannelKeys {
4949
commitment_data.1 = cmp::max(commitment_number, commitment_data.1)
5050
}
5151

52-
Ok(self.inner.sign_remote_commitment(channel_value_satoshis, channel_funding_script, feerate_per_kw, commitment_tx, keys, htlcs, to_self_delay, secp_ctx).unwrap())
52+
Ok(self.inner.sign_remote_commitment(channel_value_satoshis, feerate_per_kw, commitment_tx, keys, htlcs, to_self_delay, secp_ctx).unwrap())
5353
}
5454

5555
fn sign_closing_transaction<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, closing_tx: &Transaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
@@ -59,6 +59,10 @@ impl ChannelKeys for EnforcingChannelKeys {
5959
fn sign_channel_announcement<T: secp256k1::Signing>(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
6060
self.inner.sign_channel_announcement(msg, secp_ctx)
6161
}
62+
63+
fn set_remote_funding_pubkey(&mut self, key: &PublicKey) {
64+
self.inner.set_remote_funding_pubkey(key)
65+
}
6266
}
6367

6468
impl_writeable!(EnforcingChannelKeys, 0, {

0 commit comments

Comments
 (0)