X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchan_utils.rs;h=39106f0c775fee350116d8830fcab915b55d2ee6;hb=de2acc0ee0166e9d6cbd3a89459e08ee4ac6a4d5;hp=58ac2501f73d22e3a39d305102c3f86a996616af;hpb=263d76eb3da4fed149a5a2ec7fbcde701acdffcd;p=rust-lightning diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 58ac2501..39106f0c 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -14,6 +14,7 @@ use bitcoin::blockdata::script::{Script,Builder}; use bitcoin::blockdata::opcodes; use bitcoin::blockdata::transaction::{TxIn,TxOut,OutPoint,Transaction, EcdsaSighashType}; use bitcoin::util::sighash; +use bitcoin::util::address::Payload; use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::sha256::Hash as Sha256; @@ -25,11 +26,10 @@ use crate::ln::msgs::DecodeError; use crate::util::ser::{Readable, Writeable, Writer}; use crate::util::{byte_utils, transaction_utils}; -use bitcoin::hash_types::WPubkeyHash; use bitcoin::secp256k1::{SecretKey, PublicKey, Scalar}; use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature, Message}; -use bitcoin::secp256k1::Error as SecpError; use bitcoin::{PackedLockTime, secp256k1, Sequence, Witness}; +use bitcoin::PublicKey as BitcoinPublicKey; use crate::io; use crate::prelude::*; @@ -329,32 +329,29 @@ impl Readable for CounterpartyCommitmentSecrets { /// Derives a per-commitment-transaction private key (eg an htlc key or delayed_payment key) /// from the base secret and the per_commitment_point. -/// -/// 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_private_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, base_secret: &SecretKey) -> Result { +pub fn derive_private_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, base_secret: &SecretKey) -> SecretKey { let mut sha = Sha256::engine(); sha.input(&per_commitment_point.serialize()); sha.input(&PublicKey::from_secret_key(&secp_ctx, &base_secret).serialize()); let res = Sha256::from_engine(sha).into_inner(); base_secret.clone().add_tweak(&Scalar::from_be_bytes(res).unwrap()) + .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. -/// -/// 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_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, base_point: &PublicKey) -> Result { +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).into_inner(); - let hashkey = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&res)?); + 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. @@ -363,10 +360,9 @@ pub fn derive_public_key(secp_ctx: &Secp256k1, per_com /// commitment transaction, thus per_commitment_secret always come from cheater /// and revocation_base_secret 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_private_revocation_key(secp_ctx: &Secp256k1, per_commitment_secret: &SecretKey, countersignatory_revocation_base_secret: &SecretKey) -> Result { +pub fn derive_private_revocation_key(secp_ctx: &Secp256k1, + per_commitment_secret: &SecretKey, countersignatory_revocation_base_secret: &SecretKey) +-> SecretKey { let countersignatory_revocation_base_point = PublicKey::from_secret_key(&secp_ctx, &countersignatory_revocation_base_secret); let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret); @@ -385,9 +381,12 @@ pub fn derive_private_revocation_key(secp_ctx: &Secp256k1 Sha256::from_engine(sha).into_inner() }; - let countersignatory_contrib = countersignatory_revocation_base_secret.clone().mul_tweak(&Scalar::from_be_bytes(rev_append_commit_hash_key).unwrap())?; - let broadcaster_contrib = per_commitment_secret.clone().mul_tweak(&Scalar::from_be_bytes(commit_append_rev_hash_key).unwrap())?; + let countersignatory_contrib = countersignatory_revocation_base_secret.clone().mul_tweak(&Scalar::from_be_bytes(rev_append_commit_hash_key).unwrap()) + .expect("Multiplying a secret key by a hash is expected to never fail per secp256k1 docs"); + let broadcaster_contrib = per_commitment_secret.clone().mul_tweak(&Scalar::from_be_bytes(commit_append_rev_hash_key).unwrap()) + .expect("Multiplying a secret key by a hash is expected to never fail per secp256k1 docs"); countersignatory_contrib.add_tweak(&Scalar::from_be_bytes(broadcaster_contrib.secret_bytes()).unwrap()) + .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 @@ -401,7 +400,9 @@ pub fn derive_private_revocation_key(secp_ctx: &Secp256k1 /// /// 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) -> Result { +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()); @@ -417,9 +418,12 @@ pub fn derive_public_revocation_key(secp_ctx: &Secp2 Sha256::from_engine(sha).into_inner() }; - let countersignatory_contrib = countersignatory_revocation_base_point.clone().mul_tweak(&secp_ctx, &Scalar::from_be_bytes(rev_append_commit_hash_key).unwrap())?; - let broadcaster_contrib = per_commitment_point.clone().mul_tweak(&secp_ctx, &Scalar::from_be_bytes(commit_append_rev_hash_key).unwrap())?; + 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. @@ -492,19 +496,19 @@ 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) -> Result { - Ok(TxCreationKeys { + 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 { + 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: 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), + } } /// Generate per-state keys from channel static keys. /// Key set is asymmetric and can't be used as part of counter-signatory set of transactions. - pub fn from_channel_static_keys(per_commitment_point: &PublicKey, broadcaster_keys: &ChannelPublicKeys, countersignatory_keys: &ChannelPublicKeys, secp_ctx: &Secp256k1) -> Result { + pub fn from_channel_static_keys(per_commitment_point: &PublicKey, broadcaster_keys: &ChannelPublicKeys, countersignatory_keys: &ChannelPublicKeys, secp_ctx: &Secp256k1) -> TxCreationKeys { TxCreationKeys::derive_new( &secp_ctx, &per_commitment_point, @@ -673,7 +677,7 @@ pub fn make_funding_redeemscript(broadcaster: &PublicKey, countersignatory: &Pub /// /// 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, opt_anchors: bool, 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, opt_anchors: bool, use_non_zero_fee_anchors: bool, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction { let mut txins: Vec = Vec::new(); txins.push(TxIn { previous_output: OutPoint { @@ -690,7 +694,7 @@ pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, conte } else { htlc_success_tx_weight(opt_anchors) }; - let output_value = if opt_anchors { + let output_value = if opt_anchors && !use_non_zero_fee_anchors { htlc.amount_msat / 1000 } else { let total_fee = feerate_per_kw as u64 * weight / 1000; @@ -778,7 +782,11 @@ pub struct ChannelTransactionParameters { pub funding_outpoint: Option, /// Are anchors (zero fee HTLC transaction variant) used for this channel. Boolean is /// serialization backwards-compatible. - pub opt_anchors: Option<()> + pub opt_anchors: Option<()>, + /// Are non-zero-fee anchors are enabled (used in conjuction with opt_anchors) + /// It is intended merely for backwards compatibility with signers that need it. + /// There is no support for this feature in LDK channel negotiation. + pub opt_non_zero_fee_anchors: Option<()>, } /// Late-bound per-channel counterparty data used to build transactions. @@ -833,6 +841,7 @@ impl_writeable_tlv_based!(ChannelTransactionParameters, { (6, counterparty_parameters, option), (8, funding_outpoint, option), (10, opt_anchors, option), + (12, opt_non_zero_fee_anchors, option), }); /// Static channel fields used to build transactions given per-commitment fields, organized by @@ -955,7 +964,8 @@ impl HolderCommitmentTransaction { is_outbound_from_holder: false, counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: channel_pubkeys.clone(), selected_contest_delay: 0 }), funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }), - opt_anchors: None + opt_anchors: None, + opt_non_zero_fee_anchors: None, }; let mut htlcs_with_aux: Vec<(_, ())> = Vec::new(); let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, false, dummy_key.clone(), dummy_key.clone(), keys, 0, &mut htlcs_with_aux, &channel_parameters.as_counterparty_broadcastable()); @@ -1173,6 +1183,8 @@ pub struct CommitmentTransaction { htlcs: Vec, // A boolean that is serialization backwards-compatible opt_anchors: Option<()>, + // Whether non-zero-fee anchors should be used + opt_non_zero_fee_anchors: Option<()>, // A cache of the parties' pubkeys required to construct the transaction, see doc for trust() keys: TxCreationKeys, // For access to the pre-built transaction, see doc for trust() @@ -1206,6 +1218,7 @@ impl_writeable_tlv_based!(CommitmentTransaction, { (10, built, required), (12, htlcs, vec_type), (14, opt_anchors, option), + (16, opt_non_zero_fee_anchors, option), }); impl CommitmentTransaction { @@ -1238,9 +1251,18 @@ impl CommitmentTransaction { transaction, txid }, + opt_non_zero_fee_anchors: None, } } + /// Use non-zero fee anchors + /// + /// (C-not exported) due to move, and also not likely to be useful for binding users + pub fn with_non_zero_fee_anchors(mut self) -> Self { + self.opt_non_zero_fee_anchors = Some(()); + self + } + fn internal_rebuild_transaction(&self, keys: &TxCreationKeys, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result { let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(self.commitment_number, channel_parameters); @@ -1279,7 +1301,7 @@ impl CommitmentTransaction { let script = if opt_anchors { get_to_countersignatory_with_anchors_redeemscript(&countersignatory_pubkeys.payment_point).to_v0_p2wsh() } else { - get_p2wpkh_redeemscript(&countersignatory_pubkeys.payment_point) + Payload::p2wpkh(&BitcoinPublicKey::new(countersignatory_pubkeys.payment_point)).unwrap().script_pubkey() }; txouts.push(( TxOut { @@ -1441,7 +1463,7 @@ impl CommitmentTransaction { pub fn verify(&self, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_keys: &ChannelPublicKeys, countersignatory_keys: &ChannelPublicKeys, secp_ctx: &Secp256k1) -> Result { // This is the only field of the key cache that we trust let per_commitment_point = self.keys.per_commitment_point; - let keys = TxCreationKeys::from_channel_static_keys(&per_commitment_point, broadcaster_keys, countersignatory_keys, secp_ctx).unwrap(); + let keys = TxCreationKeys::from_channel_static_keys(&per_commitment_point, broadcaster_keys, countersignatory_keys, secp_ctx); if keys != self.keys { return Err(()); } @@ -1501,11 +1523,11 @@ impl<'a> TrustedCommitmentTransaction<'a> { let keys = &inner.keys; let txid = inner.built.txid; let mut ret = Vec::with_capacity(inner.htlcs.len()); - let holder_htlc_key = derive_private_key(secp_ctx, &inner.keys.per_commitment_point, htlc_base_key).map_err(|_| ())?; + let holder_htlc_key = derive_private_key(secp_ctx, &inner.keys.per_commitment_point, htlc_base_key); for this_htlc in inner.htlcs.iter() { assert!(this_htlc.transaction_output_index.is_some()); - let htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, self.opt_anchors(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); + let htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, self.opt_anchors(), self.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key); @@ -1527,7 +1549,7 @@ impl<'a> TrustedCommitmentTransaction<'a> { // Further, we should never be provided the preimage for an HTLC-Timeout transaction. if this_htlc.offered && preimage.is_some() { unreachable!(); } - let mut htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, self.opt_anchors(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); + let mut htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, self.opt_anchors(), self.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key); @@ -1585,18 +1607,12 @@ pub fn get_commitment_transaction_number_obscure_factor( | ((res[31] as u64) << 0 * 8) } -fn get_p2wpkh_redeemscript(key: &PublicKey) -> Script { - Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0) - .push_slice(&WPubkeyHash::hash(&key.serialize())[..]) - .into_script() -} - #[cfg(test)] mod tests { use super::CounterpartyCommitmentSecrets; use crate::{hex, chain}; use crate::prelude::*; - use crate::ln::chan_utils::{get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, get_p2wpkh_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment}; + use crate::ln::chan_utils::{get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment}; use bitcoin::secp256k1::{PublicKey, SecretKey, Secp256k1}; use crate::util::test_utils; use crate::chain::keysinterface::{KeysInterface, BaseSign}; @@ -1604,6 +1620,8 @@ mod tests { use bitcoin::hashes::Hash; use crate::ln::PaymentHash; use bitcoin::hashes::hex::ToHex; + use bitcoin::util::address::Payload; + use bitcoin::PublicKey as BitcoinPublicKey; #[test] fn test_anchors() { @@ -1620,14 +1638,15 @@ mod tests { let htlc_basepoint = &signer.pubkeys().htlc_basepoint; let holder_pubkeys = signer.pubkeys(); let counterparty_pubkeys = counterparty_signer.pubkeys(); - let keys = TxCreationKeys::derive_new(&secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint).unwrap(); + let keys = TxCreationKeys::derive_new(&secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint); let mut channel_parameters = ChannelTransactionParameters { holder_pubkeys: holder_pubkeys.clone(), holder_selected_contest_delay: 0, is_outbound_from_holder: false, counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: counterparty_pubkeys.clone(), selected_contest_delay: 0 }), funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }), - opt_anchors: None + opt_anchors: None, + opt_non_zero_fee_anchors: None, }; let mut htlcs_with_aux: Vec<(_, ())> = Vec::new(); @@ -1642,7 +1661,7 @@ mod tests { &mut htlcs_with_aux, &channel_parameters.as_holder_broadcastable() ); assert_eq!(tx.built.transaction.output.len(), 2); - assert_eq!(tx.built.transaction.output[1].script_pubkey, get_p2wpkh_redeemscript(&counterparty_pubkeys.payment_point)); + assert_eq!(tx.built.transaction.output[1].script_pubkey, Payload::p2wpkh(&BitcoinPublicKey::new(counterparty_pubkeys.payment_point)).unwrap().script_pubkey()); // Generate broadcaster and counterparty outputs as well as two anchors let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(