X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel_keys.rs;h=9e839b15e3c40636c72553b32c9eb52f35079f7b;hb=1e580668684d4dbf11d69d75e5d4a5c4f8cc40bf;hp=b577dc60008583537c4d9c1cebc8b2f6e5f48e77;hpb=f352d03ee98aed3d940e697fcb09371cfdc3ab15;p=rust-lightning diff --git a/lightning/src/ln/channel_keys.rs b/lightning/src/ln/channel_keys.rs index b577dc60..9e839b15 100644 --- a/lightning/src/ln/channel_keys.rs +++ b/lightning/src/ln/channel_keys.rs @@ -10,19 +10,19 @@ //! Keys used to generate commitment transactions. //! See: -use bitcoin::hashes::Hash; -use bitcoin::hashes::HashEngine; -use bitcoin::secp256k1::Scalar; -use bitcoin::secp256k1::SecretKey; -use bitcoin::secp256k1::Secp256k1; -use bitcoin::secp256k1; +use crate::io; use crate::ln::msgs::DecodeError; use crate::util::ser::Readable; -use crate::io; -use crate::util::ser::Writer; use crate::util::ser::Writeable; -use bitcoin::secp256k1::PublicKey; +use crate::util::ser::Writer; use bitcoin::hashes::sha256::Hash as Sha256; +use bitcoin::hashes::Hash; +use bitcoin::hashes::HashEngine; +use bitcoin::secp256k1; +use bitcoin::secp256k1::PublicKey; +use bitcoin::secp256k1::Scalar; +use bitcoin::secp256k1::Secp256k1; +use bitcoin::secp256k1::SecretKey; macro_rules! doc_comment { ($x:expr, $($tt:tt)*) => { @@ -31,12 +31,30 @@ macro_rules! doc_comment { }; } macro_rules! basepoint_impl { - ($BasepointT:ty) => { + ($BasepointT:ty $(, $KeyName: expr)?) => { impl $BasepointT { /// Get inner Public Key pub fn to_public_key(&self) -> PublicKey { self.0 } + + $(doc_comment!( + concat!( + "Derives the \"tweak\" used in calculate [`", $KeyName, "::from_basepoint`].\n", + "\n", + "[`", $KeyName, "::from_basepoint`] calculates a private key as:\n", + "`privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)`\n", + "\n", + "This calculates the hash part in the tweak derivation process, which is used to\n", + "ensure that each key is unique and cannot be guessed by an external party." + ), + pub fn derive_add_tweak(&self, per_commitment_point: &PublicKey) -> Sha256 { + let mut sha = Sha256::engine(); + sha.input(&per_commitment_point.serialize()); + sha.input(&self.to_public_key().serialize()); + Sha256::from_engine(sha) + }); + )? } impl From for $BasepointT { @@ -44,8 +62,7 @@ macro_rules! basepoint_impl { Self(value) } } - - } + }; } macro_rules! key_impl { ($BasepointT:ty, $KeyName:expr) => { @@ -87,11 +104,9 @@ macro_rules! key_read_write { Ok(Self(key)) } } - } + }; } - - /// Base key used in conjunction with a `per_commitment_point` to generate a [`DelayedPaymentKey`]. /// /// The delayed payment key is used to pay the commitment state broadcaster their @@ -99,10 +114,9 @@ macro_rules! key_read_write { /// state broadcasted was previously revoked. #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub struct DelayedPaymentBasepoint(pub PublicKey); -basepoint_impl!(DelayedPaymentBasepoint); +basepoint_impl!(DelayedPaymentBasepoint, "DelayedPaymentKey"); key_read_write!(DelayedPaymentBasepoint); - /// A derived key built from a [`DelayedPaymentBasepoint`] and `per_commitment_point`. /// /// The delayed payment key is used to pay the commitment state broadcaster their @@ -127,7 +141,7 @@ key_read_write!(DelayedPaymentKey); /// Thus, both channel counterparties' HTLC keys will appears in each HTLC output's script. #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub struct HtlcBasepoint(pub PublicKey); -basepoint_impl!(HtlcBasepoint); +basepoint_impl!(HtlcBasepoint, "HtlcKey"); key_read_write!(HtlcBasepoint); /// A derived key built from a [`HtlcBasepoint`] and `per_commitment_point`. @@ -150,14 +164,28 @@ key_read_write!(HtlcKey); /// 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. -fn derive_public_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, base_point: &PublicKey) -> PublicKey { +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).to_byte_array(); + let res = Sha256::from_engine(sha); - let hashkey = PublicKey::from_secret_key(&secp_ctx, - &SecretKey::from_slice(&res).expect("Hashes should always be valid keys unless SHA-256 is broken")); + add_public_key_tweak(secp_ctx, base_point, &res) +} + +/// Adds a tweak to a public key to derive a new public key. +/// +/// May panic if `tweak` is not the output of a SHA-256 hash. +pub fn add_public_key_tweak( + secp_ctx: &Secp256k1, base_point: &PublicKey, tweak: &Sha256, +) -> PublicKey { + let hashkey = PublicKey::from_secret_key( + &secp_ctx, + &SecretKey::from_slice(tweak.as_byte_array()) + .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.") } @@ -169,7 +197,6 @@ pub struct RevocationBasepoint(pub PublicKey); basepoint_impl!(RevocationBasepoint); key_read_write!(RevocationBasepoint); - /// The revocation key is used to allow a channel party to revoke their state - giving their /// counterparty the required material to claim all of their funds if they broadcast that state. /// @@ -192,8 +219,7 @@ impl RevocationKey { /// /// [`chan_utils::derive_private_revocation_key`]: crate::ln::chan_utils::derive_private_revocation_key pub fn from_basepoint( - secp_ctx: &Secp256k1, - countersignatory_basepoint: &RevocationBasepoint, + secp_ctx: &Secp256k1, countersignatory_basepoint: &RevocationBasepoint, per_commitment_point: &PublicKey, ) -> Self { let rev_append_commit_hash_key = { @@ -227,28 +253,56 @@ impl RevocationKey { } key_read_write!(RevocationKey); - #[cfg(test)] mod test { - use bitcoin::secp256k1::{Secp256k1, SecretKey, PublicKey}; - use bitcoin::hashes::hex::FromHex; use super::derive_public_key; + use bitcoin::hashes::hex::FromHex; + use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; #[test] fn test_key_derivation() { // Test vectors from BOLT 3 Appendix E: let secp_ctx = Secp256k1::new(); - let base_secret = SecretKey::from_slice(&>::from_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap()[..]).unwrap(); - let per_commitment_secret = SecretKey::from_slice(&>::from_hex("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap(); + let base_secret = SecretKey::from_slice( + &>::from_hex( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + ) + .unwrap()[..], + ) + .unwrap(); + let per_commitment_secret = SecretKey::from_slice( + &>::from_hex( + "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100", + ) + .unwrap()[..], + ) + .unwrap(); let base_point = PublicKey::from_secret_key(&secp_ctx, &base_secret); - assert_eq!(base_point.serialize()[..], >::from_hex("036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2").unwrap()[..]); + assert_eq!( + base_point.serialize()[..], + >::from_hex( + "036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2" + ) + .unwrap()[..] + ); let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret); - assert_eq!(per_commitment_point.serialize()[..], >::from_hex("025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486").unwrap()[..]); - - assert_eq!(derive_public_key(&secp_ctx, &per_commitment_point, &base_point).serialize()[..], - >::from_hex("0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5").unwrap()[..]); + assert_eq!( + per_commitment_point.serialize()[..], + >::from_hex( + "025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486" + ) + .unwrap()[..] + ); + + assert_eq!( + derive_public_key(&secp_ctx, &per_commitment_point, &base_point).serialize()[..], + >::from_hex( + "0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5" + ) + .unwrap()[..] + ); } }