X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchan_utils.rs;h=408f1cd7e477ca3eb0e4acde601cde9eb0c908f1;hb=5e14c24a11f610ab8c402f788ec5bd637e9e24af;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..408f1cd7 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -24,11 +24,10 @@ use bitcoin::hash_types::{Txid, PubkeyHash}; 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::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; @@ -310,7 +309,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 +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. @@ -364,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); @@ -386,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 @@ -402,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()); @@ -418,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. @@ -459,7 +462,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 +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, @@ -676,7 +679,24 @@ pub fn make_funding_redeemscript(broadcaster: &PublicKey, countersignatory: &Pub /// 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 { let mut txins: Vec = Vec::new(); - txins.push(TxIn { + txins.push(build_htlc_input(commitment_txid, htlc, opt_anchors)); + + let mut txouts: Vec = Vec::new(); + txouts.push(build_htlc_output( + feerate_per_kw, contest_delay, htlc, opt_anchors, use_non_zero_fee_anchors, + 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, opt_anchors: bool) -> 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"), @@ -684,8 +704,13 @@ pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, conte script_sig: Script::new(), sequence: Sequence(if opt_anchors { 1 } else { 0 }), witness: Witness::new(), - }); + } +} +pub(crate) fn build_htlc_output( + 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 +) -> TxOut { let weight = if htlc.offered { htlc_timeout_tx_weight(opt_anchors) } else { @@ -698,18 +723,36 @@ pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, conte 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, opt_anchors: bool, +) -> Witness { + let remote_sighash_type = if opt_anchors { + 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 } /// Gets the witnessScript for the to_remote output when anchors are enabled. @@ -753,9 +796,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 +807,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)] pub struct ChannelTransactionParameters { /// Holder public keys pub holder_pubkeys: ChannelPublicKeys, @@ -787,7 +831,7 @@ pub struct ChannelTransactionParameters { } /// Late-bound per-channel counterparty data used to build transactions. -#[derive(Clone, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct CounterpartyChannelTransactionParameters { /// Counter-party public keys pub pubkeys: ChannelPublicKeys, @@ -989,17 +1033,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()); @@ -1460,7 +1500,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(()); } @@ -1520,7 +1560,7 @@ 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()); @@ -1550,26 +1590,9 @@ impl<'a> TrustedCommitmentTransaction<'a> { 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 sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; - - // 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.opt_anchors(), + ); htlc_tx } } @@ -1635,7 +1658,7 @@ 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,