diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index d78f40f3fac..718b8bf519c 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -36,8 +36,8 @@ use bitcoin::sighash::EcdsaSighashType; use crate::ln::channel::INITIAL_COMMITMENT_NUMBER; use crate::ln::{PaymentHash, PaymentPreimage}; use crate::ln::msgs::DecodeError; -use crate::ln::chan_utils; -use crate::ln::chan_utils::{CommitmentTransaction, CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCClaim, ChannelTransactionParameters, HolderCommitmentTransaction, TxCreationKeys}; +use crate::ln::channel_keys::{DelayedPaymentKey, DelayedPaymentBasepoint, HtlcBasepoint, HtlcKey, RevocationKey, RevocationBasepoint}; +use crate::ln::chan_utils::{self,CommitmentTransaction, CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCClaim, ChannelTransactionParameters, HolderCommitmentTransaction, TxCreationKeys}; use crate::ln::channelmanager::{HTLCSource, SentHTLCId}; use crate::chain; use crate::chain::{BestBlock, WatchedOutput}; @@ -238,10 +238,10 @@ pub(crate) const HTLC_FAIL_BACK_BUFFER: u32 = CLTV_CLAIM_BUFFER + LATENCY_GRACE_ struct HolderSignedTx { /// txid of the transaction in tx, just used to make comparison faster txid: Txid, - revocation_key: PublicKey, - a_htlc_key: PublicKey, - b_htlc_key: PublicKey, - delayed_payment_key: PublicKey, + revocation_key: RevocationKey, + a_htlc_key: HtlcKey, + b_htlc_key: HtlcKey, + delayed_payment_key: DelayedPaymentKey, per_commitment_point: PublicKey, htlc_outputs: Vec<(HTLCOutputInCommitment, Option, Option)>, to_self_value_sat: u64, @@ -278,8 +278,8 @@ impl HolderSignedTx { /// justice or 2nd-stage preimage/timeout transactions. #[derive(Clone, PartialEq, Eq)] struct CounterpartyCommitmentParameters { - counterparty_delayed_payment_base_key: PublicKey, - counterparty_htlc_base_key: PublicKey, + counterparty_delayed_payment_base_key: DelayedPaymentBasepoint, + counterparty_htlc_base_key: HtlcBasepoint, on_counterparty_tx_csv: u16, } @@ -752,12 +752,12 @@ pub(crate) struct ChannelMonitorImpl { commitment_transaction_number_obscure_factor: u64, destination_script: ScriptBuf, - broadcasted_holder_revokable_script: Option<(ScriptBuf, PublicKey, PublicKey)>, + broadcasted_holder_revokable_script: Option<(ScriptBuf, PublicKey, RevocationKey)>, counterparty_payment_script: ScriptBuf, shutdown_script: Option, channel_keys_id: [u8; 32], - holder_revocation_basepoint: PublicKey, + holder_revocation_basepoint: RevocationBasepoint, funding_info: (OutPoint, ScriptBuf), current_counterparty_commitment_txid: Option, prev_counterparty_commitment_txid: Option, @@ -2924,12 +2924,10 @@ impl ChannelMonitorImpl { let their_per_commitment_point = PublicKey::from_secret_key( &self.onchain_tx_handler.secp_ctx, &per_commitment_key); - let revocation_pubkey = chan_utils::derive_public_revocation_key( - &self.onchain_tx_handler.secp_ctx, &their_per_commitment_point, - &self.holder_revocation_basepoint); - let delayed_key = chan_utils::derive_public_key(&self.onchain_tx_handler.secp_ctx, - &their_per_commitment_point, - &self.counterparty_commitment_params.counterparty_delayed_payment_base_key); + let revocation_pubkey = RevocationKey::from_basepoint(&self.onchain_tx_handler.secp_ctx, + &self.holder_revocation_basepoint, &their_per_commitment_point); + let delayed_key = DelayedPaymentKey::from_basepoint(&self.onchain_tx_handler.secp_ctx, + &self.counterparty_commitment_params.counterparty_delayed_payment_base_key, &their_per_commitment_point); let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.counterparty_commitment_params.on_counterparty_tx_csv, &delayed_key); @@ -2992,8 +2990,8 @@ impl ChannelMonitorImpl { let secret = self.get_secret(commitment_number).unwrap(); let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret)); let per_commitment_point = PublicKey::from_secret_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_key); - let revocation_pubkey = chan_utils::derive_public_revocation_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_point, &self.holder_revocation_basepoint); - let delayed_key = chan_utils::derive_public_key(&self.onchain_tx_handler.secp_ctx, &PublicKey::from_secret_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_key), &self.counterparty_commitment_params.counterparty_delayed_payment_base_key); + let revocation_pubkey = RevocationKey::from_basepoint(&self.onchain_tx_handler.secp_ctx, &self.holder_revocation_basepoint, &per_commitment_point,); + let delayed_key = DelayedPaymentKey::from_basepoint(&self.onchain_tx_handler.secp_ctx, &self.counterparty_commitment_params.counterparty_delayed_payment_base_key, &PublicKey::from_secret_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_key)); let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.counterparty_commitment_params.on_counterparty_tx_csv, &delayed_key); let revokeable_p2wsh = revokeable_redeemscript.to_v0_p2wsh(); @@ -3105,11 +3103,11 @@ impl ChannelMonitorImpl { } else { return (claimable_outpoints, to_counterparty_output_info); }; if let Some(transaction) = tx { - let revocation_pubkey = chan_utils::derive_public_revocation_key( - &self.onchain_tx_handler.secp_ctx, &per_commitment_point, &self.holder_revocation_basepoint); - let delayed_key = chan_utils::derive_public_key(&self.onchain_tx_handler.secp_ctx, - &per_commitment_point, - &self.counterparty_commitment_params.counterparty_delayed_payment_base_key); + let revocation_pubkey = RevocationKey::from_basepoint( + &self.onchain_tx_handler.secp_ctx, &self.holder_revocation_basepoint, &per_commitment_point); + + let delayed_key = DelayedPaymentKey::from_basepoint(&self.onchain_tx_handler.secp_ctx, &self.counterparty_commitment_params.counterparty_delayed_payment_base_key, &per_commitment_point); + let revokeable_p2wsh = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.counterparty_commitment_params.on_counterparty_tx_csv, &delayed_key).to_v0_p2wsh(); @@ -3204,7 +3202,7 @@ impl ChannelMonitorImpl { // Returns (1) `PackageTemplate`s that can be given to the OnchainTxHandler, so that the handler can // broadcast transactions claiming holder HTLC commitment outputs and (2) a holder revokable // script so we can detect whether a holder transaction has been seen on-chain. - fn get_broadcasted_holder_claims(&self, holder_tx: &HolderSignedTx, conf_height: u32) -> (Vec, Option<(ScriptBuf, PublicKey, PublicKey)>) { + fn get_broadcasted_holder_claims(&self, holder_tx: &HolderSignedTx, conf_height: u32) -> (Vec, Option<(ScriptBuf, PublicKey, RevocationKey)>) { let mut claim_requests = Vec::with_capacity(holder_tx.htlc_outputs.len()); let redeemscript = chan_utils::get_revokeable_redeemscript(&holder_tx.revocation_key, self.on_holder_tx_csv, &holder_tx.delayed_payment_key); @@ -4093,7 +4091,7 @@ impl ChannelMonitorImpl { per_commitment_point: broadcasted_holder_revokable_script.1, to_self_delay: self.on_holder_tx_csv, output: outp.clone(), - revocation_pubkey: broadcasted_holder_revokable_script.2.clone(), + revocation_pubkey: broadcasted_holder_revokable_script.2, channel_keys_id: self.channel_keys_id, channel_value_satoshis: self.channel_value_satoshis, })); @@ -4506,8 +4504,8 @@ mod tests { use crate::chain::transaction::OutPoint; use crate::sign::InMemorySigner; use crate::ln::{PaymentPreimage, PaymentHash}; - use crate::ln::chan_utils; - use crate::ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters}; + use crate::ln::channel_keys::{DelayedPaymentBasepoint, DelayedPaymentKey, HtlcBasepoint, RevocationBasepoint, RevocationKey}; + use crate::ln::chan_utils::{self,HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters}; use crate::ln::channelmanager::{PaymentSendFailure, PaymentId, RecipientOnionFields}; use crate::ln::functional_test_utils::*; use crate::ln::script::ShutdownScript; @@ -4674,10 +4672,10 @@ mod tests { let counterparty_pubkeys = ChannelPublicKeys { funding_pubkey: PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[44; 32]).unwrap()), - revocation_basepoint: PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[45; 32]).unwrap()), + revocation_basepoint: RevocationBasepoint::from(PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[45; 32]).unwrap())), payment_point: PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[46; 32]).unwrap()), - delayed_payment_basepoint: PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[47; 32]).unwrap()), - htlc_basepoint: PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[48; 32]).unwrap()) + delayed_payment_basepoint: DelayedPaymentBasepoint::from(PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[47; 32]).unwrap())), + htlc_basepoint: HtlcBasepoint::from(PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[48; 32]).unwrap())) }; let funding_outpoint = OutPoint { txid: Txid::all_zeros(), index: u16::max_value() }; let channel_parameters = ChannelTransactionParameters { @@ -4767,6 +4765,7 @@ mod tests { let privkey = SecretKey::from_slice(&>::from_hex("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap(); let pubkey = PublicKey::from_secret_key(&secp_ctx, &privkey); + use crate::ln::channel_keys::{HtlcKey, HtlcBasepoint}; macro_rules! sign_input { ($sighash_parts: expr, $idx: expr, $amount: expr, $weight: expr, $sum_actual_sigs: expr, $opt_anchors: expr) => { let htlc = HTLCOutputInCommitment { @@ -4776,7 +4775,7 @@ mod tests { payment_hash: PaymentHash([1; 32]), transaction_output_index: Some($idx as u32), }; - let redeem_script = if *$weight == WEIGHT_REVOKED_OUTPUT { chan_utils::get_revokeable_redeemscript(&pubkey, 256, &pubkey) } else { chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, $opt_anchors, &pubkey, &pubkey, &pubkey) }; + let redeem_script = if *$weight == WEIGHT_REVOKED_OUTPUT { chan_utils::get_revokeable_redeemscript(&RevocationKey::from_basepoint(&secp_ctx, &RevocationBasepoint::from(pubkey), &pubkey), 256, &DelayedPaymentKey::from_basepoint(&secp_ctx, &DelayedPaymentBasepoint::from(pubkey), &pubkey)) } else { chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, $opt_anchors, &HtlcKey::from_basepoint(&secp_ctx, &HtlcBasepoint::from(pubkey), &pubkey), &HtlcKey::from_basepoint(&secp_ctx, &HtlcBasepoint::from(pubkey), &pubkey), &RevocationKey::from_basepoint(&secp_ctx, &RevocationBasepoint::from(pubkey), &pubkey)) }; let sighash = hash_to_message!(&$sighash_parts.segwit_signature_hash($idx, &redeem_script, $amount, EcdsaSighashType::All).unwrap()[..]); let sig = secp_ctx.sign_ecdsa(&sighash, &privkey); let mut ser_sig = sig.serialize_der().to_vec(); diff --git a/lightning/src/chain/package.rs b/lightning/src/chain/package.rs index 5fb893d8adf..0759e80eb63 100644 --- a/lightning/src/chain/package.rs +++ b/lightning/src/chain/package.rs @@ -23,9 +23,9 @@ use bitcoin::secp256k1::{SecretKey,PublicKey}; use bitcoin::sighash::EcdsaSighashType; use crate::ln::PaymentPreimage; -use crate::ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment}; -use crate::ln::chan_utils; +use crate::ln::chan_utils::{self, TxCreationKeys, HTLCOutputInCommitment}; use crate::ln::features::ChannelTypeFeatures; +use crate::ln::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint}; use crate::ln::msgs::DecodeError; use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT, compute_feerate_sat_per_1000_weight, FEERATE_FLOOR_SATS_PER_KW}; use crate::sign::WriteableEcdsaChannelSigner; @@ -115,8 +115,8 @@ const HIGH_FREQUENCY_BUMP_INTERVAL: u32 = 1; #[derive(Clone, PartialEq, Eq)] pub(crate) struct RevokedOutput { per_commitment_point: PublicKey, - counterparty_delayed_payment_base_key: PublicKey, - counterparty_htlc_base_key: PublicKey, + counterparty_delayed_payment_base_key: DelayedPaymentBasepoint, + counterparty_htlc_base_key: HtlcBasepoint, per_commitment_key: SecretKey, weight: u64, amount: u64, @@ -125,7 +125,7 @@ pub(crate) struct RevokedOutput { } impl RevokedOutput { - pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, per_commitment_key: SecretKey, amount: u64, on_counterparty_tx_csv: u16, is_counterparty_balance_on_anchors: bool) -> Self { + pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: DelayedPaymentBasepoint, counterparty_htlc_base_key: HtlcBasepoint, per_commitment_key: SecretKey, amount: u64, on_counterparty_tx_csv: u16, is_counterparty_balance_on_anchors: bool) -> Self { RevokedOutput { per_commitment_point, counterparty_delayed_payment_base_key, @@ -161,8 +161,8 @@ impl_writeable_tlv_based!(RevokedOutput, { #[derive(Clone, PartialEq, Eq)] pub(crate) struct RevokedHTLCOutput { per_commitment_point: PublicKey, - counterparty_delayed_payment_base_key: PublicKey, - counterparty_htlc_base_key: PublicKey, + counterparty_delayed_payment_base_key: DelayedPaymentBasepoint, + counterparty_htlc_base_key: HtlcBasepoint, per_commitment_key: SecretKey, weight: u64, amount: u64, @@ -170,7 +170,7 @@ pub(crate) struct RevokedHTLCOutput { } impl RevokedHTLCOutput { - pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, per_commitment_key: SecretKey, amount: u64, htlc: HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures) -> Self { + pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: DelayedPaymentBasepoint, counterparty_htlc_base_key: HtlcBasepoint, per_commitment_key: SecretKey, amount: u64, htlc: HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures) -> Self { let weight = if htlc.offered { weight_revoked_offered_htlc(channel_type_features) } else { weight_revoked_received_htlc(channel_type_features) }; RevokedHTLCOutput { per_commitment_point, @@ -205,15 +205,15 @@ impl_writeable_tlv_based!(RevokedHTLCOutput, { #[derive(Clone, PartialEq, Eq)] pub(crate) struct CounterpartyOfferedHTLCOutput { per_commitment_point: PublicKey, - counterparty_delayed_payment_base_key: PublicKey, - counterparty_htlc_base_key: PublicKey, + counterparty_delayed_payment_base_key: DelayedPaymentBasepoint, + counterparty_htlc_base_key: HtlcBasepoint, preimage: PaymentPreimage, htlc: HTLCOutputInCommitment, channel_type_features: ChannelTypeFeatures, } impl CounterpartyOfferedHTLCOutput { - pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, preimage: PaymentPreimage, htlc: HTLCOutputInCommitment, channel_type_features: ChannelTypeFeatures) -> Self { + pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: DelayedPaymentBasepoint, counterparty_htlc_base_key: HtlcBasepoint, preimage: PaymentPreimage, htlc: HTLCOutputInCommitment, channel_type_features: ChannelTypeFeatures) -> Self { CounterpartyOfferedHTLCOutput { per_commitment_point, counterparty_delayed_payment_base_key, @@ -283,14 +283,14 @@ impl Readable for CounterpartyOfferedHTLCOutput { #[derive(Clone, PartialEq, Eq)] pub(crate) struct CounterpartyReceivedHTLCOutput { per_commitment_point: PublicKey, - counterparty_delayed_payment_base_key: PublicKey, - counterparty_htlc_base_key: PublicKey, + counterparty_delayed_payment_base_key: DelayedPaymentBasepoint, + counterparty_htlc_base_key: HtlcBasepoint, htlc: HTLCOutputInCommitment, channel_type_features: ChannelTypeFeatures, } impl CounterpartyReceivedHTLCOutput { - pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, htlc: HTLCOutputInCommitment, channel_type_features: ChannelTypeFeatures) -> Self { + pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: DelayedPaymentBasepoint, counterparty_htlc_base_key: HtlcBasepoint, htlc: HTLCOutputInCommitment, channel_type_features: ChannelTypeFeatures) -> Self { CounterpartyReceivedHTLCOutput { per_commitment_point, counterparty_delayed_payment_base_key, @@ -600,7 +600,7 @@ impl PackageSolvingData { let mut ser_sig = sig.serialize_der().to_vec(); ser_sig.push(EcdsaSighashType::All as u8); bumped_tx.input[i].witness.push(ser_sig); - bumped_tx.input[i].witness.push(chan_keys.revocation_key.clone().serialize().to_vec()); + bumped_tx.input[i].witness.push(chan_keys.revocation_key.to_public_key().serialize().to_vec()); bumped_tx.input[i].witness.push(witness_script.clone().into_bytes()); } else { return false; } }, @@ -1191,6 +1191,7 @@ mod tests { use crate::chain::Txid; use crate::ln::chan_utils::HTLCOutputInCommitment; use crate::ln::{PaymentPreimage, PaymentHash}; + use crate::ln::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint}; use bitcoin::blockdata::constants::WITNESS_SCALE_FACTOR; use bitcoin::blockdata::script::ScriptBuf; @@ -1209,7 +1210,7 @@ mod tests { { let dumb_scalar = SecretKey::from_slice(&>::from_hex("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap(); let dumb_point = PublicKey::from_secret_key(&$secp_ctx, &dumb_scalar); - PackageSolvingData::RevokedOutput(RevokedOutput::build(dumb_point, dumb_point, dumb_point, dumb_scalar, 0, 0, $is_counterparty_balance_on_anchors)) + PackageSolvingData::RevokedOutput(RevokedOutput::build(dumb_point, DelayedPaymentBasepoint::from(dumb_point), HtlcBasepoint::from(dumb_point), dumb_scalar, 0, 0, $is_counterparty_balance_on_anchors)) } } } @@ -1221,7 +1222,7 @@ mod tests { let dumb_point = PublicKey::from_secret_key(&$secp_ctx, &dumb_scalar); let hash = PaymentHash([1; 32]); let htlc = HTLCOutputInCommitment { offered: true, amount_msat: $amt, cltv_expiry: 0, payment_hash: hash, transaction_output_index: None }; - PackageSolvingData::CounterpartyReceivedHTLCOutput(CounterpartyReceivedHTLCOutput::build(dumb_point, dumb_point, dumb_point, htlc, $opt_anchors)) + PackageSolvingData::CounterpartyReceivedHTLCOutput(CounterpartyReceivedHTLCOutput::build(dumb_point, DelayedPaymentBasepoint::from(dumb_point), HtlcBasepoint::from(dumb_point), htlc, $opt_anchors)) } } } @@ -1234,7 +1235,7 @@ mod tests { let hash = PaymentHash([1; 32]); let preimage = PaymentPreimage([2;32]); let htlc = HTLCOutputInCommitment { offered: false, amount_msat: $amt, cltv_expiry: 1000, payment_hash: hash, transaction_output_index: None }; - PackageSolvingData::CounterpartyOfferedHTLCOutput(CounterpartyOfferedHTLCOutput::build(dumb_point, dumb_point, dumb_point, preimage, htlc, $opt_anchors)) + PackageSolvingData::CounterpartyOfferedHTLCOutput(CounterpartyOfferedHTLCOutput::build(dumb_point, DelayedPaymentBasepoint::from(dumb_point), HtlcBasepoint::from(dumb_point), preimage, htlc, $opt_anchors)) } } } diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 8dc31115f96..3552748b31c 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -7,7 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -//! Various utilities for building scripts and deriving keys related to channels. These are +//! Various utilities for building scripts related to channels. These are //! largely of interest for those implementing the traits on [`crate::sign`] by hand. use bitcoin::blockdata::script::{Script, ScriptBuf, Builder}; @@ -46,6 +46,7 @@ use core::ops::Deref; use crate::chain; use crate::ln::features::ChannelTypeFeatures; use crate::util::crypto::{sign, sign_with_aux_rand}; +use super::channel_keys::{DelayedPaymentBasepoint, DelayedPaymentKey, HtlcKey, HtlcBasepoint, RevocationKey, RevocationBasepoint}; /// Maximum number of one-way in-flight HTLC (protocol-level value). pub const MAX_HTLCS: u16 = 483; @@ -354,21 +355,6 @@ pub fn derive_private_key(secp_ctx: &Secp256k1, per_co .expect("Addition only fails if the tweak is the inverse of the key. This is not possible when the tweak contains the hash of the key.") } -/// Derives a per-commitment-transaction public key (eg an htlc key or a delayed_payment key) -/// from the base point and the per_commitment_key. This is the public equivalent of -/// derive_private_key - using only public keys to derive a public key instead of private keys. -pub fn derive_public_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, base_point: &PublicKey) -> PublicKey { - let mut sha = Sha256::engine(); - sha.input(&per_commitment_point.serialize()); - sha.input(&base_point.serialize()); - let res = Sha256::from_engine(sha).to_byte_array(); - - let hashkey = PublicKey::from_secret_key(&secp_ctx, - &SecretKey::from_slice(&res).expect("Hashes should always be valid keys unless SHA-256 is broken")); - base_point.combine(&hashkey) - .expect("Addition only fails if the tweak is the inverse of the key. This is not possible when the tweak contains the hash of the key.") -} - /// Derives a per-commitment-transaction revocation key from its constituent parts. /// /// Only the cheating participant owns a valid witness to propagate a revoked @@ -404,43 +390,6 @@ pub fn derive_private_revocation_key(secp_ctx: &Secp256k1 .expect("Addition only fails if the tweak is the inverse of the key. This is not possible when the tweak commits to the key.") } -/// Derives a per-commitment-transaction revocation public key from its constituent parts. This is -/// the public equivalend of derive_private_revocation_key - using only public keys to derive a -/// public key instead of private keys. -/// -/// Only the cheating participant owns a valid witness to propagate a revoked -/// commitment transaction, thus per_commitment_point always come from cheater -/// and revocation_base_point always come from punisher, which is the broadcaster -/// of the transaction spending with this key knowledge. -/// -/// Note that this is infallible iff we trust that at least one of the two input keys are randomly -/// generated (ie our own). -pub fn derive_public_revocation_key(secp_ctx: &Secp256k1, - per_commitment_point: &PublicKey, countersignatory_revocation_base_point: &PublicKey) --> PublicKey { - let rev_append_commit_hash_key = { - let mut sha = Sha256::engine(); - sha.input(&countersignatory_revocation_base_point.serialize()); - sha.input(&per_commitment_point.serialize()); - - Sha256::from_engine(sha).to_byte_array() - }; - let commit_append_rev_hash_key = { - let mut sha = Sha256::engine(); - sha.input(&per_commitment_point.serialize()); - sha.input(&countersignatory_revocation_base_point.serialize()); - - Sha256::from_engine(sha).to_byte_array() - }; - - let countersignatory_contrib = countersignatory_revocation_base_point.clone().mul_tweak(&secp_ctx, &Scalar::from_be_bytes(rev_append_commit_hash_key).unwrap()) - .expect("Multiplying a valid public key by a hash is expected to never fail per secp256k1 docs"); - let broadcaster_contrib = per_commitment_point.clone().mul_tweak(&secp_ctx, &Scalar::from_be_bytes(commit_append_rev_hash_key).unwrap()) - .expect("Multiplying a valid public key by a hash is expected to never fail per secp256k1 docs"); - countersignatory_contrib.combine(&broadcaster_contrib) - .expect("Addition only fails if the tweak is the inverse of the key. This is not possible when the tweak commits to the key.") -} - /// The set of public keys which are used in the creation of one commitment transaction. /// These are derived from the channel base keys and per-commitment data. /// @@ -459,13 +408,13 @@ pub struct TxCreationKeys { /// The revocation key which is used to allow the broadcaster of the commitment /// transaction to provide their counterparty the ability to punish them if they broadcast /// an old state. - pub revocation_key: PublicKey, + pub revocation_key: RevocationKey, /// Broadcaster's HTLC Key - pub broadcaster_htlc_key: PublicKey, + pub broadcaster_htlc_key: HtlcKey, /// Countersignatory's HTLC Key - pub countersignatory_htlc_key: PublicKey, + pub countersignatory_htlc_key: HtlcKey, /// Broadcaster's Payment Key (which isn't allowed to be spent from for some delay) - pub broadcaster_delayed_payment_key: PublicKey, + pub broadcaster_delayed_payment_key: DelayedPaymentKey, } impl_writeable_tlv_based!(TxCreationKeys, { @@ -486,7 +435,7 @@ pub struct ChannelPublicKeys { /// revocation keys. This is combined with the per-commitment-secret generated by the /// counterparty to create a secret which the counterparty can reveal to revoke previous /// states. - pub revocation_basepoint: PublicKey, + pub revocation_basepoint: RevocationBasepoint, /// The public key on which the non-broadcaster (ie the countersignatory) receives an immediately /// spendable primary channel balance on the broadcaster's commitment transaction. This key is /// static across every commitment transaction. @@ -494,10 +443,10 @@ pub struct ChannelPublicKeys { /// The base point which is used (with derive_public_key) to derive a per-commitment payment /// public key which receives non-HTLC-encumbered funds which are only available for spending /// after some delay (or can be claimed via the revocation path). - pub delayed_payment_basepoint: PublicKey, + pub delayed_payment_basepoint: DelayedPaymentBasepoint, /// The base point which is used (with derive_public_key) to derive a per-commitment public key /// which is used to encumber HTLC-in-flight outputs. - pub htlc_basepoint: PublicKey, + pub htlc_basepoint: HtlcBasepoint, } impl_writeable_tlv_based!(ChannelPublicKeys, { @@ -511,13 +460,13 @@ impl_writeable_tlv_based!(ChannelPublicKeys, { impl TxCreationKeys { /// Create per-state keys from channel base points and the per-commitment point. /// Key set is asymmetric and can't be used as part of counter-signatory set of transactions. - pub fn derive_new(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, broadcaster_delayed_payment_base: &PublicKey, broadcaster_htlc_base: &PublicKey, countersignatory_revocation_base: &PublicKey, countersignatory_htlc_base: &PublicKey) -> TxCreationKeys { + pub fn derive_new(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, broadcaster_delayed_payment_base: &DelayedPaymentBasepoint, broadcaster_htlc_base: &HtlcBasepoint, countersignatory_revocation_base: &RevocationBasepoint, countersignatory_htlc_base: &HtlcBasepoint) -> TxCreationKeys { TxCreationKeys { per_commitment_point: per_commitment_point.clone(), - revocation_key: derive_public_revocation_key(&secp_ctx, &per_commitment_point, &countersignatory_revocation_base), - broadcaster_htlc_key: derive_public_key(&secp_ctx, &per_commitment_point, &broadcaster_htlc_base), - countersignatory_htlc_key: derive_public_key(&secp_ctx, &per_commitment_point, &countersignatory_htlc_base), - broadcaster_delayed_payment_key: derive_public_key(&secp_ctx, &per_commitment_point, &broadcaster_delayed_payment_base), + revocation_key: RevocationKey::from_basepoint(&secp_ctx, &countersignatory_revocation_base, &per_commitment_point), + broadcaster_htlc_key: HtlcKey::from_basepoint(&secp_ctx, &broadcaster_htlc_base, &per_commitment_point), + countersignatory_htlc_key: HtlcKey::from_basepoint(&secp_ctx, &countersignatory_htlc_base, &per_commitment_point), + broadcaster_delayed_payment_key: DelayedPaymentKey::from_basepoint(&secp_ctx, &broadcaster_delayed_payment_base, &per_commitment_point), } } @@ -543,14 +492,14 @@ pub const REVOKEABLE_REDEEMSCRIPT_MAX_LENGTH: usize = 6 + 3 + 34*2; /// A script either spendable by the revocation /// key or the broadcaster_delayed_payment_key and satisfying the relative-locktime OP_CSV constrain. /// Encumbering a `to_holder` output on a commitment transaction or 2nd-stage HTLC transactions. -pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, contest_delay: u16, broadcaster_delayed_payment_key: &PublicKey) -> ScriptBuf { +pub fn get_revokeable_redeemscript(revocation_key: &RevocationKey, contest_delay: u16, broadcaster_delayed_payment_key: &DelayedPaymentKey) -> ScriptBuf { let res = Builder::new().push_opcode(opcodes::all::OP_IF) - .push_slice(&revocation_key.serialize()) + .push_slice(&revocation_key.to_public_key().serialize()) .push_opcode(opcodes::all::OP_ELSE) .push_int(contest_delay as i64) .push_opcode(opcodes::all::OP_CSV) .push_opcode(opcodes::all::OP_DROP) - .push_slice(&broadcaster_delayed_payment_key.serialize()) + .push_slice(&broadcaster_delayed_payment_key.to_public_key().serialize()) .push_opcode(opcodes::all::OP_ENDIF) .push_opcode(opcodes::all::OP_CHECKSIG) .into_script(); @@ -598,17 +547,17 @@ impl_writeable_tlv_based!(HTLCOutputInCommitment, { }); #[inline] -pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures, broadcaster_htlc_key: &PublicKey, countersignatory_htlc_key: &PublicKey, revocation_key: &PublicKey) -> ScriptBuf { +pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures, broadcaster_htlc_key: &HtlcKey, countersignatory_htlc_key: &HtlcKey, revocation_key: &RevocationKey) -> ScriptBuf { let payment_hash160 = Ripemd160::hash(&htlc.payment_hash.0[..]).to_byte_array(); if htlc.offered { let mut bldr = Builder::new().push_opcode(opcodes::all::OP_DUP) .push_opcode(opcodes::all::OP_HASH160) - .push_slice(PubkeyHash::hash(&revocation_key.serialize())) + .push_slice(PubkeyHash::hash(&revocation_key.to_public_key().serialize())) .push_opcode(opcodes::all::OP_EQUAL) .push_opcode(opcodes::all::OP_IF) .push_opcode(opcodes::all::OP_CHECKSIG) .push_opcode(opcodes::all::OP_ELSE) - .push_slice(countersignatory_htlc_key.serialize()) + .push_slice(&countersignatory_htlc_key.to_public_key().serialize()) .push_opcode(opcodes::all::OP_SWAP) .push_opcode(opcodes::all::OP_SIZE) .push_int(32) @@ -617,7 +566,7 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit .push_opcode(opcodes::all::OP_DROP) .push_int(2) .push_opcode(opcodes::all::OP_SWAP) - .push_slice(broadcaster_htlc_key.serialize()) + .push_slice(&broadcaster_htlc_key.to_public_key().serialize()) .push_int(2) .push_opcode(opcodes::all::OP_CHECKMULTISIG) .push_opcode(opcodes::all::OP_ELSE) @@ -636,12 +585,12 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit } else { let mut bldr = Builder::new().push_opcode(opcodes::all::OP_DUP) .push_opcode(opcodes::all::OP_HASH160) - .push_slice(PubkeyHash::hash(&revocation_key.serialize())) + .push_slice(&PubkeyHash::hash(&revocation_key.to_public_key().serialize())) .push_opcode(opcodes::all::OP_EQUAL) .push_opcode(opcodes::all::OP_IF) .push_opcode(opcodes::all::OP_CHECKSIG) .push_opcode(opcodes::all::OP_ELSE) - .push_slice(countersignatory_htlc_key.serialize()) + .push_slice(&countersignatory_htlc_key.to_public_key().serialize()) .push_opcode(opcodes::all::OP_SWAP) .push_opcode(opcodes::all::OP_SIZE) .push_int(32) @@ -652,7 +601,7 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_int(2) .push_opcode(opcodes::all::OP_SWAP) - .push_slice(broadcaster_htlc_key.serialize()) + .push_slice(&broadcaster_htlc_key.to_public_key().serialize()) .push_int(2) .push_opcode(opcodes::all::OP_CHECKMULTISIG) .push_opcode(opcodes::all::OP_ELSE) @@ -706,7 +655,7 @@ pub(crate) fn make_funding_redeemscript_from_slices(broadcaster_funding_key: &[u /// /// Panics if htlc.transaction_output_index.is_none() (as such HTLCs do not appear in the /// commitment transaction). -pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction { +pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures, broadcaster_delayed_payment_key: &DelayedPaymentKey, revocation_key: &RevocationKey) -> Transaction { let mut txins: Vec = Vec::new(); txins.push(build_htlc_input(commitment_txid, htlc, channel_type_features)); @@ -737,7 +686,7 @@ pub(crate) fn build_htlc_input(commitment_txid: &Txid, htlc: &HTLCOutputInCommit } pub(crate) fn build_htlc_output( - feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey + feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures, broadcaster_delayed_payment_key: &DelayedPaymentKey, revocation_key: &RevocationKey ) -> TxOut { let weight = if htlc.offered { htlc_timeout_tx_weight(channel_type_features) @@ -1082,17 +1031,17 @@ impl HolderCommitmentTransaction { let keys = TxCreationKeys { per_commitment_point: dummy_key.clone(), - revocation_key: dummy_key.clone(), - broadcaster_htlc_key: dummy_key.clone(), - countersignatory_htlc_key: dummy_key.clone(), - broadcaster_delayed_payment_key: dummy_key.clone(), + revocation_key: RevocationKey::from_basepoint(&secp_ctx, &RevocationBasepoint::from(dummy_key), &dummy_key), + broadcaster_htlc_key: HtlcKey::from_basepoint(&secp_ctx, &HtlcBasepoint::from(dummy_key), &dummy_key), + countersignatory_htlc_key: HtlcKey::from_basepoint(&secp_ctx, &HtlcBasepoint::from(dummy_key), &dummy_key), + broadcaster_delayed_payment_key: DelayedPaymentKey::from_basepoint(&secp_ctx, &DelayedPaymentBasepoint::from(dummy_key), &dummy_key), }; let channel_pubkeys = ChannelPublicKeys { funding_pubkey: dummy_key.clone(), - revocation_basepoint: dummy_key.clone(), + revocation_basepoint: RevocationBasepoint::from(dummy_key), payment_point: dummy_key.clone(), - delayed_payment_basepoint: dummy_key.clone(), - htlc_basepoint: dummy_key.clone() + delayed_payment_basepoint: DelayedPaymentBasepoint::from(dummy_key.clone()), + htlc_basepoint: HtlcBasepoint::from(dummy_key.clone()) }; let channel_parameters = ChannelTransactionParameters { holder_pubkeys: channel_pubkeys.clone(), diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 6803b11284b..4773f4242e0 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -55,6 +55,8 @@ use core::ops::Deref; use crate::sync::Mutex; use crate::sign::type_resolver::ChannelSignerType; +use super::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint, RevocationBasepoint}; + #[cfg(test)] pub struct ChannelValueStat { pub value_to_self_msat: u64, @@ -3164,9 +3166,9 @@ impl Channel where let htlc_sighashtype = if self.context.channel_type.supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]); log_trace!(logger, "Checking HTLC tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}.", - log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(keys.countersignatory_htlc_key.serialize()), + log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(keys.countersignatory_htlc_key.to_public_key().serialize()), encode::serialize_hex(&htlc_tx), log_bytes!(htlc_sighash[..]), encode::serialize_hex(&htlc_redeemscript), &self.context.channel_id()); - if let Err(_) = self.context.secp_ctx.verify_ecdsa(&htlc_sighash, &msg.htlc_signatures[idx], &keys.countersignatory_htlc_key) { + if let Err(_) = self.context.secp_ctx.verify_ecdsa(&htlc_sighash, &msg.htlc_signatures[idx], &keys.countersignatory_htlc_key.to_public_key()) { return Err(ChannelError::Close("Invalid HTLC tx signature from peer".to_owned())); } if !separate_nondust_htlc_sources { @@ -5696,7 +5698,7 @@ impl Channel where log_trace!(logger, "Signed remote HTLC tx {} with redeemscript {} with pubkey {} -> {} in channel {}", encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.context.get_holder_selected_contest_delay(), htlc, &self.context.channel_type, &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)), encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, &self.context.channel_type, &counterparty_keys)), - log_bytes!(counterparty_keys.broadcaster_htlc_key.serialize()), + log_bytes!(counterparty_keys.broadcaster_htlc_key.to_public_key().serialize()), log_bytes!(htlc_sig.serialize_compact()[..]), &self.context.channel_id()); } } @@ -6232,10 +6234,10 @@ impl OutboundV1Channel where SP::Target: SignerProvider { to_self_delay: self.context.get_holder_selected_contest_delay(), max_accepted_htlcs: self.context.holder_max_accepted_htlcs, funding_pubkey: keys.funding_pubkey, - revocation_basepoint: keys.revocation_basepoint, + revocation_basepoint: keys.revocation_basepoint.to_public_key(), payment_point: keys.payment_point, - delayed_payment_basepoint: keys.delayed_payment_basepoint, - htlc_basepoint: keys.htlc_basepoint, + delayed_payment_basepoint: keys.delayed_payment_basepoint.to_public_key(), + htlc_basepoint: keys.htlc_basepoint.to_public_key(), first_per_commitment_point, channel_flags: if self.context.config.announced_channel {1} else {0}, shutdown_scriptpubkey: Some(match &self.context.shutdown_scriptpubkey { @@ -6357,10 +6359,10 @@ impl OutboundV1Channel where SP::Target: SignerProvider { let counterparty_pubkeys = ChannelPublicKeys { funding_pubkey: msg.funding_pubkey, - revocation_basepoint: msg.revocation_basepoint, + revocation_basepoint: RevocationBasepoint::from(msg.revocation_basepoint), payment_point: msg.payment_point, - delayed_payment_basepoint: msg.delayed_payment_basepoint, - htlc_basepoint: msg.htlc_basepoint + delayed_payment_basepoint: DelayedPaymentBasepoint::from(msg.delayed_payment_basepoint), + htlc_basepoint: HtlcBasepoint::from(msg.htlc_basepoint) }; self.context.channel_transaction_parameters.counterparty_parameters = Some(CounterpartyChannelTransactionParameters { @@ -6433,10 +6435,10 @@ impl InboundV1Channel where SP::Target: SignerProvider { let pubkeys = holder_signer.pubkeys().clone(); let counterparty_pubkeys = ChannelPublicKeys { funding_pubkey: msg.funding_pubkey, - revocation_basepoint: msg.revocation_basepoint, + revocation_basepoint: RevocationBasepoint::from(msg.revocation_basepoint), payment_point: msg.payment_point, - delayed_payment_basepoint: msg.delayed_payment_basepoint, - htlc_basepoint: msg.htlc_basepoint + delayed_payment_basepoint: DelayedPaymentBasepoint::from(msg.delayed_payment_basepoint), + htlc_basepoint: HtlcBasepoint::from(msg.htlc_basepoint) }; if config.channel_handshake_config.our_to_self_delay < BREAKDOWN_TIMEOUT { @@ -6766,10 +6768,10 @@ impl InboundV1Channel where SP::Target: SignerProvider { to_self_delay: self.context.get_holder_selected_contest_delay(), max_accepted_htlcs: self.context.holder_max_accepted_htlcs, funding_pubkey: keys.funding_pubkey, - revocation_basepoint: keys.revocation_basepoint, + revocation_basepoint: keys.revocation_basepoint.to_public_key(), payment_point: keys.payment_point, - delayed_payment_basepoint: keys.delayed_payment_basepoint, - htlc_basepoint: keys.htlc_basepoint, + delayed_payment_basepoint: keys.delayed_payment_basepoint.to_public_key(), + htlc_basepoint: keys.htlc_basepoint.to_public_key(), first_per_commitment_point, shutdown_scriptpubkey: Some(match &self.context.shutdown_scriptpubkey { Some(script) => script.clone().into_inner(), @@ -7796,15 +7798,15 @@ mod tests { use bitcoin::blockdata::opcodes; use bitcoin::network::constants::Network; use crate::ln::PaymentHash; - use crate::ln::channelmanager::{self, HTLCSource, PaymentId}; + use crate::ln::channel_keys::{RevocationKey, RevocationBasepoint}; +use crate::ln::channelmanager::{self, HTLCSource, PaymentId}; use crate::ln::channel::InitFeatures; use crate::ln::channel::{ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, commit_tx_fee_msat}; use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS}; use crate::ln::features::ChannelTypeFeatures; use crate::ln::msgs::{ChannelUpdate, DecodeError, UnsignedChannelUpdate, MAX_VALUE_MSAT}; use crate::ln::script::ShutdownScript; - use crate::ln::chan_utils; - use crate::ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight}; + use crate::ln::chan_utils::{self, htlc_success_tx_weight, htlc_timeout_tx_weight}; use crate::chain::BestBlock; use crate::chain::chaininterface::{FeeEstimator, LowerBoundedFeeEstimator, ConfirmationTarget}; use crate::sign::{ChannelSigner, InMemorySigner, EntropySource, SignerProvider}; @@ -8334,6 +8336,7 @@ mod tests { use crate::sign::{ChannelDerivationParameters, HTLCDescriptor, EcdsaChannelSigner}; use crate::ln::PaymentPreimage; use crate::ln::channel::{HTLCOutputInCommitment ,TxCreationKeys}; + use crate::ln::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint}; use crate::ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters}; use crate::util::logger::Logger; use crate::sync::Arc; @@ -8375,10 +8378,10 @@ mod tests { let counterparty_pubkeys = ChannelPublicKeys { funding_pubkey: public_from_secret_hex(&secp_ctx, "1552dfba4f6cf29a62a0af13c8d6981d36d0ef8d61ba10fb0fe90da7634d7e13"), - revocation_basepoint: PublicKey::from_slice(&>::from_hex("02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27").unwrap()[..]).unwrap(), + revocation_basepoint: RevocationBasepoint::from(PublicKey::from_slice(&>::from_hex("02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27").unwrap()[..]).unwrap()), payment_point: public_from_secret_hex(&secp_ctx, "4444444444444444444444444444444444444444444444444444444444444444"), - delayed_payment_basepoint: public_from_secret_hex(&secp_ctx, "1552dfba4f6cf29a62a0af13c8d6981d36d0ef8d61ba10fb0fe90da7634d7e13"), - htlc_basepoint: public_from_secret_hex(&secp_ctx, "4444444444444444444444444444444444444444444444444444444444444444") + delayed_payment_basepoint: DelayedPaymentBasepoint::from(public_from_secret_hex(&secp_ctx, "1552dfba4f6cf29a62a0af13c8d6981d36d0ef8d61ba10fb0fe90da7634d7e13")), + htlc_basepoint: HtlcBasepoint::from(public_from_secret_hex(&secp_ctx, "4444444444444444444444444444444444444444444444444444444444444444")) }; chan.context.channel_transaction_parameters.counterparty_parameters = Some( CounterpartyChannelTransactionParameters { @@ -8394,7 +8397,7 @@ mod tests { assert_eq!(counterparty_pubkeys.funding_pubkey.serialize()[..], >::from_hex("030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1").unwrap()[..]); - assert_eq!(counterparty_pubkeys.htlc_basepoint.serialize()[..], + assert_eq!(counterparty_pubkeys.htlc_basepoint.to_public_key().serialize()[..], >::from_hex("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]); // We can't just use build_holder_transaction_keys here as the per_commitment_secret is not @@ -8479,7 +8482,7 @@ mod tests { let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, $opt_anchors, &keys); let htlc_sighashtype = if $opt_anchors.supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; let htlc_sighash = Message::from_slice(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]).unwrap(); - assert!(secp_ctx.verify_ecdsa(&htlc_sighash, &remote_signature, &keys.countersignatory_htlc_key).is_ok(), "verify counterparty htlc sig"); + assert!(secp_ctx.verify_ecdsa(&htlc_sighash, &remote_signature, &keys.countersignatory_htlc_key.to_public_key()).is_ok(), "verify counterparty htlc sig"); let mut preimage: Option = None; if !htlc.offered { @@ -9073,7 +9076,7 @@ mod tests { assert_eq!(chan_utils::build_commitment_secret(&seed, 1), >::from_hex("915c75942a26bb3a433a8ce2cb0427c29ec6c1775cfc78328b57f6ba7bfeaa9c").unwrap()[..]); } - + #[test] fn test_key_derivation() { // Test vectors from BOLT 3 Appendix E: @@ -9088,13 +9091,10 @@ mod tests { let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret); assert_eq!(per_commitment_point.serialize()[..], >::from_hex("025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486").unwrap()[..]); - assert_eq!(chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &base_point).serialize()[..], - >::from_hex("0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5").unwrap()[..]); - assert_eq!(chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &base_secret), SecretKey::from_slice(&>::from_hex("cbced912d3b21bf196a766651e436aff192362621ce317704ea2f75d87e7be0f").unwrap()[..]).unwrap()); - assert_eq!(chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &base_point).serialize()[..], + assert_eq!(RevocationKey::from_basepoint(&secp_ctx, &RevocationBasepoint::from(base_point), &per_commitment_point).to_public_key().serialize()[..], >::from_hex("02916e326636d19c33f13e8c0c3a03dd157f332f3e99c317c141dd865eb01f8ff0").unwrap()[..]); assert_eq!(chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_secret, &base_secret), diff --git a/lightning/src/ln/channel_keys.rs b/lightning/src/ln/channel_keys.rs new file mode 100644 index 00000000000..f737dd23407 --- /dev/null +++ b/lightning/src/ln/channel_keys.rs @@ -0,0 +1,253 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +//! Keys used to generate commitment transactions. +//! See: + +use bitcoin::hashes::Hash; +use bitcoin::hashes::HashEngine; +use bitcoin::secp256k1::Scalar; +use bitcoin::secp256k1::SecretKey; +use bitcoin::secp256k1::Secp256k1; +use bitcoin::secp256k1; +use crate::ln::msgs::DecodeError; +use crate::util::ser::Readable; +use crate::io; +use crate::util::ser::Writer; +use crate::util::ser::Writeable; +use bitcoin::secp256k1::PublicKey; +use bitcoin::hashes::sha256::Hash as Sha256; + +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + }; +} +macro_rules! basepoint_impl { + ($BasepointT:ty) => { + impl $BasepointT { + /// Get inner Public Key + pub fn to_public_key(&self) -> PublicKey { + self.0 + } + } + + impl From for $BasepointT { + fn from(value: PublicKey) -> Self { + Self(value) + } + } + + } +} +macro_rules! key_impl { + ($BasepointT:ty, $KeyName:expr) => { + doc_comment! { + concat!("Generate ", $KeyName, " using per_commitment_point"), + pub fn from_basepoint( + secp_ctx: &Secp256k1, + basepoint: &$BasepointT, + per_commitment_point: &PublicKey, + ) -> Self { + Self(derive_public_key(secp_ctx, per_commitment_point, &basepoint.0)) + } + } + + doc_comment! { + concat!("Generate ", $KeyName, " from privkey"), + pub fn from_secret_key(secp_ctx: &Secp256k1, sk: &SecretKey) -> Self { + Self(PublicKey::from_secret_key(&secp_ctx, &sk)) + } + } + + /// Get inner Public Key + pub fn to_public_key(&self) -> PublicKey { + self.0 + } + } +} +macro_rules! key_read_write { + ($SelfT:ty) => { + impl Writeable for $SelfT { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.0.serialize().write(w) + } + } + + impl Readable for $SelfT { + fn read(r: &mut R) -> Result { + let key: PublicKey = Readable::read(r)?; + Ok(Self(key)) + } + } + } +} + + + +/// Master key used in conjunction with per_commitment_point to generate [`local_delayedpubkey`](https://github.com/lightning/bolts/blob/master/03-transactions.md#key-derivation) for the latest state of a channel. +/// A watcher can be given a [DelayedPaymentBasepoint] to generate per commitment [DelayedPaymentKey] to create justice transactions. +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] +pub struct DelayedPaymentBasepoint(pub PublicKey); +basepoint_impl!(DelayedPaymentBasepoint); +key_read_write!(DelayedPaymentBasepoint); + +/// [delayedpubkey](https://github.com/lightning/bolts/blob/master/03-transactions.md#localpubkey-local_htlcpubkey-remote_htlcpubkey-local_delayedpubkey-and-remote_delayedpubkey-derivation) +/// To allow a counterparty to contest a channel state published by a node, Lightning protocol sets delays for some of the outputs, before can be spend. +/// For example a commitment transaction has to_local output encumbered by a delay, negotiated at the channel establishment flow. +/// To spend from such output a node has to generate a script using, among others, a local delayed payment key. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct DelayedPaymentKey(pub PublicKey); + +impl DelayedPaymentKey { + key_impl!(DelayedPaymentBasepoint, "delayedpubkey"); +} +key_read_write!(DelayedPaymentKey); + +/// Master key used in conjunction with per_commitment_point to generate a [localpubkey](https://github.com/lightning/bolts/blob/master/03-transactions.md#key-derivation) for the latest state of a channel. +/// Also used to generate a commitment number in a commitment transaction or as a Payment Key for a remote node (not us) in an anchor output if `option_static_remotekey` is enabled. +/// Shared by both nodes in a channel establishment message flow. +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] +pub struct PaymentBasepoint(pub PublicKey); +basepoint_impl!(PaymentBasepoint); +key_read_write!(PaymentBasepoint); + + +/// [localpubkey](https://github.com/lightning/bolts/blob/master/03-transactions.md#localpubkey-local_htlcpubkey-remote_htlcpubkey-local_delayedpubkey-and-remote_delayedpubkey-derivation) is a child key of a payment basepoint, +/// that enables a secure hash-lock for off-chain payments without risk of funds getting stuck or stolen. A payment key is normally shared with a counterparty so that it can generate +/// a commitment transaction's to_remote ouput, which our node can claim in case the counterparty force closes the channel. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct PaymentKey(pub PublicKey); + +impl PaymentKey { + key_impl!(PaymentBasepoint, "localpubkey"); +} +key_read_write!(PaymentKey); + +/// Master key used in conjunction with per_commitment_point to generate [htlcpubkey](https://github.com/lightning/bolts/blob/master/03-transactions.md#key-derivation) for the latest state of a channel. +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] +pub struct HtlcBasepoint(pub PublicKey); +basepoint_impl!(HtlcBasepoint); +key_read_write!(HtlcBasepoint); + + +/// [htlcpubkey](https://github.com/lightning/bolts/blob/master/03-transactions.md#localpubkey-local_htlcpubkey-remote_htlcpubkey-local_delayedpubkey-and-remote_delayedpubkey-derivation) is a child key of an htlc basepoint, +/// that enables secure routing of payments in onion scheme without a risk of them getting stuck or diverted. It is used to claim the funds in successful or timed out htlc outputs. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct HtlcKey(pub PublicKey); + +impl HtlcKey { + key_impl!(HtlcBasepoint, "htlcpubkey"); +} +key_read_write!(HtlcKey); + +/// Derives a per-commitment-transaction public key (eg an htlc key or a delayed_payment key) +/// from the base point and the per_commitment_key. This is the public equivalent of +/// derive_private_key - using only public keys to derive a public key instead of private keys. +fn derive_public_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, base_point: &PublicKey) -> PublicKey { + let mut sha = Sha256::engine(); + sha.input(&per_commitment_point.serialize()); + sha.input(&base_point.serialize()); + let res = Sha256::from_engine(sha).to_byte_array(); + + + let hashkey = PublicKey::from_secret_key(&secp_ctx, + &SecretKey::from_slice(&res).expect("Hashes should always be valid keys unless SHA-256 is broken")); + base_point.combine(&hashkey) + .expect("Addition only fails if the tweak is the inverse of the key. This is not possible when the tweak contains the hash of the key.") +} + +/// Master key used in conjunction with per_commitment_point to generate [htlcpubkey](https://github.com/lightning/bolts/blob/master/03-transactions.md#key-derivation) for the latest state of a channel. +/// A watcher can be given a [RevocationBasepoint] to generate per commitment [RevocationKey] to create justice transactions. +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] +pub struct RevocationBasepoint(pub PublicKey); +basepoint_impl!(RevocationBasepoint); +key_read_write!(RevocationBasepoint); + + +/// [htlcpubkey](https://github.com/lightning/bolts/blob/master/03-transactions.md#localpubkey-local_htlcpubkey-remote_htlcpubkey-local_delayedpubkey-and-remote_delayedpubkey-derivation) is a child key of a revocation basepoint, +/// that enables a node to create a justice transaction punishing a counterparty for an attempt to steal funds. Used to in generation of commitment and htlc outputs. +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] +pub struct RevocationKey(pub PublicKey); + +impl RevocationKey { + /// Derives a per-commitment-transaction revocation public key from its constituent parts. This is + /// the public equivalend of derive_private_revocation_key - using only public keys to derive a + /// public key instead of private keys. + /// + /// Only the cheating participant owns a valid witness to propagate a revoked + /// commitment transaction, thus per_commitment_point always come from cheater + /// and revocation_base_point always come from punisher, which is the broadcaster + /// of the transaction spending with this key knowledge. + /// + /// Note that this is infallible iff we trust that at least one of the two input keys are randomly + /// generated (ie our own). + pub fn from_basepoint( + secp_ctx: &Secp256k1, + basepoint: &RevocationBasepoint, + per_commitment_point: &PublicKey, + ) -> Self { + let rev_append_commit_hash_key = { + let mut sha = Sha256::engine(); + sha.input(&basepoint.to_public_key().serialize()); + sha.input(&per_commitment_point.serialize()); + + Sha256::from_engine(sha).to_byte_array() + }; + let commit_append_rev_hash_key = { + let mut sha = Sha256::engine(); + sha.input(&per_commitment_point.serialize()); + sha.input(&basepoint.to_public_key().serialize()); + + Sha256::from_engine(sha).to_byte_array() + }; + + let countersignatory_contrib = basepoint.to_public_key().mul_tweak(&secp_ctx, &Scalar::from_be_bytes(rev_append_commit_hash_key).unwrap()) + .expect("Multiplying a valid public key by a hash is expected to never fail per secp256k1 docs"); + let broadcaster_contrib = (&per_commitment_point).mul_tweak(&secp_ctx, &Scalar::from_be_bytes(commit_append_rev_hash_key).unwrap()) + .expect("Multiplying a valid public key by a hash is expected to never fail per secp256k1 docs"); + let pk = countersignatory_contrib.combine(&broadcaster_contrib) + .expect("Addition only fails if the tweak is the inverse of the key. This is not possible when the tweak commits to the key."); + Self(pk) + } + + /// Get inner Public Key + pub fn to_public_key(&self) -> PublicKey { + self.0 + } +} +key_read_write!(RevocationKey); + + + +#[cfg(test)] +mod test { + use bitcoin::secp256k1::{Secp256k1, SecretKey, PublicKey}; + use bitcoin::hashes::hex::FromHex; + use super::derive_public_key; + + #[test] + fn test_key_derivation() { + // Test vectors from BOLT 3 Appendix E: + let secp_ctx = Secp256k1::new(); + + let base_secret = SecretKey::from_slice(&>::from_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap()[..]).unwrap(); + let per_commitment_secret = SecretKey::from_slice(&>::from_hex("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap(); + + let base_point = PublicKey::from_secret_key(&secp_ctx, &base_secret); + assert_eq!(base_point.serialize()[..], >::from_hex("036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2").unwrap()[..]); + + let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret); + assert_eq!(per_commitment_point.serialize()[..], >::from_hex("025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486").unwrap()[..]); + + assert_eq!(derive_public_key(&secp_ctx, &per_commitment_point, &base_point).serialize()[..], + >::from_hex("0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5").unwrap()[..]); + } +} diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index f9d364ed0db..fb809041af5 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -14,6 +14,7 @@ pub mod functional_test_utils; pub mod channelmanager; +pub mod channel_keys; pub mod inbound_payment; pub mod msgs; pub mod peer_handler; diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index bc15a3a7662..c4d4bc002f4 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -42,6 +42,7 @@ use crate::chain::transaction::OutPoint; use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI; 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}; use crate::ln::script::ShutdownScript; use crate::offers::invoice::UnsignedBolt12Invoice; @@ -83,7 +84,7 @@ pub struct DelayedPaymentOutputDescriptor { pub output: TxOut, /// The revocation point specific to the commitment transaction which was broadcast. Used to /// derive the witnessScript for this output. - pub revocation_pubkey: PublicKey, + pub revocation_pubkey: RevocationKey, /// Arbitrary identification information returned by a call to [`ChannelSigner::channel_keys_id`]. /// This may be useful in re-deriving keys used in the channel to spend the output. pub channel_keys_id: [u8; 32], @@ -224,8 +225,8 @@ pub enum SpendableOutputDescriptor { /// To derive the delayed payment key which is used to sign this input, you must pass the /// holder [`InMemorySigner::delayed_payment_base_key`] (i.e., the private key which corresponds to the /// [`ChannelPublicKeys::delayed_payment_basepoint`] in [`ChannelSigner::pubkeys`]) and the provided - /// [`DelayedPaymentOutputDescriptor::per_commitment_point`] to [`chan_utils::derive_private_key`]. The public key can be - /// generated without the secret key using [`chan_utils::derive_public_key`] and only the + /// [`DelayedPaymentOutputDescriptor::per_commitment_point`] to [`chan_utils::derive_private_key`]. The DelayedPaymentKey can be + /// generated without the secret key using [`DelayedPaymentKey::from_basepoint`] and only the /// [`ChannelPublicKeys::delayed_payment_basepoint`] which appears in [`ChannelSigner::pubkeys`]. /// /// To derive the [`DelayedPaymentOutputDescriptor::revocation_pubkey`] provided here (which is @@ -233,7 +234,7 @@ pub enum SpendableOutputDescriptor { /// [`ChannelPublicKeys::revocation_basepoint`] (which appears in the call to /// [`ChannelSigner::provide_channel_parameters`]) and the provided /// [`DelayedPaymentOutputDescriptor::per_commitment_point`] to - /// [`chan_utils::derive_public_revocation_key`]. + /// [`RevocationKey`]. /// /// The witness script which is hashed and included in the output `script_pubkey` may be /// regenerated by passing the [`DelayedPaymentOutputDescriptor::revocation_pubkey`] (derived @@ -493,12 +494,10 @@ impl HTLCDescriptor { let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable(); let broadcaster_keys = channel_params.broadcaster_pubkeys(); let counterparty_keys = channel_params.countersignatory_pubkeys(); - let broadcaster_delayed_key = chan_utils::derive_public_key( - secp, &self.per_commitment_point, &broadcaster_keys.delayed_payment_basepoint - ); - let counterparty_revocation_key = chan_utils::derive_public_revocation_key( - secp, &self.per_commitment_point, &counterparty_keys.revocation_basepoint + let broadcaster_delayed_key = DelayedPaymentKey::from_basepoint( + secp, &broadcaster_keys.delayed_payment_basepoint, &self.per_commitment_point ); + let counterparty_revocation_key = &RevocationKey::from_basepoint(&secp, &counterparty_keys.revocation_basepoint, &self.per_commitment_point); chan_utils::build_htlc_output( self.feerate_per_kw, channel_params.contest_delay(), &self.htlc, channel_params.channel_type_features(), &broadcaster_delayed_key, &counterparty_revocation_key @@ -510,15 +509,13 @@ impl HTLCDescriptor { let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable(); let broadcaster_keys = channel_params.broadcaster_pubkeys(); let counterparty_keys = channel_params.countersignatory_pubkeys(); - let broadcaster_htlc_key = chan_utils::derive_public_key( - secp, &self.per_commitment_point, &broadcaster_keys.htlc_basepoint - ); - let counterparty_htlc_key = chan_utils::derive_public_key( - secp, &self.per_commitment_point, &counterparty_keys.htlc_basepoint + let broadcaster_htlc_key = HtlcKey::from_basepoint( + secp, &broadcaster_keys.htlc_basepoint, &self.per_commitment_point ); - let counterparty_revocation_key = chan_utils::derive_public_revocation_key( - secp, &self.per_commitment_point, &counterparty_keys.revocation_basepoint + let counterparty_htlc_key = HtlcKey::from_basepoint( + secp, &counterparty_keys.htlc_basepoint, &self.per_commitment_point, ); + let counterparty_revocation_key = &RevocationKey::from_basepoint(&secp, &counterparty_keys.revocation_basepoint, &self.per_commitment_point); chan_utils::get_htlc_redeemscript_with_explicit_keys( &self.htlc, channel_params.channel_type_features(), &broadcaster_htlc_key, &counterparty_htlc_key, &counterparty_revocation_key, @@ -1031,10 +1028,10 @@ impl InMemorySigner { let from_secret = |s: &SecretKey| PublicKey::from_secret_key(secp_ctx, s); ChannelPublicKeys { funding_pubkey: from_secret(&funding_key), - revocation_basepoint: from_secret(&revocation_base_key), + revocation_basepoint: RevocationBasepoint::from(from_secret(&revocation_base_key)), payment_point: from_secret(&payment_key), - delayed_payment_basepoint: from_secret(&delayed_payment_base_key), - htlc_basepoint: from_secret(&htlc_base_key), + delayed_payment_basepoint: DelayedPaymentBasepoint::from(from_secret(&delayed_payment_base_key)), + htlc_basepoint: HtlcBasepoint::from(from_secret(&htlc_base_key)), } } @@ -1173,7 +1170,7 @@ impl InMemorySigner { if spend_tx.input[input_idx].sequence.0 != descriptor.to_self_delay as u32 { return Err(()); } let delayed_payment_key = chan_utils::derive_private_key(&secp_ctx, &descriptor.per_commitment_point, &self.delayed_payment_base_key); - let delayed_payment_pubkey = PublicKey::from_secret_key(&secp_ctx, &delayed_payment_key); + let delayed_payment_pubkey = DelayedPaymentKey::from_secret_key(&secp_ctx, &delayed_payment_key); let witness_script = chan_utils::get_revokeable_redeemscript(&descriptor.revocation_pubkey, descriptor.to_self_delay, &delayed_payment_pubkey); let sighash = hash_to_message!(&sighash::SighashCache::new(spend_tx).segwit_signature_hash(input_idx, &witness_script, descriptor.output.value, EcdsaSighashType::All).unwrap()[..]); let local_delayedsig = EcdsaSignature { @@ -1286,12 +1283,14 @@ impl EcdsaChannelSigner for InMemorySigner { fn sign_justice_revoked_output(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, secp_ctx: &Secp256k1) -> Result { let revocation_key = chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_key, &self.revocation_base_key); let per_commitment_point = PublicKey::from_secret_key(secp_ctx, &per_commitment_key); - let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint); + let revocation_pubkey = RevocationKey::from_basepoint( + &secp_ctx, &self.pubkeys().revocation_basepoint, &per_commitment_point, + ); let witness_script = { let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); let holder_selected_contest_delay = self.holder_selected_contest_delay().expect(MISSING_PARAMS_ERR); - let counterparty_delayedpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &counterparty_keys.delayed_payment_basepoint); + let counterparty_delayedpubkey = DelayedPaymentKey::from_basepoint(&secp_ctx, &counterparty_keys.delayed_payment_basepoint, &per_commitment_point); chan_utils::get_revokeable_redeemscript(&revocation_pubkey, holder_selected_contest_delay, &counterparty_delayedpubkey) }; let mut sighash_parts = sighash::SighashCache::new(justice_tx); @@ -1302,11 +1301,17 @@ impl EcdsaChannelSigner for InMemorySigner { fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { let revocation_key = chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_key, &self.revocation_base_key); let per_commitment_point = PublicKey::from_secret_key(secp_ctx, &per_commitment_key); - let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint); + let revocation_pubkey = RevocationKey::from_basepoint( + &secp_ctx, &self.pubkeys().revocation_basepoint, &per_commitment_point, + ); let witness_script = { let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); - let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &counterparty_keys.htlc_basepoint); - let holder_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint); + let counterparty_htlcpubkey = HtlcKey::from_basepoint( + &secp_ctx, &counterparty_keys.htlc_basepoint, &per_commitment_point, + ); + let holder_htlcpubkey = HtlcKey::from_basepoint( + &secp_ctx, &self.pubkeys().htlc_basepoint, &per_commitment_point, + ); let chan_type = self.channel_type_features().expect(MISSING_PARAMS_ERR); chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, chan_type, &counterparty_htlcpubkey, &holder_htlcpubkey, &revocation_pubkey) }; @@ -1331,10 +1336,14 @@ impl EcdsaChannelSigner for InMemorySigner { fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { let htlc_key = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &self.htlc_base_key); - let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint); + let revocation_pubkey = RevocationKey::from_basepoint( + &secp_ctx, &self.pubkeys().revocation_basepoint, &per_commitment_point, + ); let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); - let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &counterparty_keys.htlc_basepoint); - let htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint); + let counterparty_htlcpubkey = HtlcKey::from_basepoint( + &secp_ctx, &counterparty_keys.htlc_basepoint, &per_commitment_point, + ); + let htlcpubkey = HtlcKey::from_basepoint(&secp_ctx, &self.pubkeys().htlc_basepoint, &per_commitment_point); let chan_type = self.channel_type_features().expect(MISSING_PARAMS_ERR); let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, chan_type, &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey); let mut sighash_parts = sighash::SighashCache::new(htlc_tx); diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index fe1c8cfe06f..9c6a1e30224 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -9,7 +9,8 @@ use crate::ln::channel::{ANCHOR_OUTPUT_VALUE_SATOSHI, MIN_CHAN_DUST_LIMIT_SATOSHIS}; use crate::ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, HolderCommitmentTransaction, CommitmentTransaction, ChannelTransactionParameters, TrustedCommitmentTransaction, ClosingTransaction}; -use crate::ln::{chan_utils, msgs, PaymentPreimage}; +use crate::ln::channel_keys::{HtlcKey}; +use crate::ln::{msgs, PaymentPreimage}; use crate::sign::{WriteableEcdsaChannelSigner, InMemorySigner, ChannelSigner, EcdsaChannelSigner}; use crate::prelude::*; @@ -232,11 +233,12 @@ impl EcdsaChannelSigner for TestChannelSigner { let sighash = &sighash::SighashCache::new(&*htlc_tx).segwit_signature_hash( input, &witness_script, htlc_descriptor.htlc.amount_msat / 1000, sighash_type ).unwrap(); - let countersignatory_htlc_key = chan_utils::derive_public_key( - &secp_ctx, &htlc_descriptor.per_commitment_point, &self.inner.counterparty_pubkeys().unwrap().htlc_basepoint + let countersignatory_htlc_key = HtlcKey::from_basepoint( + &secp_ctx, &self.inner.counterparty_pubkeys().unwrap().htlc_basepoint, &htlc_descriptor.per_commitment_point, ); + secp_ctx.verify_ecdsa( - &hash_to_message!(sighash.as_byte_array()), &htlc_descriptor.counterparty_sig, &countersignatory_htlc_key + &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())