X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchan_utils.rs;h=85490afaec1292bf792d245c18b13c3b54d78b0a;hb=b7d0357a8ad42415eb38e83aa4595b51e86d1a98;hp=4a66f85e2c98e63281fd82e5e2cfd42f761e416a;hpb=648a69a1e31ceae7c6fa2259d18d1a2ac1095ced;p=rust-lightning diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 4a66f85e..85490afa 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -8,7 +8,7 @@ // licenses. //! Various utilities for building scripts and deriving keys related to channels. These are -//! largely of interest for those implementing chain::keysinterface::Sign message signing by hand. +//! largely of interest for those implementing the traits on [`crate::sign`] by hand. use bitcoin::blockdata::script::{Script,Builder}; use bitcoin::blockdata::opcodes; @@ -21,14 +21,14 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::ripemd160::Hash as Ripemd160; use bitcoin::hash_types::{Txid, PubkeyHash}; +use crate::sign::EntropySource; use crate::ln::{PaymentHash, PaymentPreimage}; use crate::ln::msgs::DecodeError; -use crate::util::ser::{Readable, Writeable, Writer}; -use crate::util::{byte_utils, transaction_utils}; +use crate::util::ser::{Readable, RequiredWrapper, Writeable, Writer}; +use crate::util::transaction_utils; 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; @@ -40,7 +40,8 @@ use crate::util::transaction_utils::sort_outputs; use crate::ln::channel::{INITIAL_COMMITMENT_NUMBER, ANCHOR_OUTPUT_VALUE_SATOSHI}; use core::ops::Deref; use crate::chain; -use crate::util::crypto::sign; +use crate::ln::features::ChannelTypeFeatures; +use crate::util::crypto::{sign, sign_with_aux_rand}; /// Maximum number of one-way in-flight HTLC (protocol-level value). pub const MAX_HTLCS: u16 = 483; @@ -57,20 +58,29 @@ pub(crate) const MIN_ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 136; /// This is the maximum post-anchor value. pub const MAX_ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 143; +/// The upper bound weight of an anchor input. +pub const ANCHOR_INPUT_WITNESS_WEIGHT: u64 = 116; +/// The upper bound weight of an HTLC timeout input from a commitment transaction with anchor +/// outputs. +pub const HTLC_TIMEOUT_INPUT_ANCHOR_WITNESS_WEIGHT: u64 = 288; +/// The upper bound weight of an HTLC success input from a commitment transaction with anchor +/// outputs. +pub const HTLC_SUCCESS_INPUT_ANCHOR_WITNESS_WEIGHT: u64 = 327; + /// Gets the weight for an HTLC-Success transaction. #[inline] -pub fn htlc_success_tx_weight(opt_anchors: bool) -> u64 { +pub fn htlc_success_tx_weight(channel_type_features: &ChannelTypeFeatures) -> u64 { const HTLC_SUCCESS_TX_WEIGHT: u64 = 703; const HTLC_SUCCESS_ANCHOR_TX_WEIGHT: u64 = 706; - if opt_anchors { HTLC_SUCCESS_ANCHOR_TX_WEIGHT } else { HTLC_SUCCESS_TX_WEIGHT } + if channel_type_features.supports_anchors_zero_fee_htlc_tx() { HTLC_SUCCESS_ANCHOR_TX_WEIGHT } else { HTLC_SUCCESS_TX_WEIGHT } } /// Gets the weight for an HTLC-Timeout transaction. #[inline] -pub fn htlc_timeout_tx_weight(opt_anchors: bool) -> u64 { +pub fn htlc_timeout_tx_weight(channel_type_features: &ChannelTypeFeatures) -> u64 { const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663; const HTLC_TIMEOUT_ANCHOR_TX_WEIGHT: u64 = 666; - if opt_anchors { HTLC_TIMEOUT_ANCHOR_TX_WEIGHT } else { HTLC_TIMEOUT_TX_WEIGHT } + if channel_type_features.supports_anchors_zero_fee_htlc_tx() { HTLC_TIMEOUT_ANCHOR_TX_WEIGHT } else { HTLC_TIMEOUT_TX_WEIGHT } } /// Describes the type of HTLC claim as determined by analyzing the witness. @@ -310,7 +320,7 @@ impl Writeable for CounterpartyCommitmentSecrets { fn write(&self, writer: &mut W) -> Result<(), io::Error> { for &(ref secret, ref idx) in self.old_secrets.iter() { writer.write_all(secret)?; - writer.write_all(&byte_utils::be64_to_array(*idx))?; + writer.write_all(&idx.to_be_bytes())?; } write_tlv_fields!(writer, {}); Ok(()) @@ -330,32 +340,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. @@ -364,10 +371,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); @@ -386,9 +392,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 @@ -402,7 +411,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()); @@ -418,9 +429,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. @@ -459,7 +473,7 @@ impl_writeable_tlv_based!(TxCreationKeys, { }); /// One counterparty's public keys which do not change over the life of a channel. -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct ChannelPublicKeys { /// The public key which is used to sign all commitment transactions, as it appears in the /// on-chain channel lock-in 2-of-2 multisig output. @@ -493,19 +507,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, @@ -570,7 +584,7 @@ impl_writeable_tlv_based!(HTLCOutputInCommitment, { }); #[inline] -pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, opt_anchors: bool, broadcaster_htlc_key: &PublicKey, countersignatory_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script { +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) -> Script { let payment_hash160 = Ripemd160::hash(&htlc.payment_hash.0[..]).into_inner(); if htlc.offered { let mut bldr = Builder::new().push_opcode(opcodes::all::OP_DUP) @@ -598,7 +612,7 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_CHECKSIG) .push_opcode(opcodes::all::OP_ENDIF); - if opt_anchors { + if channel_type_features.supports_anchors_zero_fee_htlc_tx() { bldr = bldr.push_opcode(opcodes::all::OP_PUSHNUM_1) .push_opcode(opcodes::all::OP_CSV) .push_opcode(opcodes::all::OP_DROP); @@ -634,7 +648,7 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit .push_opcode(opcodes::all::OP_DROP) .push_opcode(opcodes::all::OP_CHECKSIG) .push_opcode(opcodes::all::OP_ENDIF); - if opt_anchors { + if channel_type_features.supports_anchors_zero_fee_htlc_tx() { bldr = bldr.push_opcode(opcodes::all::OP_PUSHNUM_1) .push_opcode(opcodes::all::OP_CSV) .push_opcode(opcodes::all::OP_DROP); @@ -647,8 +661,8 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit /// Gets the witness redeemscript for an HTLC output in a commitment transaction. Note that htlc /// does not need to have its previous_output_index filled. #[inline] -pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, opt_anchors: bool, keys: &TxCreationKeys) -> Script { - get_htlc_redeemscript_with_explicit_keys(htlc, opt_anchors, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key) +pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures, keys: &TxCreationKeys) -> Script { + get_htlc_redeemscript_with_explicit_keys(htlc, channel_type_features, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key) } /// Gets the redeemscript for a funding output from the two funding public keys. @@ -657,13 +671,17 @@ pub fn make_funding_redeemscript(broadcaster: &PublicKey, countersignatory: &Pub let broadcaster_funding_key = broadcaster.serialize(); let countersignatory_funding_key = countersignatory.serialize(); + make_funding_redeemscript_from_slices(&broadcaster_funding_key, &countersignatory_funding_key) +} + +pub(crate) fn make_funding_redeemscript_from_slices(broadcaster_funding_key: &[u8], countersignatory_funding_key: &[u8]) -> Script { let builder = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2); if broadcaster_funding_key[..] < countersignatory_funding_key[..] { - builder.push_slice(&broadcaster_funding_key) - .push_slice(&countersignatory_funding_key) + builder.push_slice(broadcaster_funding_key) + .push_slice(countersignatory_funding_key) } else { - builder.push_slice(&countersignatory_funding_key) - .push_slice(&broadcaster_funding_key) + builder.push_slice(countersignatory_funding_key) + .push_slice(broadcaster_funding_key) }.push_opcode(opcodes::all::OP_PUSHNUM_2).push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script() } @@ -674,41 +692,111 @@ 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, use_non_zero_fee_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, channel_type_features: &ChannelTypeFeatures, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction { let mut txins: Vec = Vec::new(); - txins.push(TxIn { + txins.push(build_htlc_input(commitment_txid, htlc, channel_type_features)); + + let mut txouts: Vec = Vec::new(); + txouts.push(build_htlc_output( + feerate_per_kw, contest_delay, htlc, channel_type_features, + broadcaster_delayed_payment_key, revocation_key + )); + + Transaction { + version: 2, + lock_time: PackedLockTime(if htlc.offered { htlc.cltv_expiry } else { 0 }), + input: txins, + output: txouts, + } +} + +pub(crate) fn build_htlc_input(commitment_txid: &Txid, htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures) -> TxIn { + TxIn { previous_output: OutPoint { txid: commitment_txid.clone(), vout: htlc.transaction_output_index.expect("Can't build an HTLC transaction for a dust output"), }, script_sig: Script::new(), - sequence: Sequence(if opt_anchors { 1 } else { 0 }), + sequence: Sequence(if channel_type_features.supports_anchors_zero_fee_htlc_tx() { 1 } else { 0 }), witness: Witness::new(), - }); + } +} +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 +) -> TxOut { let weight = if htlc.offered { - htlc_timeout_tx_weight(opt_anchors) + htlc_timeout_tx_weight(channel_type_features) } else { - htlc_success_tx_weight(opt_anchors) + htlc_success_tx_weight(channel_type_features) }; - let output_value = if opt_anchors && !use_non_zero_fee_anchors { + let output_value = if channel_type_features.supports_anchors_zero_fee_htlc_tx() && !channel_type_features.supports_anchors_nonzero_fee_htlc_tx() { htlc.amount_msat / 1000 } else { let total_fee = feerate_per_kw as u64 * weight / 1000; htlc.amount_msat / 1000 - total_fee }; - let mut txouts: Vec = Vec::new(); - txouts.push(TxOut { + TxOut { script_pubkey: get_revokeable_redeemscript(revocation_key, contest_delay, broadcaster_delayed_payment_key).to_v0_p2wsh(), value: output_value, - }); + } +} - Transaction { - version: 2, - lock_time: PackedLockTime(if htlc.offered { htlc.cltv_expiry } else { 0 }), - input: txins, - output: txouts, +/// Returns the witness required to satisfy and spend a HTLC input. +pub fn build_htlc_input_witness( + local_sig: &Signature, remote_sig: &Signature, preimage: &Option, + redeem_script: &Script, channel_type_features: &ChannelTypeFeatures, +) -> Witness { + let remote_sighash_type = if channel_type_features.supports_anchors_zero_fee_htlc_tx() { + EcdsaSighashType::SinglePlusAnyoneCanPay + } else { + EcdsaSighashType::All + }; + + let mut witness = Witness::new(); + // First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element. + witness.push(vec![]); + witness.push_bitcoin_signature(&remote_sig.serialize_der(), remote_sighash_type); + witness.push_bitcoin_signature(&local_sig.serialize_der(), EcdsaSighashType::All); + if let Some(preimage) = preimage { + witness.push(preimage.0.to_vec()); + } else { + // Due to BIP146 (MINIMALIF) this must be a zero-length element to relay. + witness.push(vec![]); + } + witness.push(redeem_script.to_bytes()); + witness +} + +/// Pre-anchors channel type features did not use to get serialized in the following six structs: +/// — [`ChannelTransactionParameters`] +/// — [`CommitmentTransaction`] +/// — [`CounterpartyOfferedHTLCOutput`] +/// — [`CounterpartyReceivedHTLCOutput`] +/// — [`HolderHTLCOutput`] +/// — [`HolderFundingOutput`] +/// +/// To ensure a forwards-compatible serialization, we use odd TLV fields. However, if new features +/// are used that could break security, where old signers should be prevented from handling the +/// serialized data, an optional even-field TLV will be used as a stand-in to break compatibility. +/// +/// This method determines whether or not that option needs to be set based on the chanenl type +/// features, and returns it. +/// +/// [`CounterpartyOfferedHTLCOutput`]: crate::chain::package::CounterpartyOfferedHTLCOutput +/// [`CounterpartyReceivedHTLCOutput`]: crate::chain::package::CounterpartyReceivedHTLCOutput +/// [`HolderHTLCOutput`]: crate::chain::package::HolderHTLCOutput +/// [`HolderFundingOutput`]: crate::chain::package::HolderFundingOutput +pub(crate) fn legacy_deserialization_prevention_marker_for_channel_type_features(features: &ChannelTypeFeatures) -> Option<()> { + let mut legacy_version_bit_set = ChannelTypeFeatures::only_static_remote_key(); + legacy_version_bit_set.set_scid_privacy_required(); + legacy_version_bit_set.set_zero_conf_required(); + + if features.is_subset(&legacy_version_bit_set) { + None + } else { + Some(()) } } @@ -741,7 +829,6 @@ pub fn get_anchor_redeemscript(funding_pubkey: &PublicKey) -> Script { .into_script() } -#[cfg(anchors)] /// Locates the output with an anchor script paying to `funding_pubkey` within `commitment_tx`. pub(crate) fn get_anchor_output<'a>(commitment_tx: &'a Transaction, funding_pubkey: &PublicKey) -> Option<(u32, &'a TxOut)> { let anchor_script = chan_utils::get_anchor_redeemscript(funding_pubkey).to_v0_p2wsh(); @@ -753,9 +840,10 @@ pub(crate) fn get_anchor_output<'a>(commitment_tx: &'a Transaction, funding_pubk /// Returns the witness required to satisfy and spend an anchor input. pub fn build_anchor_input_witness(funding_key: &PublicKey, funding_sig: &Signature) -> Witness { let anchor_redeem_script = chan_utils::get_anchor_redeemscript(funding_key); - let mut funding_sig = funding_sig.serialize_der().to_vec(); - funding_sig.push(EcdsaSighashType::All as u8); - Witness::from_vec(vec![funding_sig, anchor_redeem_script.to_bytes()]) + let mut ret = Witness::new(); + ret.push_bitcoin_signature(&funding_sig.serialize_der(), EcdsaSighashType::All); + ret.push(anchor_redeem_script.as_bytes()); + ret } /// Per-channel data used to build transactions in conjunction with the per-commitment data (CommitmentTransaction). @@ -763,7 +851,7 @@ pub fn build_anchor_input_witness(funding_key: &PublicKey, funding_sig: &Signatu /// /// Normally, this is converted to the broadcaster/countersignatory-organized DirectedChannelTransactionParameters /// before use, via the as_holder_broadcastable and as_counterparty_broadcastable functions. -#[derive(Clone, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct ChannelTransactionParameters { /// Holder public keys pub holder_pubkeys: ChannelPublicKeys, @@ -777,17 +865,13 @@ pub struct ChannelTransactionParameters { pub counterparty_parameters: Option, /// The late-bound funding outpoint pub funding_outpoint: Option, - /// Are anchors (zero fee HTLC transaction variant) used for this channel. Boolean is - /// serialization backwards-compatible. - 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<()>, + /// This channel's type, as negotiated during channel open. For old objects where this field + /// wasn't serialized, it will default to static_remote_key at deserialization. + pub channel_type_features: ChannelTypeFeatures } /// Late-bound per-channel counterparty data used to build transactions. -#[derive(Clone, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct CounterpartyChannelTransactionParameters { /// Counter-party public keys pub pubkeys: ChannelPublicKeys, @@ -831,15 +915,56 @@ impl_writeable_tlv_based!(CounterpartyChannelTransactionParameters, { (2, selected_contest_delay, required), }); -impl_writeable_tlv_based!(ChannelTransactionParameters, { - (0, holder_pubkeys, required), - (2, holder_selected_contest_delay, required), - (4, is_outbound_from_holder, required), - (6, counterparty_parameters, option), - (8, funding_outpoint, option), - (10, opt_anchors, option), - (12, opt_non_zero_fee_anchors, option), -}); +impl Writeable for ChannelTransactionParameters { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + let legacy_deserialization_prevention_marker = legacy_deserialization_prevention_marker_for_channel_type_features(&self.channel_type_features); + write_tlv_fields!(writer, { + (0, self.holder_pubkeys, required), + (2, self.holder_selected_contest_delay, required), + (4, self.is_outbound_from_holder, required), + (6, self.counterparty_parameters, option), + (8, self.funding_outpoint, option), + (10, legacy_deserialization_prevention_marker, option), + (11, self.channel_type_features, required), + }); + Ok(()) + } +} + +impl Readable for ChannelTransactionParameters { + fn read(reader: &mut R) -> Result { + let mut holder_pubkeys = RequiredWrapper(None); + let mut holder_selected_contest_delay = RequiredWrapper(None); + let mut is_outbound_from_holder = RequiredWrapper(None); + let mut counterparty_parameters = None; + let mut funding_outpoint = None; + let mut _legacy_deserialization_prevention_marker: Option<()> = None; + let mut channel_type_features = None; + + read_tlv_fields!(reader, { + (0, holder_pubkeys, required), + (2, holder_selected_contest_delay, required), + (4, is_outbound_from_holder, required), + (6, counterparty_parameters, option), + (8, funding_outpoint, option), + (10, _legacy_deserialization_prevention_marker, option), + (11, channel_type_features, option), + }); + + let mut additional_features = ChannelTypeFeatures::empty(); + additional_features.set_anchors_nonzero_fee_htlc_tx_required(); + chain::package::verify_channel_type_features(&channel_type_features, Some(&additional_features))?; + + Ok(Self { + holder_pubkeys: holder_pubkeys.0.unwrap(), + holder_selected_contest_delay: holder_selected_contest_delay.0.unwrap(), + is_outbound_from_holder: is_outbound_from_holder.0.unwrap(), + counterparty_parameters, + funding_outpoint, + channel_type_features: channel_type_features.unwrap_or(ChannelTypeFeatures::only_static_remote_key()) + }) + } +} /// Static channel fields used to build transactions given per-commitment fields, organized by /// broadcaster/countersignatory. @@ -893,8 +1018,8 @@ impl<'a> DirectedChannelTransactionParameters<'a> { } /// Whether to use anchors for this channel - pub fn opt_anchors(&self) -> bool { - self.inner.opt_anchors.is_some() + pub fn channel_type_features(&self) -> &ChannelTypeFeatures { + &self.inner.channel_type_features } } @@ -931,12 +1056,12 @@ impl_writeable_tlv_based!(HolderCommitmentTransaction, { (0, inner, required), (2, counterparty_sig, required), (4, holder_sig_first, required), - (6, counterparty_htlc_sigs, vec_type), + (6, counterparty_htlc_sigs, required_vec), }); impl HolderCommitmentTransaction { #[cfg(test)] - pub fn dummy() -> Self { + pub fn dummy(htlcs: &mut Vec<(HTLCOutputInCommitment, ())>) -> Self { let secp_ctx = Secp256k1::new(); let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); let dummy_sig = sign(&secp_ctx, &secp256k1::Message::from_slice(&[42; 32]).unwrap(), &SecretKey::from_slice(&[42; 32]).unwrap()); @@ -961,15 +1086,18 @@ 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_non_zero_fee_anchors: None, + channel_type_features: ChannelTypeFeatures::only_static_remote_key(), }; - 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()); + let mut counterparty_htlc_sigs = Vec::new(); + for _ in 0..htlcs.len() { + counterparty_htlc_sigs.push(dummy_sig); + } + let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, dummy_key.clone(), dummy_key.clone(), keys, 0, htlcs, &channel_parameters.as_counterparty_broadcastable()); + htlcs.sort_by_key(|htlc| htlc.0.transaction_output_index); HolderCommitmentTransaction { inner, counterparty_sig: dummy_sig, - counterparty_htlc_sigs: Vec::new(), + counterparty_htlc_sigs, holder_sig_first: false } } @@ -989,17 +1117,13 @@ impl HolderCommitmentTransaction { // First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element. let mut tx = self.inner.built.transaction.clone(); tx.input[0].witness.push(Vec::new()); - let mut ser_holder_sig = holder_sig.serialize_der().to_vec(); - ser_holder_sig.push(EcdsaSighashType::All as u8); - let mut ser_cp_sig = self.counterparty_sig.serialize_der().to_vec(); - ser_cp_sig.push(EcdsaSighashType::All as u8); if self.holder_sig_first { - tx.input[0].witness.push(ser_holder_sig); - tx.input[0].witness.push(ser_cp_sig); + tx.input[0].witness.push_bitcoin_signature(&holder_sig.serialize_der(), EcdsaSighashType::All); + tx.input[0].witness.push_bitcoin_signature(&self.counterparty_sig.serialize_der(), EcdsaSighashType::All); } else { - tx.input[0].witness.push(ser_cp_sig); - tx.input[0].witness.push(ser_holder_sig); + tx.input[0].witness.push_bitcoin_signature(&self.counterparty_sig.serialize_der(), EcdsaSighashType::All); + tx.input[0].witness.push_bitcoin_signature(&holder_sig.serialize_der(), EcdsaSighashType::All); } tx.input[0].witness.push(funding_redeemscript.as_bytes().to_vec()); @@ -1033,12 +1157,20 @@ impl BuiltCommitmentTransaction { hash_to_message!(sighash) } - /// Sign a transaction, either because we are counter-signing the counterparty's transaction or - /// because we are about to broadcast a holder transaction. - pub fn sign(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1) -> Signature { + /// Signs the counterparty's commitment transaction. + pub fn sign_counterparty_commitment(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1) -> Signature { let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis); sign(secp_ctx, &sighash, funding_key) } + + /// Signs the holder commitment transaction because we are about to broadcast it. + pub fn sign_holder_commitment( + &self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, + entropy_source: &ES, secp_ctx: &Secp256k1 + ) -> Signature where ES::Target: EntropySource { + let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis); + sign_with_aux_rand(secp_ctx, &sighash, funding_key, entropy_source) + } } /// This class tracks the per-transaction information needed to build a closing transaction and will @@ -1178,10 +1310,8 @@ pub struct CommitmentTransaction { to_countersignatory_value_sat: u64, feerate_per_kw: u32, 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<()>, + // Note that on upgrades, some features of existing outputs may be missed. + channel_type_features: ChannelTypeFeatures, // 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() @@ -1196,7 +1326,7 @@ impl PartialEq for CommitmentTransaction { self.to_countersignatory_value_sat == o.to_countersignatory_value_sat && self.feerate_per_kw == o.feerate_per_kw && self.htlcs == o.htlcs && - self.opt_anchors == o.opt_anchors && + self.channel_type_features == o.channel_type_features && self.keys == o.keys; if eq { debug_assert_eq!(self.built.transaction, o.built.transaction); @@ -1206,17 +1336,54 @@ impl PartialEq for CommitmentTransaction { } } -impl_writeable_tlv_based!(CommitmentTransaction, { - (0, commitment_number, required), - (2, to_broadcaster_value_sat, required), - (4, to_countersignatory_value_sat, required), - (6, feerate_per_kw, required), - (8, keys, required), - (10, built, required), - (12, htlcs, vec_type), - (14, opt_anchors, option), - (16, opt_non_zero_fee_anchors, option), -}); +impl Writeable for CommitmentTransaction { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + let legacy_deserialization_prevention_marker = legacy_deserialization_prevention_marker_for_channel_type_features(&self.channel_type_features); + write_tlv_fields!(writer, { + (0, self.commitment_number, required), + (2, self.to_broadcaster_value_sat, required), + (4, self.to_countersignatory_value_sat, required), + (6, self.feerate_per_kw, required), + (8, self.keys, required), + (10, self.built, required), + (12, self.htlcs, required_vec), + (14, legacy_deserialization_prevention_marker, option), + (15, self.channel_type_features, required), + }); + Ok(()) + } +} + +impl Readable for CommitmentTransaction { + fn read(reader: &mut R) -> Result { + _init_and_read_tlv_fields!(reader, { + (0, commitment_number, required), + (2, to_broadcaster_value_sat, required), + (4, to_countersignatory_value_sat, required), + (6, feerate_per_kw, required), + (8, keys, required), + (10, built, required), + (12, htlcs, required_vec), + (14, _legacy_deserialization_prevention_marker, option), + (15, channel_type_features, option), + }); + + let mut additional_features = ChannelTypeFeatures::empty(); + additional_features.set_anchors_nonzero_fee_htlc_tx_required(); + chain::package::verify_channel_type_features(&channel_type_features, Some(&additional_features))?; + + Ok(Self { + commitment_number: commitment_number.0.unwrap(), + to_broadcaster_value_sat: to_broadcaster_value_sat.0.unwrap(), + to_countersignatory_value_sat: to_countersignatory_value_sat.0.unwrap(), + feerate_per_kw: feerate_per_kw.0.unwrap(), + keys: keys.0.unwrap(), + built: built.0.unwrap(), + htlcs, + channel_type_features: channel_type_features.unwrap_or(ChannelTypeFeatures::only_static_remote_key()) + }) + } +} impl CommitmentTransaction { /// Construct an object of the class while assigning transaction output indices to HTLCs. @@ -1228,10 +1395,10 @@ impl CommitmentTransaction { /// /// Only include HTLCs that are above the dust limit for the channel. /// - /// (C-not exported) due to the generic though we likely should expose a version without - pub fn new_with_auxiliary_htlc_data(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, opt_anchors: bool, broadcaster_funding_key: PublicKey, countersignatory_funding_key: PublicKey, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction { + /// This is not exported to bindings users due to the generic though we likely should expose a version without + pub fn new_with_auxiliary_htlc_data(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, broadcaster_funding_key: PublicKey, countersignatory_funding_key: PublicKey, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction { // Sort outputs and populate output indices while keeping track of the auxiliary data - let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters, opt_anchors, &broadcaster_funding_key, &countersignatory_funding_key).unwrap(); + let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters, &broadcaster_funding_key, &countersignatory_funding_key).unwrap(); let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(commitment_number, channel_parameters); let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs); @@ -1242,21 +1409,20 @@ impl CommitmentTransaction { to_countersignatory_value_sat, feerate_per_kw, htlcs, - opt_anchors: if opt_anchors { Some(()) } else { None }, + channel_type_features: channel_parameters.channel_type_features().clone(), keys, built: BuiltCommitmentTransaction { 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 + /// This is not exported to bindings users 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.channel_type_features.set_anchors_nonzero_fee_htlc_tx_required(); self } @@ -1264,7 +1430,7 @@ impl CommitmentTransaction { let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(self.commitment_number, channel_parameters); let mut htlcs_with_aux = self.htlcs.iter().map(|h| (h.clone(), ())).collect(); - let (outputs, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters, self.opt_anchors.is_some(), broadcaster_funding_key, countersignatory_funding_key)?; + let (outputs, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters, broadcaster_funding_key, countersignatory_funding_key)?; let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs); let txid = transaction.txid(); @@ -1288,14 +1454,14 @@ impl CommitmentTransaction { // - initial sorting of outputs / HTLCs in the constructor, in which case T is auxiliary data the // caller needs to have sorted together with the HTLCs so it can keep track of the output index // - building of a bitcoin transaction during a verify() call, in which case T is just () - fn internal_build_outputs(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, opt_anchors: bool, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<(Vec, Vec), ()> { + fn internal_build_outputs(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<(Vec, Vec), ()> { let countersignatory_pubkeys = channel_parameters.countersignatory_pubkeys(); let contest_delay = channel_parameters.contest_delay(); let mut txouts: Vec<(TxOut, Option<&mut HTLCOutputInCommitment>)> = Vec::new(); if to_countersignatory_value_sat > 0 { - let script = if opt_anchors { + let script = if channel_parameters.channel_type_features().supports_anchors_zero_fee_htlc_tx() { get_to_countersignatory_with_anchors_redeemscript(&countersignatory_pubkeys.payment_point).to_v0_p2wsh() } else { Payload::p2wpkh(&BitcoinPublicKey::new(countersignatory_pubkeys.payment_point)).unwrap().script_pubkey() @@ -1324,7 +1490,7 @@ impl CommitmentTransaction { )); } - if opt_anchors { + if channel_parameters.channel_type_features().supports_anchors_zero_fee_htlc_tx() { if to_broadcaster_value_sat > 0 || !htlcs_with_aux.is_empty() { let anchor_script = get_anchor_redeemscript(broadcaster_funding_key); txouts.push(( @@ -1350,7 +1516,7 @@ impl CommitmentTransaction { let mut htlcs = Vec::with_capacity(htlcs_with_aux.len()); for (htlc, _) in htlcs_with_aux { - let script = chan_utils::get_htlc_redeemscript(&htlc, opt_anchors, &keys); + let script = chan_utils::get_htlc_redeemscript(&htlc, &channel_parameters.channel_type_features(), &keys); let txout = TxOut { script_pubkey: script.to_v0_p2wsh(), value: htlc.amount_msat / 1000, @@ -1435,7 +1601,7 @@ impl CommitmentTransaction { /// which were included in this commitment transaction in output order. /// The transaction index is always populated. /// - /// (C-not exported) as we cannot currently convert Vec references to/from C, though we should + /// This is not exported to bindings users as we cannot currently convert Vec references to/from C, though we should /// expose a less effecient version which creates a Vec of references in the future. pub fn htlcs(&self) -> &Vec { &self.htlcs @@ -1460,7 +1626,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(()); } @@ -1505,8 +1671,8 @@ impl<'a> TrustedCommitmentTransaction<'a> { } /// Should anchors be used. - pub fn opt_anchors(&self) -> bool { - self.opt_anchors.is_some() + pub fn channel_type_features(&self) -> &ChannelTypeFeatures { + &self.inner.channel_type_features } /// Get a signature for each HTLC which was included in the commitment transaction (ie for @@ -1515,21 +1681,24 @@ impl<'a> TrustedCommitmentTransaction<'a> { /// The returned Vec has one entry for each HTLC, and in the same order. /// /// This function is only valid in the holder commitment context, it always uses EcdsaSighashType::All. - pub fn get_htlc_sigs(&self, htlc_base_key: &SecretKey, channel_parameters: &DirectedChannelTransactionParameters, secp_ctx: &Secp256k1) -> Result, ()> { + pub fn get_htlc_sigs( + &self, htlc_base_key: &SecretKey, channel_parameters: &DirectedChannelTransactionParameters, + entropy_source: &ES, secp_ctx: &Secp256k1, + ) -> Result, ()> where ES::Target: EntropySource { let inner = self.inner; 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(), self.opt_non_zero_fee_anchors.is_some(), &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.channel_type_features, &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); + let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, &self.channel_type_features, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key); let sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, this_htlc.amount_msat / 1000, EcdsaSighashType::All).unwrap()[..]); - ret.push(sign(secp_ctx, &sighash, &holder_htlc_key)); + ret.push(sign_with_aux_rand(secp_ctx, &sighash, &holder_htlc_key, entropy_source)); } Ok(ret) } @@ -1546,30 +1715,13 @@ 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(), 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); + let mut htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, &self.channel_type_features, &keys.broadcaster_delayed_payment_key, &keys.revocation_key); - let sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; + let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, &self.channel_type_features, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key); - // First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element. - htlc_tx.input[0].witness.push(Vec::new()); - - let mut cp_sig_ser = counterparty_signature.serialize_der().to_vec(); - cp_sig_ser.push(sighashtype as u8); - htlc_tx.input[0].witness.push(cp_sig_ser); - let mut holder_sig_ser = signature.serialize_der().to_vec(); - holder_sig_ser.push(EcdsaSighashType::All as u8); - htlc_tx.input[0].witness.push(holder_sig_ser); - - if this_htlc.offered { - // Due to BIP146 (MINIMALIF) this must be a zero-length element to relay. - htlc_tx.input[0].witness.push(Vec::new()); - } else { - htlc_tx.input[0].witness.push(preimage.unwrap().0.to_vec()); - } - - htlc_tx.input[0].witness.push(htlc_redeemscript.as_bytes().to_vec()); + htlc_tx.input[0].witness = chan_utils::build_htlc_input_witness( + signature, counterparty_signature, preimage, &htlc_redeemscript, &self.channel_type_features, + ); htlc_tx } } @@ -1612,13 +1764,14 @@ mod tests { 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}; + use crate::sign::{ChannelSigner, SignerProvider}; use bitcoin::{Network, Txid}; use bitcoin::hashes::Hash; use crate::ln::PaymentHash; use bitcoin::hashes::hex::ToHex; use bitcoin::util::address::Payload; use bitcoin::PublicKey as BitcoinPublicKey; + use crate::ln::features::ChannelTypeFeatures; #[test] fn test_anchors() { @@ -1635,15 +1788,14 @@ 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_non_zero_fee_anchors: None, + channel_type_features: ChannelTypeFeatures::only_static_remote_key(), }; let mut htlcs_with_aux: Vec<(_, ())> = Vec::new(); @@ -1651,7 +1803,6 @@ mod tests { // Generate broadcaster and counterparty outputs let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( 0, 1000, 2000, - false, holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, @@ -1661,9 +1812,9 @@ mod tests { 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 + channel_parameters.channel_type_features = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(); let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( 0, 1000, 2000, - true, holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, @@ -1675,7 +1826,6 @@ mod tests { // Generate broadcaster output and anchor let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( 0, 3000, 0, - true, holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, @@ -1686,7 +1836,6 @@ mod tests { // Generate counterparty output and anchor let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( 0, 0, 3000, - true, holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, @@ -1711,9 +1860,9 @@ mod tests { }; // Generate broadcaster output and received and offered HTLC outputs, w/o anchors + channel_parameters.channel_type_features = ChannelTypeFeatures::only_static_remote_key(); let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( 0, 3000, 0, - false, holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, @@ -1721,18 +1870,17 @@ mod tests { &channel_parameters.as_holder_broadcastable() ); assert_eq!(tx.built.transaction.output.len(), 3); - assert_eq!(tx.built.transaction.output[0].script_pubkey, get_htlc_redeemscript(&received_htlc, false, &keys).to_v0_p2wsh()); - assert_eq!(tx.built.transaction.output[1].script_pubkey, get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh()); - assert_eq!(get_htlc_redeemscript(&received_htlc, false, &keys).to_v0_p2wsh().to_hex(), + assert_eq!(tx.built.transaction.output[0].script_pubkey, get_htlc_redeemscript(&received_htlc, &ChannelTypeFeatures::only_static_remote_key(), &keys).to_v0_p2wsh()); + assert_eq!(tx.built.transaction.output[1].script_pubkey, get_htlc_redeemscript(&offered_htlc, &ChannelTypeFeatures::only_static_remote_key(), &keys).to_v0_p2wsh()); + assert_eq!(get_htlc_redeemscript(&received_htlc, &ChannelTypeFeatures::only_static_remote_key(), &keys).to_v0_p2wsh().to_hex(), "0020e43a7c068553003fe68fcae424fb7b28ec5ce48cd8b6744b3945631389bad2fb"); - assert_eq!(get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh().to_hex(), + assert_eq!(get_htlc_redeemscript(&offered_htlc, &ChannelTypeFeatures::only_static_remote_key(), &keys).to_v0_p2wsh().to_hex(), "0020215d61bba56b19e9eadb6107f5a85d7f99c40f65992443f69229c290165bc00d"); // Generate broadcaster output and received and offered HTLC outputs, with anchors - channel_parameters.opt_anchors = Some(()); + channel_parameters.channel_type_features = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(); let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( 0, 3000, 0, - true, holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, @@ -1740,11 +1888,11 @@ mod tests { &channel_parameters.as_holder_broadcastable() ); assert_eq!(tx.built.transaction.output.len(), 5); - assert_eq!(tx.built.transaction.output[2].script_pubkey, get_htlc_redeemscript(&received_htlc, true, &keys).to_v0_p2wsh()); - assert_eq!(tx.built.transaction.output[3].script_pubkey, get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh()); - assert_eq!(get_htlc_redeemscript(&received_htlc, true, &keys).to_v0_p2wsh().to_hex(), + assert_eq!(tx.built.transaction.output[2].script_pubkey, get_htlc_redeemscript(&received_htlc, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), &keys).to_v0_p2wsh()); + assert_eq!(tx.built.transaction.output[3].script_pubkey, get_htlc_redeemscript(&offered_htlc, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), &keys).to_v0_p2wsh()); + assert_eq!(get_htlc_redeemscript(&received_htlc, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), &keys).to_v0_p2wsh().to_hex(), "0020b70d0649c72b38756885c7a30908d912a7898dd5d79457a7280b8e9a20f3f2bc"); - assert_eq!(get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh().to_hex(), + assert_eq!(get_htlc_redeemscript(&offered_htlc, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), &keys).to_v0_p2wsh().to_hex(), "002087a3faeb1950a469c0e2db4a79b093a41b9526e5a6fc6ef5cb949bde3be379c7"); }