From c6bcf75848cf6b0f0d1f873e211a711697c2b80a Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Sun, 5 Nov 2023 21:36:59 -0800 Subject: [PATCH] Add TaprootSigner variant to SignerProvider. Previously, SignerProvider was not laid out to support multiple signer types. However, with the distinction between ECDSA and Taproot signers, we now need to account for SignerProviders needing to support both. This approach does mean that if ever we introduced another signer type in the future, all implementers of SignerProvider would need to add it as an associated type, and would also need to write a set of dummy implementations for any Signer trait they do not wish to support. For the time being, the TaprootSigner associated type is cfg-gated. --- fuzz/src/chanmon_consistency.rs | 2 + fuzz/src/full_stack.rs | 2 + fuzz/src/onion_message.rs | 2 + lightning/src/ln/channel.rs | 2 + lightning/src/sign/mod.rs | 54 +++++++++++++++++++++ lightning/src/util/test_channel_signer.rs | 57 +++++++++++++++++++++-- lightning/src/util/test_utils.rs | 4 ++ 7 files changed, 118 insertions(+), 5 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 22491bdf0..f65490877 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -231,6 +231,8 @@ impl NodeSigner for KeyProvider { impl SignerProvider for KeyProvider { type EcdsaSigner = TestChannelSigner; + #[cfg(taproot)] + type TaprootSigner = TestChannelSigner; fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed) as u8; diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 49d676506..57c78e76d 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -341,6 +341,8 @@ impl NodeSigner for KeyProvider { impl SignerProvider for KeyProvider { type EcdsaSigner = TestChannelSigner; + #[cfg(taproot)] + type TaprootSigner = TestChannelSigner; fn generate_channel_keys_id(&self, inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { let ctr = self.counter.fetch_add(1, Ordering::Relaxed) as u8; diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 6ddee84c0..13de5005c 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -190,6 +190,8 @@ impl NodeSigner for KeyProvider { impl SignerProvider for KeyProvider { type EcdsaSigner = TestChannelSigner; + #[cfg(taproot)] + type TaprootSigner = TestChannelSigner; fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { unreachable!() } diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index cf543b32d..157103fea 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -7863,6 +7863,8 @@ use crate::ln::channelmanager::{self, HTLCSource, PaymentId}; impl SignerProvider for Keys { type EcdsaSigner = InMemorySigner; + #[cfg(taproot)] + type TaprootSigner = InMemorySigner; fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { self.signer.channel_keys_id() diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index a21a68f19..a2740bc35 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -29,6 +29,8 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hash_types::WPubkeyHash; +#[cfg(taproot)] +use bitcoin::secp256k1::All; use bitcoin::secp256k1::{KeyPair, PublicKey, Scalar, Secp256k1, SecretKey, Signing}; use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature}; @@ -44,6 +46,8 @@ use crate::ln::{chan_utils, PaymentPreimage}; use crate::ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction}; use crate::ln::channel_keys::{DelayedPaymentBasepoint, DelayedPaymentKey, HtlcKey, HtlcBasepoint, RevocationKey, RevocationBasepoint}; use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage}; +#[cfg(taproot)] +use crate::ln::msgs::PartialSignatureWithNonce; use crate::ln::script::ShutdownScript; use crate::offers::invoice::UnsignedBolt12Invoice; use crate::offers::invoice_request::UnsignedInvoiceRequest; @@ -52,9 +56,13 @@ use crate::prelude::*; use core::convert::TryInto; use core::ops::Deref; use core::sync::atomic::{AtomicUsize, Ordering}; +#[cfg(taproot)] +use musig2::types::{PartialSignature, PublicNonce, SecretNonce}; use crate::io::{self, Error}; use crate::ln::features::ChannelTypeFeatures; use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT}; +#[cfg(taproot)] +use crate::sign::taproot::TaprootChannelSigner; use crate::util::atomic_counter::AtomicCounter; use crate::util::chacha20::ChaCha20; use crate::util::invoice::construct_invoice_preimage; @@ -869,6 +877,9 @@ pub trait NodeSigner { pub trait SignerProvider { /// A type which implements [`WriteableEcdsaChannelSigner`] which will be returned by [`Self::derive_channel_signer`]. type EcdsaSigner: WriteableEcdsaChannelSigner; + #[cfg(taproot)] + /// A type which implements [`TaprootChannelSigner`] + type TaprootSigner: TaprootChannelSigner; /// Generates a unique `channel_keys_id` that can be used to obtain a [`Self::EcdsaSigner`] through /// [`SignerProvider::derive_channel_signer`]. The `user_channel_id` is provided to allow @@ -1380,6 +1391,45 @@ impl EcdsaChannelSigner for InMemorySigner { } } +#[cfg(taproot)] +impl TaprootChannelSigner for InMemorySigner { + fn generate_local_nonce_pair(&self, commitment_number: u64, secp_ctx: &Secp256k1) -> PublicNonce { + todo!() + } + + fn partially_sign_counterparty_commitment(&self, counterparty_nonce: PublicNonce, commitment_tx: &CommitmentTransaction, preimages: Vec, secp_ctx: &Secp256k1) -> Result<(PartialSignatureWithNonce, Vec), ()> { + todo!() + } + + fn finalize_holder_commitment(&self, commitment_number: u64, commitment_tx: &HolderCommitmentTransaction, counterparty_partial_signature: PartialSignatureWithNonce, secp_ctx: &Secp256k1) -> Result { + todo!() + } + + fn sign_justice_revoked_output(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, secp_ctx: &Secp256k1) -> Result { + todo!() + } + + fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { + todo!() + } + + fn sign_holder_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor, secp_ctx: &Secp256k1) -> Result { + todo!() + } + + fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { + todo!() + } + + fn partially_sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1) -> Result { + todo!() + } + + fn sign_holder_anchor_input(&self, anchor_tx: &Transaction, input: usize, secp_ctx: &Secp256k1) -> Result { + todo!() + } +} + const SERIALIZATION_VERSION: u8 = 1; const MIN_SERIALIZATION_VERSION: u8 = 1; @@ -1783,6 +1833,8 @@ impl NodeSigner for KeysManager { impl SignerProvider for KeysManager { type EcdsaSigner = InMemorySigner; + #[cfg(taproot)] + type TaprootSigner = InMemorySigner; fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32] { let child_idx = self.channel_child_index.fetch_add(1, Ordering::AcqRel); @@ -1902,6 +1954,8 @@ impl NodeSigner for PhantomKeysManager { impl SignerProvider for PhantomKeysManager { type EcdsaSigner = InMemorySigner; + #[cfg(taproot)] + type TaprootSigner = InMemorySigner; fn generate_channel_keys_id(&self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32] { self.inner.generate_channel_keys_id(inbound, channel_value_satoshis, user_channel_id) diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index 9c6a1e302..3e0ca970e 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -24,12 +24,20 @@ use bitcoin::sighash; use bitcoin::sighash::EcdsaSighashType; use bitcoin::secp256k1; +#[cfg(taproot)] +use bitcoin::secp256k1::All; use bitcoin::secp256k1::{SecretKey, PublicKey}; use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature}; +#[cfg(taproot)] +use musig2::types::{PartialSignature, PublicNonce, SecretNonce}; use crate::sign::HTLCDescriptor; use crate::util::ser::{Writeable, Writer}; use crate::io::Error; use crate::ln::features::ChannelTypeFeatures; +#[cfg(taproot)] +use crate::ln::msgs::PartialSignatureWithNonce; +#[cfg(taproot)] +use crate::sign::taproot::TaprootChannelSigner; /// Initial value for revoked commitment downward counter pub const INITIAL_REVOKED_COMMITMENT_NUMBER: u64 = 1 << 48; @@ -201,11 +209,11 @@ impl EcdsaChannelSigner for TestChannelSigner { } fn sign_justice_revoked_output(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, secp_ctx: &Secp256k1) -> Result { - Ok(self.inner.sign_justice_revoked_output(justice_tx, input, amount, per_commitment_key, secp_ctx).unwrap()) + Ok(EcdsaChannelSigner::sign_justice_revoked_output(&self.inner, justice_tx, input, amount, per_commitment_key, secp_ctx).unwrap()) } fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { - Ok(self.inner.sign_justice_revoked_htlc(justice_tx, input, amount, per_commitment_key, htlc, secp_ctx).unwrap()) + Ok(EcdsaChannelSigner::sign_justice_revoked_htlc(&self.inner, justice_tx, input, amount, per_commitment_key, htlc, secp_ctx).unwrap()) } fn sign_holder_htlc_transaction( @@ -241,11 +249,11 @@ impl EcdsaChannelSigner for TestChannelSigner { &hash_to_message!(sighash.as_byte_array()), &htlc_descriptor.counterparty_sig, &countersignatory_htlc_key.to_public_key() ).unwrap(); } - Ok(self.inner.sign_holder_htlc_transaction(htlc_tx, input, htlc_descriptor, secp_ctx).unwrap()) + Ok(EcdsaChannelSigner::sign_holder_htlc_transaction(&self.inner, htlc_tx, input, htlc_descriptor, secp_ctx).unwrap()) } fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { - Ok(self.inner.sign_counterparty_htlc_transaction(htlc_tx, input, amount, per_commitment_point, htlc, secp_ctx).unwrap()) + Ok(EcdsaChannelSigner::sign_counterparty_htlc_transaction(&self.inner, htlc_tx, input, amount, per_commitment_point, htlc, secp_ctx).unwrap()) } fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1) -> Result { @@ -261,7 +269,7 @@ impl EcdsaChannelSigner for TestChannelSigner { // As long as our minimum dust limit is enforced and is greater than our anchor output // value, an anchor output can only have an index within [0, 1]. assert!(anchor_tx.input[input].previous_output.vout == 0 || anchor_tx.input[input].previous_output.vout == 1); - self.inner.sign_holder_anchor_input(anchor_tx, input, secp_ctx) + EcdsaChannelSigner::sign_holder_anchor_input(&self.inner, anchor_tx, input, secp_ctx) } fn sign_channel_announcement_with_funding_key( @@ -273,6 +281,45 @@ impl EcdsaChannelSigner for TestChannelSigner { impl WriteableEcdsaChannelSigner for TestChannelSigner {} +#[cfg(taproot)] +impl TaprootChannelSigner for TestChannelSigner { + fn generate_local_nonce_pair(&self, commitment_number: u64, secp_ctx: &Secp256k1) -> PublicNonce { + todo!() + } + + fn partially_sign_counterparty_commitment(&self, counterparty_nonce: PublicNonce, commitment_tx: &CommitmentTransaction, preimages: Vec, secp_ctx: &Secp256k1) -> Result<(PartialSignatureWithNonce, Vec), ()> { + todo!() + } + + fn finalize_holder_commitment(&self, commitment_number: u64, commitment_tx: &HolderCommitmentTransaction, counterparty_partial_signature: PartialSignatureWithNonce, secp_ctx: &Secp256k1) -> Result { + todo!() + } + + fn sign_justice_revoked_output(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, secp_ctx: &Secp256k1) -> Result { + todo!() + } + + fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { + todo!() + } + + fn sign_holder_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor, secp_ctx: &Secp256k1) -> Result { + todo!() + } + + fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { + todo!() + } + + fn partially_sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1) -> Result { + todo!() + } + + fn sign_holder_anchor_input(&self, anchor_tx: &Transaction, input: usize, secp_ctx: &Secp256k1) -> Result { + todo!() + } +} + impl Writeable for TestChannelSigner { fn write(&self, writer: &mut W) -> Result<(), Error> { // TestChannelSigner has two fields - `inner` ([`InMemorySigner`]) and `state` diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index b46f14681..c9563f42f 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -176,6 +176,8 @@ impl EntropySource for OnlyReadsKeysInterface { impl SignerProvider for OnlyReadsKeysInterface { type EcdsaSigner = TestChannelSigner; + #[cfg(taproot)] + type TaprootSigner = TestChannelSigner; fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { unreachable!(); } @@ -1097,6 +1099,8 @@ impl NodeSigner for TestKeysInterface { impl SignerProvider for TestKeysInterface { type EcdsaSigner = TestChannelSigner; + #[cfg(taproot)] + type TaprootSigner = TestChannelSigner; fn generate_channel_keys_id(&self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32] { self.backing.generate_channel_keys_id(inbound, channel_value_satoshis, user_channel_id) -- 2.39.5