Skip to content

Commit 08a9495

Browse files
committed
construct funding redeem script in signer
1 parent ffba0d3 commit 08a9495

File tree

6 files changed

+60
-21
lines changed

6 files changed

+60
-21
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ impl KeysInterface for KeyProvider {
157157
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(),
158158
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(),
159159
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],
160+
remote_funding_pubkey: None,
160161
})
161162
}
162163

fuzz/src/full_stack.rs

Lines changed: 2 additions & 0 deletions
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

Lines changed: 24 additions & 4 deletions
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;
@@ -147,7 +147,7 @@ pub trait ChannelKeys : Send {
147147
/// TODO: Document the things someone using this interface should enforce before signing.
148148
/// TODO: Add more input vars to enable better checking (preferably removing commitment_tx and
149149
/// making the callee generate it via some util function we expose)!
150-
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>, redeem_scripts: &Vec<Script>, remote_per_commitment_point: &PublicKey) -> Result<(Signature, Vec<Signature>), ()>;
150+
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>, redeem_scripts: &Vec<Script>, remote_per_commitment_point: &PublicKey) -> Result<(Signature, Vec<Signature>), ()>;
151151

152152
/// Create a signature for a (proposed) closing transaction.
153153
///
@@ -164,6 +164,12 @@ pub trait ChannelKeys : Send {
164164
/// our counterparty may (though likely will not) close the channel on us for violating the
165165
/// protocol.
166166
fn sign_channel_announcement<T: secp256k1::Signing>(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()>;
167+
168+
/// Set the remote funding key. This should be done immediately on incoming channels
169+
/// and as soon as the channel is accepted on outgoing channels.
170+
///
171+
/// Must be called before any signatures are applied.
172+
fn set_remote_funding_pubkey(&mut self, key: &PublicKey);
167173
}
168174

169175
#[derive(Clone)]
@@ -181,6 +187,8 @@ pub struct InMemoryChannelKeys {
181187
pub htlc_base_key: SecretKey,
182188
/// Commitment seed
183189
pub commitment_seed: [u8; 32],
190+
/// Remote funding pubkey
191+
pub remote_funding_pubkey: Option<PublicKey>,
184192
}
185193

186194
impl ChannelKeys for InMemoryChannelKeys {
@@ -191,9 +199,13 @@ impl ChannelKeys for InMemoryChannelKeys {
191199
fn htlc_base_key(&self) -> &SecretKey { &self.htlc_base_key }
192200
fn commitment_seed(&self) -> &[u8; 32] { &self.commitment_seed }
193201

194-
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>, redeem_scripts: &Vec<Script>, remote_per_commitment_point: &PublicKey) -> Result<(Signature, Vec<Signature>), ()> {
202+
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>, redeem_scripts: &Vec<Script>, _remote_per_commitment_point: &PublicKey) -> Result<(Signature, Vec<Signature>), ()> {
195203
if commitment_tx.input.len() != 1 { return Err(()); }
196204
if commitment_tx.output.len() != redeem_scripts.len() { return Err(()); }
205+
206+
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
207+
let channel_funding_redeemscript = make_funding_redeemscript(funding_pubkey, self.remote_funding_pubkey.expect("must set remote funding key before signing"));
208+
197209
let commitment_sighash = hash_to_message!(&bip143::SighashComponents::new(&commitment_tx).sighash_all(&commitment_tx.input[0], &channel_funding_redeemscript, channel_value_satoshis)[..]);
198210
let commitment_sig = secp_ctx.sign(&commitment_sighash, &self.funding_key);
199211

@@ -230,6 +242,11 @@ impl ChannelKeys for InMemoryChannelKeys {
230242
let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
231243
Ok(secp_ctx.sign(&msghash, &self.funding_key))
232244
}
245+
246+
fn set_remote_funding_pubkey(&mut self, key: &PublicKey) {
247+
assert!(self.remote_funding_pubkey.is_none(), "Already set remote funding key");
248+
self.remote_funding_pubkey = Some(*key);
249+
}
233250
}
234251

235252
impl_writeable!(InMemoryChannelKeys, 0, {
@@ -238,7 +255,8 @@ impl_writeable!(InMemoryChannelKeys, 0, {
238255
payment_base_key,
239256
delayed_payment_base_key,
240257
htlc_base_key,
241-
commitment_seed
258+
commitment_seed,
259+
remote_funding_pubkey
242260
});
243261

244262
/// Simple KeysInterface implementor that takes a 32-byte seed for use as a BIP 32 extended key
@@ -379,6 +397,7 @@ impl KeysInterface for KeysManager {
379397
let payment_base_key = key_step!(b"payment base key", revocation_base_key);
380398
let delayed_payment_base_key = key_step!(b"delayed payment base key", payment_base_key);
381399
let htlc_base_key = key_step!(b"HTLC base key", delayed_payment_base_key);
400+
let remote_funding_pubkey = None;
382401

383402
InMemoryChannelKeys {
384403
funding_key,
@@ -387,6 +406,7 @@ impl KeysInterface for KeysManager {
387406
delayed_payment_base_key,
388407
htlc_base_key,
389408
commitment_seed,
409+
remote_funding_pubkey,
390410
}
391411
}
392412

lightning/src/ln/chan_utils.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,21 @@ 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+
/// redeem script for funding transaction output
259+
pub fn make_funding_redeemscript(our_funding_pubkey: PublicKey, their_funding_pubkey: PublicKey) -> Script {
260+
let our_funding_key = our_funding_pubkey.serialize();
261+
let their_funding_key = their_funding_pubkey.serialize();
262+
263+
let builder = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2);
264+
if our_funding_key[..] < their_funding_key[..] {
265+
builder.push_slice(&our_funding_key)
266+
.push_slice(&their_funding_key)
267+
} else {
268+
builder.push_slice(&their_funding_key)
269+
.push_slice(&our_funding_key)
270+
}.push_opcode(opcodes::all::OP_PUSHNUM_2).push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script()
271+
}
272+
258273
/// panics if htlc.transaction_output_index.is_none()!
259274
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 {
260275
let mut txins: Vec<TxIn> = Vec::new();

lightning/src/ln/channel.rs

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

550551
if config.own_channel_config.our_to_self_delay < BREAKDOWN_TIMEOUT {
@@ -1118,16 +1119,9 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
11181119
/// pays to get_funding_redeemscript().to_v0_p2wsh()).
11191120
/// Panics if called before accept_channel/new_from_req
11201121
pub fn get_funding_redeemscript(&self) -> Script {
1121-
let builder = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2);
1122-
let our_funding_key = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key()).serialize();
1123-
let their_funding_key = self.their_funding_pubkey.expect("get_funding_redeemscript only allowed after accept_channel").serialize();
1124-
if our_funding_key[..] < their_funding_key[..] {
1125-
builder.push_slice(&our_funding_key)
1126-
.push_slice(&their_funding_key)
1127-
} else {
1128-
builder.push_slice(&their_funding_key)
1129-
.push_slice(&our_funding_key)
1130-
}.push_opcode(opcodes::all::OP_PUSHNUM_2).push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script()
1122+
let our_funding_key = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key());
1123+
let their_funding_key = self.their_funding_pubkey.expect("get_funding_redeemscript only allowed after accept_channel");
1124+
make_funding_redeemscript(our_funding_key, their_funding_key)
11311125
}
11321126

11331127
/// Builds the htlc-success or htlc-timeout transaction which spends a given HTLC output
@@ -1414,6 +1408,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
14141408
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);
14151409

14161410
self.channel_state = ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32;
1411+
self.local_keys.set_remote_funding_pubkey(&msg.funding_pubkey);
14171412

14181413
Ok(())
14191414
}
@@ -1434,7 +1429,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
14341429
let commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw);
14351430
let remote_initial_commitment_tx = commitment_tx.0;
14361431
let scripts = commitment_tx.3;
1437-
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, &scripts, &self.their_cur_commitment_point.unwrap())
1432+
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, &scripts, &self.their_cur_commitment_point.unwrap())
14381433
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?.0;
14391434

