Skip to content

Commit

Permalink
introduce DynSigner and TestSignerFactory
Browse files Browse the repository at this point in the history
  • Loading branch information
devrandom committed Apr 24, 2024
1 parent 7d35171 commit 3a1986c
Show file tree
Hide file tree
Showing 8 changed files with 538 additions and 90 deletions.
11 changes: 6 additions & 5 deletions lightning-invoice/src/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ mod tests {
use core::time::Duration;
#[cfg(feature = "std")]
use std::time::SystemTime;
use bech32::ToBase32;
use lightning::sign::{NodeSigner, Recipient};

fn duration_since_epoch() -> Duration {
#[cfg(feature = "std")]
Expand Down Expand Up @@ -194,11 +196,10 @@ mod tests {
.min_final_cltv_expiry_delta(144)
.amount_milli_satoshis(50_000)
.payment_metadata(payment_metadata.clone())
.build_signed(|hash| {
Secp256k1::new().sign_ecdsa_recoverable(hash,
&nodes[1].keys_manager.backing.get_node_secret_key())
})
.unwrap();
.build_raw().unwrap();
let sig = nodes[1].keys_manager.backing.sign_invoice(invoice.hrp.to_string().as_bytes(), &invoice.data.to_base32(), Recipient::Node).unwrap();
let invoice = invoice.sign::<_, ()>(|_| Ok(sig)).unwrap();
let invoice = Bolt11Invoice::from_signed(invoice).unwrap();

let (hash, onion, params) = payment_parameters_from_invoice(&invoice).unwrap();
nodes[0].node.send_payment(hash, onion, PaymentId(hash.0), params, Retry::Attempts(0)).unwrap();
Expand Down
67 changes: 32 additions & 35 deletions lightning-invoice/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,7 @@ mod test {
use lightning::util::config::UserConfig;
use crate::utils::{create_invoice_from_channelmanager_and_duration_since_epoch, rotate_through_iterators};
use std::collections::HashSet;
use lightning::util::dyn_signer::{DynKeysInterface, DynPhantomKeysInterface};
use lightning::util::string::UntrustedString;

#[test]
Expand Down Expand Up @@ -1295,6 +1296,13 @@ mod test {
do_test_multi_node_receive(false);
}

fn make_dyn_keys_interface(seed: &[u8; 32]) -> DynKeysInterface {
let cross_node_seed = [44u8; 32];
let inner = PhantomKeysManager::new(&seed, 43, 44, &cross_node_seed);
let dyn_inner = DynPhantomKeysInterface::new(inner);
DynKeysInterface::new(Box::new(dyn_inner))
}

#[cfg(feature = "std")]
fn do_test_multi_node_receive(user_generated_pmt_hash: bool) {
use lightning::events::{Event, EventsProvider};
Expand All @@ -1303,9 +1311,8 @@ mod test {
let mut chanmon_cfgs = create_chanmon_cfgs(3);
let seed_1 = [42u8; 32];
let seed_2 = [43u8; 32];
let cross_node_seed = [44u8; 32];
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1);
chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
Expand Down Expand Up @@ -1407,9 +1414,8 @@ mod test {
let mut chanmon_cfgs = create_chanmon_cfgs(3);
let seed_1 = [42u8; 32];
let seed_2 = [43u8; 32];
let cross_node_seed = [44u8; 32];
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1);
chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
Expand Down Expand Up @@ -1501,9 +1507,8 @@ mod test {
let mut chanmon_cfgs = create_chanmon_cfgs(3);
let seed_1 = [42u8; 32];
let seed_2 = [43u8; 32];
let cross_node_seed = [44u8; 32];
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1);
chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
Expand All @@ -1530,9 +1535,8 @@ mod test {
let mut chanmon_cfgs = create_chanmon_cfgs(4);
let seed_1 = [42u8; 32];
let seed_2 = [43u8; 32];
let cross_node_seed = [44u8; 32];
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
chanmon_cfgs[3].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_1);
chanmon_cfgs[3].keys_manager.backing = make_dyn_keys_interface(&seed_2);
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
Expand Down Expand Up @@ -1561,9 +1565,8 @@ mod test {
let mut chanmon_cfgs = create_chanmon_cfgs(4);
let seed_1 = [42u8; 32];
let seed_2 = [43u8; 32];
let cross_node_seed = [44u8; 32];
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
chanmon_cfgs[3].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_1);
chanmon_cfgs[3].keys_manager.backing = make_dyn_keys_interface(&seed_2);
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
Expand Down Expand Up @@ -1619,9 +1622,8 @@ mod test {
let mut chanmon_cfgs = create_chanmon_cfgs(3);
let seed_1 = [42u8; 32];
let seed_2 = [43u8; 32];
let cross_node_seed = [44u8; 32];
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1);
chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
Expand Down Expand Up @@ -1652,9 +1654,8 @@ mod test {
let mut chanmon_cfgs = create_chanmon_cfgs(4);
let seed_1 = [42u8; 32];
let seed_2 = [43u8; 32];
let cross_node_seed = [44u8; 32];
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1);
chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2);
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
Expand Down Expand Up @@ -1686,9 +1687,8 @@ mod test {
let mut chanmon_cfgs = create_chanmon_cfgs(3);
let seed_1 = [42u8; 32];
let seed_2 = [43u8; 32];
let cross_node_seed = [44u8; 32];
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1);
chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
Expand Down Expand Up @@ -1717,9 +1717,8 @@ mod test {
let mut chanmon_cfgs = create_chanmon_cfgs(4);
let seed_1 = [42u8; 32];
let seed_2 = [43u8; 32];
let cross_node_seed = [44u8; 32];
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1);
chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2);
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
Expand Down Expand Up @@ -1792,11 +1791,10 @@ mod test {
let seed_2 = [43 as u8; 32];
let seed_3 = [44 as u8; 32];
let seed_4 = [45 as u8; 32];
let cross_node_seed = [44 as u8; 32];
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
chanmon_cfgs[3].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
chanmon_cfgs[4].keys_manager.backing = PhantomKeysManager::new(&seed_3, 43, 44, &cross_node_seed);
chanmon_cfgs[5].keys_manager.backing = PhantomKeysManager::new(&seed_4, 43, 44, &cross_node_seed);
chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_1);
chanmon_cfgs[3].keys_manager.backing = make_dyn_keys_interface(&seed_2);
chanmon_cfgs[4].keys_manager.backing = make_dyn_keys_interface(&seed_3);
chanmon_cfgs[4].keys_manager.backing = make_dyn_keys_interface(&seed_4);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(6, &node_cfgs, &[None, None, None, None, None, None]);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
Expand Down Expand Up @@ -1849,9 +1847,8 @@ mod test {
let mut chanmon_cfgs = create_chanmon_cfgs(5);
let seed_1 = [42 as u8; 32];
let seed_2 = [43 as u8; 32];
let cross_node_seed = [44 as u8; 32];
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1);
chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2);
let node_cfgs = create_node_cfgs(5, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(5, &node_cfgs, &[None, None, None, None, None]);
let nodes = create_network(5, &node_cfgs, &node_chanmgrs);
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/chain/channelmonitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4868,7 +4868,7 @@ mod tests {
nodes[1].chain_monitor.chain_monitor.transactions_confirmed(&new_header,
&[(0, broadcast_tx)], conf_height);

let (_, pre_update_monitor) = <(BlockHash, ChannelMonitor<InMemorySigner>)>::read(
let (_, pre_update_monitor) = <(BlockHash, ChannelMonitor<_>)>::read(
&mut io::Cursor::new(&get_monitor!(nodes[1], channel.2).encode()),
(&nodes[1].keys_manager.backing, &nodes[1].keys_manager.backing)).unwrap();

Expand Down
98 changes: 62 additions & 36 deletions lightning/src/sign/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ use bitcoin::hashes::{Hash, HashEngine};
use bitcoin::secp256k1::ecdh::SharedSecret;
use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
use bitcoin::secp256k1::schnorr;
#[cfg(taproot)]
use bitcoin::secp256k1::All;
use bitcoin::secp256k1::{KeyPair, PublicKey, Scalar, Secp256k1, SecretKey, Signing};
use bitcoin::secp256k1::{KeyPair, PublicKey, Scalar, Secp256k1, SecretKey, Signing, All};
use bitcoin::{secp256k1, Sequence, Txid, Witness};

use crate::chain::transaction::OutPoint;
Expand Down Expand Up @@ -727,6 +725,32 @@ impl HTLCDescriptor {
/// A trait to handle Lightning channel key material without concretizing the channel type or
/// the signature mechanism.
pub trait ChannelSigner {
/// Returns the commitment seed for the channel.
fn commitment_seed(&self) -> [u8; 32];
/// Returns the counterparty's pubkeys.
///
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
/// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation.
fn counterparty_pubkeys(&self) -> Option<&ChannelPublicKeys>;
/// Funding outpoint
///
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
/// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation.
fn funding_outpoint(&self) -> Option<&OutPoint>;
/// Returns a [`ChannelTransactionParameters`] for this channel, to be used when verifying or
/// building transactions.
///
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
/// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation.
fn get_channel_parameters(&self) -> Option<&ChannelTransactionParameters>;

/// Returns the channel type features of the channel parameters. Should be helpful for
/// determining a channel's category, i. e. legacy/anchors/taproot/etc.
///
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
/// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation.
fn channel_type_features(&self) -> Option<&ChannelTypeFeatures>;

/// Gets the per-commitment point for a specific commitment number
///
/// Note that the commitment number starts at `(1 << 48) - 1` and counts backwards.
Expand Down Expand Up @@ -914,10 +938,10 @@ pub trait OutputSpender {
/// Returns `Err(())` if the output value is greater than the input value minus required fee,
/// if a descriptor was duplicated, or if an output descriptor `script_pubkey`
/// does not match the one we can spend.
fn spend_spendable_outputs<C: Signing>(
fn spend_spendable_outputs(
&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>,
change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32,
locktime: Option<LockTime>, secp_ctx: &Secp256k1<C>,
locktime: Option<LockTime>, secp_ctx: &Secp256k1<All>,
) -> Result<Transaction, ()>;
}

Expand Down Expand Up @@ -1120,16 +1144,6 @@ impl InMemorySigner {
}
}

/// Returns the counterparty's pubkeys.
///
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
/// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation.
pub fn counterparty_pubkeys(&self) -> Option<&ChannelPublicKeys> {
self.get_channel_parameters().and_then(|params| {
params.counterparty_parameters.as_ref().map(|params| &params.pubkeys)
})
}

/// Returns the `contest_delay` value specified by our counterparty and applied on holder-broadcastable
/// transactions, i.e., the amount of time that we have to wait to recover our funds if we
/// broadcast a transaction.
Expand Down Expand Up @@ -1160,14 +1174,6 @@ impl InMemorySigner {
self.get_channel_parameters().map(|params| params.is_outbound_from_holder)
}

/// Funding outpoint
///
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
/// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation.
pub fn funding_outpoint(&self) -> Option<&OutPoint> {
self.get_channel_parameters().map(|params| params.funding_outpoint.as_ref()).flatten()
}

/// Returns a [`ChannelTransactionParameters`] for this channel, to be used when verifying or
/// building transactions.
///
Expand All @@ -1177,15 +1183,6 @@ impl InMemorySigner {
self.channel_parameters.as_ref()
}

/// Returns the channel type features of the channel parameters. Should be helpful for
/// determining a channel's category, i. e. legacy/anchors/taproot/etc.
///
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
/// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation.
pub fn channel_type_features(&self) -> Option<&ChannelTypeFeatures> {
self.get_channel_parameters().map(|params| &params.channel_type_features)
}

/// Sign the single input of `spend_tx` at index `input_idx`, which spends the output described
/// by `descriptor`, returning the witness stack for the input.
///
Expand Down Expand Up @@ -1338,6 +1335,35 @@ impl EntropySource for InMemorySigner {
}

impl ChannelSigner for InMemorySigner {
fn commitment_seed(&self) -> [u8; 32] {
self.commitment_seed
}

fn counterparty_pubkeys(&self) -> Option<&ChannelPublicKeys> {
self.get_channel_parameters().and_then(|params| {
params.counterparty_parameters.as_ref().map(|params| &params.pubkeys)
})
}

fn funding_outpoint(&self) -> Option<&OutPoint> {
self.get_channel_parameters().map(|params| params.funding_outpoint.as_ref()).flatten()
}

fn get_channel_parameters(&self) -> Option<&ChannelTransactionParameters> {
self.channel_parameters.as_ref()
}


/// Returns the channel type features of the channel parameters. Should be helpful for
/// determining a channel's category, i. e. legacy/anchors/taproot/etc.
///
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
/// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation.
fn channel_type_features(&self) -> Option<&ChannelTypeFeatures> {
self.get_channel_parameters().map(|params| &params.channel_type_features)
}


fn get_per_commitment_point(
&self, idx: u64, secp_ctx: &Secp256k1<secp256k1::All>,
) -> PublicKey {
Expand Down Expand Up @@ -2199,10 +2225,10 @@ impl OutputSpender for KeysManager {
///
/// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used
/// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`].
fn spend_spendable_outputs<C: Signing>(
fn spend_spendable_outputs(
&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>,
change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32,
locktime: Option<LockTime>, secp_ctx: &Secp256k1<C>,
locktime: Option<LockTime>, secp_ctx: &Secp256k1<All>,
) -> Result<Transaction, ()> {
let (mut psbt, expected_max_weight) =
SpendableOutputDescriptor::create_spendable_outputs_psbt(
Expand Down Expand Up @@ -2363,10 +2389,10 @@ impl NodeSigner for PhantomKeysManager {
impl OutputSpender for PhantomKeysManager {
/// See [`OutputSpender::spend_spendable_outputs`] and [`KeysManager::spend_spendable_outputs`]
/// for documentation on this method.
fn spend_spendable_outputs<C: Signing>(
fn spend_spendable_outputs(
&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>,
change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32,
locktime: Option<LockTime>, secp_ctx: &Secp256k1<C>,
locktime: Option<LockTime>, secp_ctx: &Secp256k1<All>,
) -> Result<Transaction, ()> {
self.inner.spend_spendable_outputs(
descriptors,
Expand Down

0 comments on commit 3a1986c

Please sign in to comment.