use bitcoin::secp256k1::key::{SecretKey, PublicKey};
use bitcoin::secp256k1::{Secp256k1, Signature};
+use bitcoin::secp256k1::Error as SecpError;
use bitcoin::secp256k1;
use std::{cmp, mem};
///
/// 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<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, base_secret: &SecretKey) -> Result<SecretKey, secp256k1::Error> {
+pub fn derive_private_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, base_secret: &SecretKey) -> Result<SecretKey, SecpError> {
let mut sha = Sha256::engine();
sha.input(&per_commitment_point.serialize());
sha.input(&PublicKey::from_secret_key(&secp_ctx, &base_secret).serialize());
///
/// 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<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, base_point: &PublicKey) -> Result<PublicKey, secp256k1::Error> {
+pub fn derive_public_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, base_point: &PublicKey) -> Result<PublicKey, SecpError> {
let mut sha = Sha256::engine();
sha.input(&per_commitment_point.serialize());
sha.input(&base_point.serialize());
/// Derives a per-commitment-transaction revocation key from its constituent parts.
///
+/// Only the cheating participant owns a valid witness to propagate a revoked
+/// 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<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result<SecretKey, secp256k1::Error> {
- let revocation_base_point = PublicKey::from_secret_key(&secp_ctx, &revocation_base_secret);
+pub fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_secret: &SecretKey, countersignatory_revocation_base_secret: &SecretKey) -> Result<SecretKey, SecpError> {
+ 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);
let rev_append_commit_hash_key = {
let mut sha = Sha256::engine();
- sha.input(&revocation_base_point.serialize());
+ sha.input(&countersignatory_revocation_base_point.serialize());
sha.input(&per_commitment_point.serialize());
Sha256::from_engine(sha).into_inner()
let commit_append_rev_hash_key = {
let mut sha = Sha256::engine();
sha.input(&per_commitment_point.serialize());
- sha.input(&revocation_base_point.serialize());
+ sha.input(&countersignatory_revocation_base_point.serialize());
Sha256::from_engine(sha).into_inner()
};
- let mut part_a = revocation_base_secret.clone();
- part_a.mul_assign(&rev_append_commit_hash_key)?;
- let mut part_b = per_commitment_secret.clone();
- part_b.mul_assign(&commit_append_rev_hash_key)?;
- part_a.add_assign(&part_b[..])?;
- Ok(part_a)
+ let mut countersignatory_contrib = countersignatory_revocation_base_secret.clone();
+ countersignatory_contrib.mul_assign(&rev_append_commit_hash_key)?;
+ let mut broadcaster_contrib = per_commitment_secret.clone();
+ broadcaster_contrib.mul_assign(&commit_append_rev_hash_key)?;
+ countersignatory_contrib.add_assign(&broadcaster_contrib[..])?;
+ Ok(countersignatory_contrib)
}
/// 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.
///
+/// Only the cheating participant owns a valid witness to propagate a revoked
+/// commitment transaction, thus per_commitment_point always come from cheater
+/// and revocation_base_point 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_public_revocation_key<T: secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, revocation_base_point: &PublicKey) -> Result<PublicKey, secp256k1::Error> {
+pub fn derive_public_revocation_key<T: secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, countersignatory_revocation_base_point: &PublicKey) -> Result<PublicKey, SecpError> {
let rev_append_commit_hash_key = {
let mut sha = Sha256::engine();
- sha.input(&revocation_base_point.serialize());
+ sha.input(&countersignatory_revocation_base_point.serialize());
sha.input(&per_commitment_point.serialize());
Sha256::from_engine(sha).into_inner()
let commit_append_rev_hash_key = {
let mut sha = Sha256::engine();
sha.input(&per_commitment_point.serialize());
- sha.input(&revocation_base_point.serialize());
+ sha.input(&countersignatory_revocation_base_point.serialize());
Sha256::from_engine(sha).into_inner()
};
- let mut part_a = revocation_base_point.clone();
- part_a.mul_assign(&secp_ctx, &rev_append_commit_hash_key)?;
- let mut part_b = per_commitment_point.clone();
- part_b.mul_assign(&secp_ctx, &commit_append_rev_hash_key)?;
- part_a.combine(&part_b)
+ let mut countersignatory_contrib = countersignatory_revocation_base_point.clone();
+ countersignatory_contrib.mul_assign(&secp_ctx, &rev_append_commit_hash_key)?;
+ let mut broadcaster_contrib = per_commitment_point.clone();
+ broadcaster_contrib.mul_assign(&secp_ctx, &commit_append_rev_hash_key)?;
+ countersignatory_contrib.combine(&broadcaster_contrib)
}
/// 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.
///
+/// A broadcaster key is provided from potential broadcaster of the computed transaction.
+/// A countersignatory key is coming from a protocol participant unable to broadcast the
+/// transaction.
+///
/// 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.
+ /// The broadcaster's 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.
+ /// The revocation key which is used to allow the broadcaster of the commitment
+ /// transaction to provide their counterparty the ability to punish them if they broadcast
+ /// an old state.
pub revocation_key: PublicKey,
- /// A's HTLC Key
- pub a_htlc_key: PublicKey,
- /// B's HTLC Key
- pub b_htlc_key: PublicKey,
- /// A's Payment Key (which isn't allowed to be spent from for some delay)
- pub a_delayed_payment_key: PublicKey,
+ /// Broadcaster's HTLC Key
+ pub broadcaster_htlc_key: PublicKey,
+ /// Countersignatory's HTLC Key
+ pub countersignatory_htlc_key: PublicKey,
+ /// Broadcaster's Payment Key (which isn't allowed to be spent from for some delay)
+ pub broadcaster_delayed_payment_key: PublicKey,
}
impl_writeable!(TxCreationKeys, 33*6,
- { per_commitment_point, revocation_key, a_htlc_key, b_htlc_key, a_delayed_payment_key });
+ { per_commitment_point, revocation_key, broadcaster_htlc_key, countersignatory_htlc_key, broadcaster_delayed_payment_key });
/// The per-commitment point and a set of pre-calculated public keys used for transaction creation
/// in the signer.
}
/// The transaction per-commitment point
- pub fn per_comitment_point(&self) -> &PublicKey {
+ pub fn per_commitment_point(&self) -> &PublicKey {
&self.0.per_commitment_point
}
}
impl TxCreationKeys {
/// Create a new TxCreationKeys from channel base points and the per-commitment point
- pub fn new<T: secp256k1::Signing + secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, a_delayed_payment_base: &PublicKey, a_htlc_base: &PublicKey, b_revocation_base: &PublicKey, b_htlc_base: &PublicKey) -> Result<TxCreationKeys, secp256k1::Error> {
+ pub fn derive_new<T: secp256k1::Signing + secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, broadcaster_delayed_payment_base: &PublicKey, broadcaster_htlc_base: &PublicKey, countersignatory_revocation_base: &PublicKey, countersignatory_htlc_base: &PublicKey) -> Result<TxCreationKeys, SecpError> {
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)?,
+ 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)?,
})
}
}
/// A script either spendable by the revocation
-/// key or the delayed_payment_key and satisfying the relative-locktime OP_CSV constrain.
+/// key or the broadcaster_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 {
+pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, contest_delay: u16, broadcaster_delayed_payment_key: &PublicKey) -> Script {
Builder::new().push_opcode(opcodes::all::OP_IF)
.push_slice(&revocation_key.serialize())
.push_opcode(opcodes::all::OP_ELSE)
- .push_int(to_self_delay as i64)
+ .push_int(contest_delay as i64)
.push_opcode(opcodes::all::OP_CSV)
.push_opcode(opcodes::all::OP_DROP)
- .push_slice(&delayed_payment_key.serialize())
+ .push_slice(&broadcaster_delayed_payment_key.serialize())
.push_opcode(opcodes::all::OP_ENDIF)
.push_opcode(opcodes::all::OP_CHECKSIG)
.into_script()
});
#[inline]
-pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, a_htlc_key: &PublicKey, b_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script {
+pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, 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 {
Builder::new().push_opcode(opcodes::all::OP_DUP)
.push_opcode(opcodes::all::OP_IF)
.push_opcode(opcodes::all::OP_CHECKSIG)
.push_opcode(opcodes::all::OP_ELSE)
- .push_slice(&b_htlc_key.serialize()[..])
+ .push_slice(&countersignatory_htlc_key.serialize()[..])
.push_opcode(opcodes::all::OP_SWAP)
.push_opcode(opcodes::all::OP_SIZE)
.push_int(32)
.push_opcode(opcodes::all::OP_DROP)
.push_int(2)
.push_opcode(opcodes::all::OP_SWAP)
- .push_slice(&a_htlc_key.serialize()[..])
+ .push_slice(&broadcaster_htlc_key.serialize()[..])
.push_int(2)
.push_opcode(opcodes::all::OP_CHECKMULTISIG)
.push_opcode(opcodes::all::OP_ELSE)
.push_opcode(opcodes::all::OP_IF)
.push_opcode(opcodes::all::OP_CHECKSIG)
.push_opcode(opcodes::all::OP_ELSE)
- .push_slice(&b_htlc_key.serialize()[..])
+ .push_slice(&countersignatory_htlc_key.serialize()[..])
.push_opcode(opcodes::all::OP_SWAP)
.push_opcode(opcodes::all::OP_SIZE)
.push_int(32)
.push_opcode(opcodes::all::OP_EQUALVERIFY)
.push_int(2)
.push_opcode(opcodes::all::OP_SWAP)
- .push_slice(&a_htlc_key.serialize()[..])
+ .push_slice(&broadcaster_htlc_key.serialize()[..])
.push_int(2)
.push_opcode(opcodes::all::OP_CHECKMULTISIG)
.push_opcode(opcodes::all::OP_ELSE)
}
}
-/// note here that 'a_revocation_key' is generated using b_revocation_basepoint and a's
+/// note here that 'revocation_key' is generated using countersignatory_revocation_basepoint and broadcaster's
/// commitment secret. 'htlc' does *not* need to have its previous_output_index filled.
#[inline]
pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Script {
- get_htlc_redeemscript_with_explicit_keys(htlc, &keys.a_htlc_key, &keys.b_htlc_key, &keys.revocation_key)
+ get_htlc_redeemscript_with_explicit_keys(htlc, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key)
}
/// Gets the redeemscript for a funding output from the two funding public keys.
/// Note that the order of funding public keys does not matter.
-pub fn make_funding_redeemscript(a: &PublicKey, b: &PublicKey) -> Script {
- let our_funding_key = a.serialize();
- let their_funding_key = b.serialize();
+pub fn make_funding_redeemscript(broadcaster: &PublicKey, countersignatory: &PublicKey) -> Script {
+ let broadcaster_funding_key = broadcaster.serialize();
+ let countersignatory_funding_key = countersignatory.serialize();
let builder = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2);
- if our_funding_key[..] < their_funding_key[..] {
- builder.push_slice(&our_funding_key)
- .push_slice(&their_funding_key)
+ if broadcaster_funding_key[..] < countersignatory_funding_key[..] {
+ builder.push_slice(&broadcaster_funding_key)
+ .push_slice(&countersignatory_funding_key)
} else {
- builder.push_slice(&their_funding_key)
- .push_slice(&our_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()
}
/// panics if htlc.transaction_output_index.is_none()!
-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 {
+pub fn build_htlc_transaction(prev_hash: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction {
let mut txins: Vec<TxIn> = Vec::new();
txins.push(TxIn {
previous_output: OutPoint {
let mut txouts: Vec<TxOut> = Vec::new();
txouts.push(TxOut {
- script_pubkey: get_revokeable_redeemscript(revocation_key, to_self_delay, a_delayed_payment_key).to_v0_p2wsh(),
+ script_pubkey: get_revokeable_redeemscript(revocation_key, contest_delay, broadcaster_delayed_payment_key).to_v0_p2wsh(),
value: htlc.amount_msat / 1000 - total_fee //TODO: BOLT 3 does not specify if we should add amount_msat before dividing or if we should divide by 1000 before subtracting (as we do here)
});
local_keys: TxCreationKeys {
per_commitment_point: dummy_key.clone(),
revocation_key: dummy_key.clone(),
- a_htlc_key: dummy_key.clone(),
- b_htlc_key: dummy_key.clone(),
- a_delayed_payment_key: dummy_key.clone(),
+ broadcaster_htlc_key: dummy_key.clone(),
+ countersignatory_htlc_key: dummy_key.clone(),
+ broadcaster_delayed_payment_key: dummy_key.clone(),
},
feerate_per_kw: 0,
per_htlc: Vec::new()
/// ChannelKeys::sign_local_commitment() calls directly.
/// Channel value is amount locked in funding_outpoint.
pub fn get_local_sig<T: secp256k1::Signing>(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>) -> 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)
}
for this_htlc in self.per_htlc.iter() {
if this_htlc.0.transaction_output_index.is_some() {
- let htlc_tx = build_htlc_transaction(&txid, self.feerate_per_kw, local_csv, &this_htlc.0, &self.local_keys.a_delayed_payment_key, &self.local_keys.revocation_key);
+ let htlc_tx = build_htlc_transaction(&txid, self.feerate_per_kw, local_csv, &this_htlc.0, &self.local_keys.broadcaster_delayed_payment_key, &self.local_keys.revocation_key);
- 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 htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc.0, &self.local_keys.broadcaster_htlc_key, &self.local_keys.countersignatory_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);
// Further, we should never be provided the preimage for an HTLC-Timeout transaction.
if this_htlc.0.offered && preimage.is_some() { unreachable!(); }
- let mut htlc_tx = build_htlc_transaction(&txid, self.feerate_per_kw, local_csv, &this_htlc.0, &self.local_keys.a_delayed_payment_key, &self.local_keys.revocation_key);
+ let mut htlc_tx = build_htlc_transaction(&txid, self.feerate_per_kw, local_csv, &this_htlc.0, &self.local_keys.broadcaster_delayed_payment_key, &self.local_keys.revocation_key);
// Channel should have checked that we have a remote signature for this HTLC at
// creation, and we should have a sensible htlc transaction:
assert!(this_htlc.1.is_some());
- 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 htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc.0, &self.local_keys.broadcaster_htlc_key, &self.local_keys.countersignatory_htlc_key, &self.local_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());