X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchan_utils.rs;h=c5e36e2d0ceef192094f356cbb1e434fe2868bb7;hb=9d8efecadf4d5f966223b352ffc0a65a8fdfd263;hp=9be3f38a78e6c027c7328a6d5e6c35e69013c8bd;hpb=ea4ccf63c7b8a8af5107c536bb6ab01ee04cbdc4;p=rust-lightning diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 9be3f38a..c5e36e2d 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -1,3 +1,12 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + //! Various utilities for building scripts and deriving keys related to channels. These are //! largely of interest for those implementing chain::keysinterface::ChannelKeys message signing //! by hand. @@ -5,7 +14,8 @@ use bitcoin::blockdata::script::{Script,Builder}; use bitcoin::blockdata::opcodes; use bitcoin::blockdata::transaction::{TxIn,TxOut,OutPoint,Transaction, SigHashType}; -use bitcoin::consensus::encode::{self, Decodable, Encodable}; +use bitcoin::consensus::encode::{Decodable, Encodable}; +use bitcoin::consensus::encode; use bitcoin::util::bip143; use bitcoin::hashes::{Hash, HashEngine}; @@ -20,6 +30,7 @@ use util::byte_utils; use bitcoin::secp256k1::key::{SecretKey, PublicKey}; use bitcoin::secp256k1::{Secp256k1, Signature}; +use bitcoin::secp256k1::Error as SecpError; use bitcoin::secp256k1; use std::{cmp, mem}; @@ -51,7 +62,8 @@ impl HTLCType { // Various functions for key derivation and transaction creation for use within channels. Primarily // used in Channel and ChannelMonitor. -pub(super) fn build_commitment_secret(commitment_seed: &[u8; 32], idx: u64) -> [u8; 32] { +/// Build the commitment secret from the seed and the commitment number +pub fn build_commitment_secret(commitment_seed: &[u8; 32], idx: u64) -> [u8; 32] { let mut res: [u8; 32] = commitment_seed.clone(); for i in 0..48 { let bitpos = 47 - i; @@ -171,8 +183,11 @@ impl Readable for CounterpartyCommitmentSecrets { } } -/// Derives a per-commitment-transaction private key (eg an htlc key or payment key) from the base -/// private key for that type of key and the per_commitment_point (available in TxCreationKeys) +/// 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 { let mut sha = Sha256::engine(); sha.input(&per_commitment_point.serialize()); @@ -184,7 +199,13 @@ pub fn derive_private_key(secp_ctx: &Secp256k1, per_co Ok(key) } -pub(super) fn derive_public_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, base_point: &PublicKey) -> Result { +/// 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 { let mut sha = Sha256::engine(); sha.input(&per_commitment_point.serialize()); sha.input(&base_point.serialize()); @@ -194,10 +215,11 @@ pub(super) fn derive_public_key(secp_ctx: &Secp256k1, base_point.combine(&hashkey) } -/// Derives a revocation key from its constituent parts. +/// Derives a per-commitment-transaction revocation key from its constituent parts. +/// /// Note that this is infallible iff we trust that at least one of the two input keys are randomly /// generated (ie our own). -pub(super) fn derive_private_revocation_key(secp_ctx: &Secp256k1, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result { +pub fn derive_private_revocation_key(secp_ctx: &Secp256k1, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result { let revocation_base_point = PublicKey::from_secret_key(&secp_ctx, &revocation_base_secret); let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret); @@ -224,7 +246,13 @@ pub(super) fn derive_private_revocation_key(secp_ctx: &Se Ok(part_a) } -pub(super) fn derive_public_revocation_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, revocation_base_point: &PublicKey) -> Result { +/// Derives a per-commitment-transaction revocation public key from its constituent parts. This is +/// the public equivalend of derive_private_revocation_key - using only public keys to derive a +/// public key instead of private keys. +/// +/// 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, revocation_base_point: &PublicKey) -> Result { let rev_append_commit_hash_key = { let mut sha = Sha256::engine(); sha.input(&revocation_base_point.serialize()); @@ -249,24 +277,51 @@ pub(super) fn derive_public_revocation_key(secp_ctx: /// The set of public keys which are used in the creation of one commitment transaction. /// These are derived from the channel base keys and per-commitment data. +/// +/// These keys are assumed to be good, either because the code derived them from +/// channel basepoints via the new function, or they were obtained via +/// PreCalculatedTxCreationKeys.trust_key_derivation because we trusted the source of the +/// pre-calculated keys. #[derive(PartialEq, Clone)] pub struct TxCreationKeys { /// The per-commitment public key which was used to derive the other keys. pub per_commitment_point: PublicKey, /// The revocation key which is used to allow the owner of the commitment transaction to /// provide their counterparty the ability to punish them if they broadcast an old state. - pub(crate) revocation_key: PublicKey, + pub revocation_key: PublicKey, /// A's HTLC Key - pub(crate) a_htlc_key: PublicKey, + pub a_htlc_key: PublicKey, /// B's HTLC Key - pub(crate) b_htlc_key: PublicKey, + pub b_htlc_key: PublicKey, /// A's Payment Key (which isn't allowed to be spent from for some delay) - pub(crate) a_delayed_payment_key: PublicKey, - /// B's Payment Key - pub(crate) b_payment_key: PublicKey, + pub a_delayed_payment_key: PublicKey, } impl_writeable!(TxCreationKeys, 33*6, - { per_commitment_point, revocation_key, a_htlc_key, b_htlc_key, a_delayed_payment_key, b_payment_key }); + { per_commitment_point, revocation_key, a_htlc_key, b_htlc_key, a_delayed_payment_key }); + +/// The per-commitment point and a set of pre-calculated public keys used for transaction creation +/// in the signer. +/// The pre-calculated keys are an optimization, because ChannelKeys has enough +/// information to re-derive them. +pub struct PreCalculatedTxCreationKeys(TxCreationKeys); + +impl PreCalculatedTxCreationKeys { + /// Create a new PreCalculatedTxCreationKeys from TxCreationKeys + pub fn new(keys: TxCreationKeys) -> Self { + PreCalculatedTxCreationKeys(keys) + } + + /// The pre-calculated transaction creation public keys. + /// An external validating signer should not trust these keys. + pub fn trust_key_derivation(&self) -> &TxCreationKeys { + &self.0 + } + + /// The transaction per-commitment point + pub fn per_commitment_point(&self) -> &PublicKey { + &self.0.per_commitment_point + } +} /// One counterparty's public keys which do not change over the life of a channel. #[derive(Clone, PartialEq)] @@ -275,13 +330,14 @@ pub struct ChannelPublicKeys { /// on-chain channel lock-in 2-of-2 multisig output. pub funding_pubkey: PublicKey, /// The base point which is used (with derive_public_revocation_key) to derive per-commitment - /// revocation keys. The per-commitment revocation private key is then revealed by the owner of - /// a commitment transaction so that their counterparty can claim all available funds if they - /// broadcast an old state. + /// revocation keys. This is combined with the per-commitment-secret generated by the + /// counterparty to create a secret which the counterparty can reveal to revoke previous + /// states. pub revocation_basepoint: PublicKey, - /// The base point which is used (with derive_public_key) to derive a per-commitment payment - /// public key which receives immediately-spendable non-HTLC-encumbered funds. - pub payment_basepoint: PublicKey, + /// The public key which receives our immediately spendable primary channel balance in + /// remote-broadcasted commitment transactions. This key is static across every commitment + /// transaction. + pub payment_point: PublicKey, /// The base point which is used (with derive_public_key) to derive a per-commitment payment /// public key which receives non-HTLC-encumbered funds which are only available for spending /// after some delay (or can be claimed via the revocation path). @@ -294,28 +350,29 @@ pub struct ChannelPublicKeys { impl_writeable!(ChannelPublicKeys, 33*5, { funding_pubkey, revocation_basepoint, - payment_basepoint, + payment_point, delayed_payment_basepoint, htlc_basepoint }); impl TxCreationKeys { - pub(crate) fn new(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, a_delayed_payment_base: &PublicKey, a_htlc_base: &PublicKey, b_revocation_base: &PublicKey, b_payment_base: &PublicKey, b_htlc_base: &PublicKey) -> Result { + /// Create a new TxCreationKeys from channel base points and the per-commitment point + pub fn derive_new(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, a_delayed_payment_base: &PublicKey, a_htlc_base: &PublicKey, b_revocation_base: &PublicKey, b_htlc_base: &PublicKey) -> Result { Ok(TxCreationKeys { per_commitment_point: per_commitment_point.clone(), revocation_key: derive_public_revocation_key(&secp_ctx, &per_commitment_point, &b_revocation_base)?, a_htlc_key: derive_public_key(&secp_ctx, &per_commitment_point, &a_htlc_base)?, b_htlc_key: derive_public_key(&secp_ctx, &per_commitment_point, &b_htlc_base)?, a_delayed_payment_key: derive_public_key(&secp_ctx, &per_commitment_point, &a_delayed_payment_base)?, - b_payment_key: derive_public_key(&secp_ctx, &per_commitment_point, &b_payment_base)?, }) } } -/// Gets the "to_local" output redeemscript, ie the script which is time-locked or spendable by -/// the revocation key -pub(super) fn get_revokeable_redeemscript(revocation_key: &PublicKey, to_self_delay: u16, delayed_payment_key: &PublicKey) -> Script { +/// A script either spendable by the revocation +/// key or the delayed_payment_key and satisfying the relative-locktime OP_CSV constrain. +/// Encumbering a `to_local` output on a commitment transaction or 2nd-stage HTLC transactions. +pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, to_self_delay: u16, delayed_payment_key: &PublicKey) -> Script { Builder::new().push_opcode(opcodes::all::OP_IF) .push_slice(&revocation_key.serialize()) .push_opcode(opcodes::all::OP_ELSE) @@ -446,7 +503,7 @@ pub fn make_funding_redeemscript(a: &PublicKey, b: &PublicKey) -> Script { } /// panics if htlc.transaction_output_index.is_none()! -pub fn build_htlc_transaction(prev_hash: &Txid, feerate_per_kw: u64, to_self_delay: u16, htlc: &HTLCOutputInCommitment, a_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction { +pub fn build_htlc_transaction(prev_hash: &Txid, feerate_per_kw: u32, to_self_delay: u16, htlc: &HTLCOutputInCommitment, a_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction { let mut txins: Vec = Vec::new(); txins.push(TxIn { previous_output: OutPoint { @@ -459,9 +516,9 @@ pub fn build_htlc_transaction(prev_hash: &Txid, feerate_per_kw: u64, to_self_del }); let total_fee = if htlc.offered { - feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000 + feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000 } else { - feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000 + feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000 }; let mut txouts: Vec = Vec::new(); @@ -480,8 +537,8 @@ pub fn build_htlc_transaction(prev_hash: &Txid, feerate_per_kw: u64, to_self_del #[derive(Clone)] /// We use this to track local commitment transactions and put off signing them until we are ready -/// to broadcast. Eventually this will require a signer which is possibly external, but for now we -/// just pass in the SecretKeys required. +/// to broadcast. This class can be used inside a signer implementation to generate a signature +/// given the relevant secret key. pub struct LocalCommitmentTransaction { // TODO: We should migrate away from providing the transaction, instead providing enough to // allow the ChannelKeys to construct it from scratch. Luckily we already have HTLC data here, @@ -493,11 +550,10 @@ pub struct LocalCommitmentTransaction { // Which order the signatures should go in when constructing the final commitment tx witness. // The user should be able to reconstruc this themselves, so we don't bother to expose it. our_sig_first: bool, - /// The key derivation parameters for this commitment transaction - pub local_keys: TxCreationKeys, + pub(crate) local_keys: TxCreationKeys, /// The feerate paid per 1000-weight-unit in this commitment transaction. This value is /// controlled by the channel initiator. - pub feerate_per_kw: u64, + pub feerate_per_kw: u32, /// The HTLCs and remote htlc signatures which were included in this commitment transaction. /// /// Note that this includes all HTLCs, including ones which were considered dust and not @@ -537,7 +593,6 @@ impl LocalCommitmentTransaction { a_htlc_key: dummy_key.clone(), b_htlc_key: dummy_key.clone(), a_delayed_payment_key: dummy_key.clone(), - b_payment_key: dummy_key.clone(), }, feerate_per_kw: 0, per_htlc: Vec::new() @@ -545,11 +600,26 @@ impl LocalCommitmentTransaction { } /// Generate a new LocalCommitmentTransaction based on a raw commitment transaction, - /// remote signature and both parties keys - pub(crate) fn new_missing_local_sig(unsigned_tx: Transaction, their_sig: Signature, our_funding_key: &PublicKey, their_funding_key: &PublicKey, local_keys: TxCreationKeys, feerate_per_kw: u64, htlc_data: Vec<(HTLCOutputInCommitment, Option)>) -> LocalCommitmentTransaction { + /// remote signature and both parties keys. + /// + /// The unsigned transaction outputs must be consistent with htlc_data. This function + /// only checks that the shape and amounts are consistent, but does not check the scriptPubkey. + pub fn new_missing_local_sig(unsigned_tx: Transaction, their_sig: Signature, our_funding_key: &PublicKey, their_funding_key: &PublicKey, local_keys: TxCreationKeys, feerate_per_kw: u32, htlc_data: Vec<(HTLCOutputInCommitment, Option)>) -> LocalCommitmentTransaction { if unsigned_tx.input.len() != 1 { panic!("Tried to store a commitment transaction that had input count != 1!"); } if unsigned_tx.input[0].witness.len() != 0 { panic!("Tried to store a signed commitment transaction?"); } + for htlc in &htlc_data { + if let Some(index) = htlc.0.transaction_output_index { + let out = &unsigned_tx.output[index as usize]; + if out.value != htlc.0.amount_msat / 1000 { + panic!("HTLC at index {} has incorrect amount", index); + } + if !out.script_pubkey.is_v0_p2wsh() { + panic!("HTLC at index {} doesn't have p2wsh scriptPubkey", index); + } + } + } + Self { unsigned_tx, their_sig, @@ -560,6 +630,12 @@ impl LocalCommitmentTransaction { } } + /// The pre-calculated transaction creation public keys. + /// An external validating signer should not trust these keys. + pub fn trust_key_derivation(&self) -> &TxCreationKeys { + &self.local_keys + } + /// Get the txid of the local commitment transaction contained in this /// LocalCommitmentTransaction pub fn txid(&self) -> Txid { @@ -575,8 +651,8 @@ impl LocalCommitmentTransaction { /// ChannelKeys::sign_local_commitment() calls directly. /// Channel value is amount locked in funding_outpoint. pub fn get_local_sig(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1) -> Signature { - let sighash = hash_to_message!(&bip143::SighashComponents::new(&self.unsigned_tx) - .sighash_all(&self.unsigned_tx.input[0], funding_redeemscript, channel_value_satoshis)[..]); + let sighash = hash_to_message!(&bip143::SigHashCache::new(&self.unsigned_tx) + .signature_hash(0, funding_redeemscript, channel_value_satoshis, SigHashType::All)[..]); secp_ctx.sign(&sighash, funding_key) } @@ -616,7 +692,7 @@ impl LocalCommitmentTransaction { let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc.0, &self.local_keys.a_htlc_key, &self.local_keys.b_htlc_key, &self.local_keys.revocation_key); - let sighash = hash_to_message!(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, this_htlc.0.amount_msat / 1000)[..]); + let sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, this_htlc.0.amount_msat / 1000, SigHashType::All)[..]); ret.push(Some(secp_ctx.sign(&sighash, &our_htlc_key))); } else { ret.push(None);