2020-08-10 15:00:09 -04:00
// This file is Copyright its original authors, visible in version control
// history.
//
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
// You may not use this file except in accordance with one or both of these
// licenses.
2020-10-15 13:45:18 +02:00
use ln ::chan_utils ::{ HTLCOutputInCommitment , ChannelPublicKeys , HolderCommitmentTransaction , CommitmentTransaction , ChannelTransactionParameters , TrustedCommitmentTransaction } ;
Batch-sign local HTLC txn with a well-doc'd API, returning sigs
1107ab06c33bd360bdee7ee64f4b690e753003f6 introduced an API to have a
ChannelKeys implementer sign HTLC transactions by calling into the
LocalCommitmentTransaction object, which would then store the tx.
This API was incredibly awkward, both because it required an
external signer trust our own internal interfaces, but also because
it didn't allow for any inspection of what was about to be signed.
Further, it signed the HTLC transactions one-by-one in a somewhat
inefficient way, and there isn't a clear way to resolve this (as
the which-HTLC parameter has to refer to something in between the
HTLC's arbitrary index, and its index in the commitment tx, which
has "holes" for the non-HTLC outputs and skips some HTLCs).
We replace it with a new function in ChannelKeys which allows us
to sign all HTLCs in a given commitment transaction (which allows
for a bit more effeciency on the signers' part, as well as
sidesteps the which-HTLC issue). This may also simplify the signer
implementation as we will always want to sign all HTLCs spending a
given commitment transaction at once anyway.
We also de-mut the LocalCommitmentTransaction passed to the
ChanKeys, instead opting to make LocalCommitmentTransaction const
and avoid storing any new HTLC-related data in it.
2020-04-19 22:59:53 -04:00
use ln ::{ chan_utils , msgs } ;
2019-11-26 16:46:33 -05:00
use chain ::keysinterface ::{ ChannelKeys , InMemoryChannelKeys } ;
2019-11-27 16:08:48 -05:00
use std ::cmp ;
2020-02-04 09:15:59 -08:00
use std ::sync ::{ Mutex , Arc } ;
2019-11-27 16:08:48 -05:00
2020-08-25 18:47:24 -04:00
use bitcoin ::blockdata ::transaction ::{ Transaction , SigHashType } ;
Batch-sign local HTLC txn with a well-doc'd API, returning sigs
1107ab06c33bd360bdee7ee64f4b690e753003f6 introduced an API to have a
ChannelKeys implementer sign HTLC transactions by calling into the
LocalCommitmentTransaction object, which would then store the tx.
This API was incredibly awkward, both because it required an
external signer trust our own internal interfaces, but also because
it didn't allow for any inspection of what was about to be signed.
Further, it signed the HTLC transactions one-by-one in a somewhat
inefficient way, and there isn't a clear way to resolve this (as
the which-HTLC parameter has to refer to something in between the
HTLC's arbitrary index, and its index in the commitment tx, which
has "holes" for the non-HTLC outputs and skips some HTLCs).
We replace it with a new function in ChannelKeys which allows us
to sign all HTLCs in a given commitment transaction (which allows
for a bit more effeciency on the signers' part, as well as
sidesteps the which-HTLC issue). This may also simplify the signer
implementation as we will always want to sign all HTLCs spending a
given commitment transaction at once anyway.
We also de-mut the LocalCommitmentTransaction passed to the
ChanKeys, instead opting to make LocalCommitmentTransaction const
and avoid storing any new HTLC-related data in it.
2020-04-19 22:59:53 -04:00
use bitcoin ::util ::bip143 ;
2019-11-27 16:08:48 -05:00
2020-04-27 16:51:59 +02:00
use bitcoin ::secp256k1 ;
use bitcoin ::secp256k1 ::key ::{ SecretKey , PublicKey } ;
use bitcoin ::secp256k1 ::{ Secp256k1 , Signature } ;
2020-02-04 09:15:59 -08:00
use util ::ser ::{ Writeable , Writer , Readable } ;
use std ::io ::Error ;
use ln ::msgs ::DecodeError ;
2019-11-26 16:46:33 -05:00
2020-10-15 13:45:18 +02:00
/// An implementation of ChannelKeys that enforces some policy checks.
///
/// Eventually we will probably want to expose a variant of this which would essentially
/// be what you'd want to run on a hardware wallet.
2020-02-04 09:15:59 -08:00
#[ derive(Clone) ]
2019-11-26 16:46:33 -05:00
pub struct EnforcingChannelKeys {
pub inner : InMemoryChannelKeys ,
2020-10-15 13:45:18 +02:00
last_commitment_number : Arc < Mutex < Option < u64 > > > ,
2019-11-26 16:46:33 -05:00
}
impl EnforcingChannelKeys {
pub fn new ( inner : InMemoryChannelKeys ) -> Self {
Self {
inner ,
2020-10-15 13:45:18 +02:00
last_commitment_number : Arc ::new ( Mutex ::new ( None ) ) ,
2019-11-26 16:46:33 -05:00
}
}
}
2020-01-16 16:51:15 -08:00
2019-11-26 16:46:33 -05:00
impl ChannelKeys for EnforcingChannelKeys {
2020-07-11 03:19:43 -07:00
fn get_per_commitment_point < T : secp256k1 ::Signing + secp256k1 ::Verification > ( & self , idx : u64 , secp_ctx : & Secp256k1 < T > ) -> PublicKey {
self . inner . get_per_commitment_point ( idx , secp_ctx )
}
fn release_commitment_secret ( & self , idx : u64 ) -> [ u8 ; 32 ] {
// TODO: enforce the ChannelKeys contract - error here if we already signed this commitment
self . inner . release_commitment_secret ( idx )
}
2020-05-30 23:18:35 -04:00
fn pubkeys ( & self ) -> & ChannelPublicKeys { self . inner . pubkeys ( ) }
2020-05-05 20:00:01 -04:00
fn key_derivation_params ( & self ) -> ( u64 , u64 ) { self . inner . key_derivation_params ( ) }
2019-11-27 16:08:48 -05:00
2020-10-15 13:45:18 +02:00
fn sign_counterparty_commitment < T : secp256k1 ::Signing + secp256k1 ::Verification > ( & self , commitment_tx : & CommitmentTransaction , secp_ctx : & Secp256k1 < T > ) -> Result < ( Signature , Vec < Signature > ) , ( ) > {
self . verify_counterparty_commitment_tx ( commitment_tx , secp_ctx ) ;
2019-11-27 16:08:48 -05:00
{
2020-10-15 13:45:18 +02:00
let mut last_commitment_number_guard = self . last_commitment_number . lock ( ) . unwrap ( ) ;
let actual_commitment_number = commitment_tx . commitment_number ( ) ;
let last_commitment_number = last_commitment_number_guard . unwrap_or ( actual_commitment_number ) ;
// These commitment numbers are backwards counting. We expect either the same as the previously encountered,
// or the next one.
assert! ( last_commitment_number = = actual_commitment_number | | last_commitment_number - 1 = = actual_commitment_number , " {} doesn't come after {} " , actual_commitment_number , last_commitment_number ) ;
* last_commitment_number_guard = Some ( cmp ::min ( last_commitment_number , actual_commitment_number ) )
2019-11-27 16:08:48 -05:00
}
2020-10-15 13:45:18 +02:00
Ok ( self . inner . sign_counterparty_commitment ( commitment_tx , secp_ctx ) . unwrap ( ) )
2019-11-27 16:08:48 -05:00
}
2019-12-07 17:54:55 -05:00
2020-10-15 13:45:18 +02:00
fn sign_holder_commitment < T : secp256k1 ::Signing + secp256k1 ::Verification > ( & self , commitment_tx : & HolderCommitmentTransaction , secp_ctx : & Secp256k1 < T > ) -> Result < Signature , ( ) > {
self . verify_holder_commitment_tx ( commitment_tx , secp_ctx ) ;
2020-07-11 03:19:43 -07:00
// TODO: enforce the ChannelKeys contract - error if this commitment was already revoked
// TODO: need the commitment number
2020-10-15 13:45:18 +02:00
Ok ( self . inner . sign_holder_commitment ( commitment_tx , secp_ctx ) . unwrap ( ) )
2020-03-20 18:04:01 -04:00
}
2020-07-03 13:41:21 -07:00
#[ cfg(any(test,feature = " unsafe_revoked_tx_signing " )) ]
2020-10-15 13:45:18 +02:00
fn unsafe_sign_holder_commitment < T : secp256k1 ::Signing + secp256k1 ::Verification > ( & self , commitment_tx : & HolderCommitmentTransaction , secp_ctx : & Secp256k1 < T > ) -> Result < Signature , ( ) > {
Ok ( self . inner . unsafe_sign_holder_commitment ( commitment_tx , secp_ctx ) . unwrap ( ) )
2020-03-20 18:04:01 -04:00
}
2020-10-15 13:45:18 +02:00
fn sign_holder_commitment_htlc_transactions < T : secp256k1 ::Signing + secp256k1 ::Verification > ( & self , commitment_tx : & HolderCommitmentTransaction , secp_ctx : & Secp256k1 < T > ) -> Result < Vec < Signature > , ( ) > {
let trusted_tx = self . verify_holder_commitment_tx ( commitment_tx , secp_ctx ) ;
let commitment_txid = trusted_tx . txid ( ) ;
2020-09-06 20:07:11 -04:00
let holder_csv = self . inner . counterparty_selected_contest_delay ( ) ;
Batch-sign local HTLC txn with a well-doc'd API, returning sigs
1107ab06c33bd360bdee7ee64f4b690e753003f6 introduced an API to have a
ChannelKeys implementer sign HTLC transactions by calling into the
LocalCommitmentTransaction object, which would then store the tx.
This API was incredibly awkward, both because it required an
external signer trust our own internal interfaces, but also because
it didn't allow for any inspection of what was about to be signed.
Further, it signed the HTLC transactions one-by-one in a somewhat
inefficient way, and there isn't a clear way to resolve this (as
the which-HTLC parameter has to refer to something in between the
HTLC's arbitrary index, and its index in the commitment tx, which
has "holes" for the non-HTLC outputs and skips some HTLCs).
We replace it with a new function in ChannelKeys which allows us
to sign all HTLCs in a given commitment transaction (which allows
for a bit more effeciency on the signers' part, as well as
sidesteps the which-HTLC issue). This may also simplify the signer
implementation as we will always want to sign all HTLCs spending a
given commitment transaction at once anyway.
We also de-mut the LocalCommitmentTransaction passed to the
ChanKeys, instead opting to make LocalCommitmentTransaction const
and avoid storing any new HTLC-related data in it.
2020-04-19 22:59:53 -04:00
2020-10-15 13:45:18 +02:00
for ( this_htlc , sig ) in trusted_tx . htlcs ( ) . iter ( ) . zip ( & commitment_tx . counterparty_htlc_sigs ) {
assert! ( this_htlc . transaction_output_index . is_some ( ) ) ;
let keys = trusted_tx . keys ( ) ;
let htlc_tx = chan_utils ::build_htlc_transaction ( & commitment_txid , trusted_tx . feerate_per_kw ( ) , holder_csv , & this_htlc , & keys . broadcaster_delayed_payment_key , & keys . revocation_key ) ;
Batch-sign local HTLC txn with a well-doc'd API, returning sigs
1107ab06c33bd360bdee7ee64f4b690e753003f6 introduced an API to have a
ChannelKeys implementer sign HTLC transactions by calling into the
LocalCommitmentTransaction object, which would then store the tx.
This API was incredibly awkward, both because it required an
external signer trust our own internal interfaces, but also because
it didn't allow for any inspection of what was about to be signed.
Further, it signed the HTLC transactions one-by-one in a somewhat
inefficient way, and there isn't a clear way to resolve this (as
the which-HTLC parameter has to refer to something in between the
HTLC's arbitrary index, and its index in the commitment tx, which
has "holes" for the non-HTLC outputs and skips some HTLCs).
We replace it with a new function in ChannelKeys which allows us
to sign all HTLCs in a given commitment transaction (which allows
for a bit more effeciency on the signers' part, as well as
sidesteps the which-HTLC issue). This may also simplify the signer
implementation as we will always want to sign all HTLCs spending a
given commitment transaction at once anyway.
We also de-mut the LocalCommitmentTransaction passed to the
ChanKeys, instead opting to make LocalCommitmentTransaction const
and avoid storing any new HTLC-related data in it.
2020-04-19 22:59:53 -04:00
2020-10-15 13:45:18 +02:00
let htlc_redeemscript = chan_utils ::get_htlc_redeemscript ( & this_htlc , & keys ) ;
Batch-sign local HTLC txn with a well-doc'd API, returning sigs
1107ab06c33bd360bdee7ee64f4b690e753003f6 introduced an API to have a
ChannelKeys implementer sign HTLC transactions by calling into the
LocalCommitmentTransaction object, which would then store the tx.
This API was incredibly awkward, both because it required an
external signer trust our own internal interfaces, but also because
it didn't allow for any inspection of what was about to be signed.
Further, it signed the HTLC transactions one-by-one in a somewhat
inefficient way, and there isn't a clear way to resolve this (as
the which-HTLC parameter has to refer to something in between the
HTLC's arbitrary index, and its index in the commitment tx, which
has "holes" for the non-HTLC outputs and skips some HTLCs).
We replace it with a new function in ChannelKeys which allows us
to sign all HTLCs in a given commitment transaction (which allows
for a bit more effeciency on the signers' part, as well as
sidesteps the which-HTLC issue). This may also simplify the signer
implementation as we will always want to sign all HTLCs spending a
given commitment transaction at once anyway.
We also de-mut the LocalCommitmentTransaction passed to the
ChanKeys, instead opting to make LocalCommitmentTransaction const
and avoid storing any new HTLC-related data in it.
2020-04-19 22:59:53 -04:00
2020-10-15 13:45:18 +02:00
let sighash = hash_to_message! ( & bip143 ::SigHashCache ::new ( & htlc_tx ) . signature_hash ( 0 , & htlc_redeemscript , this_htlc . amount_msat / 1000 , SigHashType ::All ) [ .. ] ) ;
secp_ctx . verify ( & sighash , sig , & keys . countersignatory_htlc_key ) . unwrap ( ) ;
Batch-sign local HTLC txn with a well-doc'd API, returning sigs
1107ab06c33bd360bdee7ee64f4b690e753003f6 introduced an API to have a
ChannelKeys implementer sign HTLC transactions by calling into the
LocalCommitmentTransaction object, which would then store the tx.
This API was incredibly awkward, both because it required an
external signer trust our own internal interfaces, but also because
it didn't allow for any inspection of what was about to be signed.
Further, it signed the HTLC transactions one-by-one in a somewhat
inefficient way, and there isn't a clear way to resolve this (as
the which-HTLC parameter has to refer to something in between the
HTLC's arbitrary index, and its index in the commitment tx, which
has "holes" for the non-HTLC outputs and skips some HTLCs).
We replace it with a new function in ChannelKeys which allows us
to sign all HTLCs in a given commitment transaction (which allows
for a bit more effeciency on the signers' part, as well as
sidesteps the which-HTLC issue). This may also simplify the signer
implementation as we will always want to sign all HTLCs spending a
given commitment transaction at once anyway.
We also de-mut the LocalCommitmentTransaction passed to the
ChanKeys, instead opting to make LocalCommitmentTransaction const
and avoid storing any new HTLC-related data in it.
2020-04-19 22:59:53 -04:00
}
2020-10-15 13:45:18 +02:00
Ok ( self . inner . sign_holder_commitment_htlc_transactions ( commitment_tx , secp_ctx ) . unwrap ( ) )
2020-03-21 15:39:19 -04:00
}
2020-07-23 06:54:49 -07:00
fn sign_justice_transaction < T : secp256k1 ::Signing + secp256k1 ::Verification > ( & self , justice_tx : & Transaction , input : usize , amount : u64 , per_commitment_key : & SecretKey , htlc : & Option < HTLCOutputInCommitment > , secp_ctx : & Secp256k1 < T > ) -> Result < Signature , ( ) > {
Ok ( self . inner . sign_justice_transaction ( justice_tx , input , amount , per_commitment_key , htlc , secp_ctx ) . unwrap ( ) )
2020-03-24 14:22:16 -04:00
}
2020-08-31 15:31:19 -04:00
fn sign_counterparty_htlc_transaction < T : secp256k1 ::Signing + secp256k1 ::Verification > ( & self , htlc_tx : & Transaction , input : usize , amount : u64 , per_commitment_point : & PublicKey , htlc : & HTLCOutputInCommitment , secp_ctx : & Secp256k1 < T > ) -> Result < Signature , ( ) > {
Ok ( self . inner . sign_counterparty_htlc_transaction ( htlc_tx , input , amount , per_commitment_point , htlc , secp_ctx ) . unwrap ( ) )
2020-03-24 15:04:36 -04:00
}
2020-01-23 14:32:29 -08:00
fn sign_closing_transaction < T : secp256k1 ::Signing > ( & self , closing_tx : & Transaction , secp_ctx : & Secp256k1 < T > ) -> Result < Signature , ( ) > {
Ok ( self . inner . sign_closing_transaction ( closing_tx , secp_ctx ) . unwrap ( ) )
2019-12-13 01:57:45 -05:00
}
2019-12-07 17:54:55 -05:00
fn sign_channel_announcement < T : secp256k1 ::Signing > ( & self , msg : & msgs ::UnsignedChannelAnnouncement , secp_ctx : & Secp256k1 < T > ) -> Result < Signature , ( ) > {
self . inner . sign_channel_announcement ( msg , secp_ctx )
}
2020-01-09 17:28:48 -08:00
2020-10-15 13:45:18 +02:00
fn ready_channel ( & mut self , channel_parameters : & ChannelTransactionParameters ) {
self . inner . ready_channel ( channel_parameters )
2020-01-09 17:28:48 -08:00
}
2019-11-26 16:46:33 -05:00
}
2020-10-15 13:45:18 +02:00
2020-02-04 09:15:59 -08:00
impl Writeable for EnforcingChannelKeys {
fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , Error > {
self . inner . write ( writer ) ? ;
2020-10-15 13:45:18 +02:00
let last = * self . last_commitment_number . lock ( ) . unwrap ( ) ;
2020-02-04 09:15:59 -08:00
last . write ( writer ) ? ;
Ok ( ( ) )
}
}
2020-01-16 16:51:15 -08:00
2020-02-23 23:12:19 -05:00
impl Readable for EnforcingChannelKeys {
fn read < R : ::std ::io ::Read > ( reader : & mut R ) -> Result < Self , DecodeError > {
2020-02-04 09:15:59 -08:00
let inner = Readable ::read ( reader ) ? ;
2020-10-15 13:45:18 +02:00
let last_commitment_number = Readable ::read ( reader ) ? ;
2020-02-04 09:15:59 -08:00
Ok ( EnforcingChannelKeys {
2020-10-15 13:45:18 +02:00
inner ,
last_commitment_number : Arc ::new ( Mutex ::new ( last_commitment_number ) )
2020-02-04 09:15:59 -08:00
} )
}
}
2020-10-15 13:45:18 +02:00
impl EnforcingChannelKeys {
fn verify_counterparty_commitment_tx < ' a , T : secp256k1 ::Signing + secp256k1 ::Verification > ( & self , commitment_tx : & ' a CommitmentTransaction , secp_ctx : & Secp256k1 < T > ) -> TrustedCommitmentTransaction < ' a > {
commitment_tx . verify ( & self . inner . get_channel_parameters ( ) . as_counterparty_broadcastable ( ) ,
self . inner . counterparty_pubkeys ( ) , self . inner . pubkeys ( ) , secp_ctx )
. expect ( " derived different per-tx keys or built transaction " )
}
fn verify_holder_commitment_tx < ' a , T : secp256k1 ::Signing + secp256k1 ::Verification > ( & self , commitment_tx : & ' a CommitmentTransaction , secp_ctx : & Secp256k1 < T > ) -> TrustedCommitmentTransaction < ' a > {
commitment_tx . verify ( & self . inner . get_channel_parameters ( ) . as_holder_broadcastable ( ) ,
self . inner . pubkeys ( ) , self . inner . counterparty_pubkeys ( ) , secp_ctx )
. expect ( " derived different per-tx keys or built transaction " )
}
}