14401435
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
@@ -2654,6 +2649,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
26542649

26552650
self.channel_state |= ChannelState::LocalShutdownSent as u32;
26562651
self.channel_update_count += 1;
2652+
26572653
Ok((our_shutdown, self.maybe_propose_first_closing_signed(fee_estimator), dropped_outbound_htlcs))
26582654
}
26592655

@@ -3162,7 +3158,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
31623158
let commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw);
31633159
let remote_initial_commitment_tx = commitment_tx.0;
31643160
let scripts = commitment_tx.3;
3165-
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, &scripts, &self.their_cur_commitment_point.unwrap())
3161+
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, &scripts, &self.their_cur_commitment_point.unwrap())
31663162
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?.0, remote_initial_commitment_tx))
31673163
}
31683164

@@ -3470,7 +3466,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
34703466
htlcs.push(htlc);
34713467
}
34723468

3473-
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, &remote_commitment_tx.3, &self.their_cur_commitment_point.unwrap())
3469+
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, &remote_commitment_tx.3, &self.their_cur_commitment_point.unwrap())
34743470
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?;
34753471
signature = res.0;
34763472
htlc_signatures = res.1;
@@ -4142,6 +4138,7 @@ mod tests {
41424138
// These aren't set in the test vectors:
41434139
revocation_base_key: SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
41444140
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],
4141+
remote_funding_pubkey: None,
41454142
};
41464143
assert_eq!(PublicKey::from_secret_key(&secp_ctx, chan_keys.funding_key()).serialize()[..],
41474144
hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);

lightning/src/util/enforcing_trait_impls.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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>, redeem_scripts: &Vec<Script>, remote_per_commitment_point: &PublicKey) -> 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>, redeem_scripts: &Vec<Script>, remote_per_commitment_point: &PublicKey) -> Result<(Signature, Vec<Signature>), ()> {
3939
if commitment_tx.input.len() != 1 { panic!(); }
4040
if commitment_tx.output.len() != redeem_scripts.len() { panic!(); }
4141

@@ -51,7 +51,7 @@ impl ChannelKeys for EnforcingChannelKeys {
5151
commitment_data.1 = cmp::max(commitment_number, commitment_data.1)
5252
}
5353

54-
Ok(self.inner.sign_remote_commitment(channel_value_satoshis, channel_funding_script, feerate_per_kw, commitment_tx, keys, htlcs, to_self_delay, secp_ctx, redeem_scripts, remote_per_commitment_point).unwrap())
54+
Ok(self.inner.sign_remote_commitment(channel_value_satoshis, feerate_per_kw, commitment_tx, keys, htlcs, to_self_delay, secp_ctx, redeem_scripts, remote_per_commitment_point).unwrap())
5555
}
5656

5757
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, ()> {
@@ -61,6 +61,10 @@ impl ChannelKeys for EnforcingChannelKeys {
6161
fn sign_channel_announcement<T: secp256k1::Signing>(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
6262
self.inner.sign_channel_announcement(msg, secp_ctx)
6363
}
64+
65+
fn set_remote_funding_pubkey(&mut self, key: &PublicKey) {
66+
self.inner.set_remote_funding_pubkey(key)
67+
}
6468
}
6569

6670
impl_writeable!(EnforcingChannelKeys, 0, {

0 commit comments

Comments
 (0)