Add V2 constructors to `ChannelId`
authorDuncan Dean <git@dunxen.dev>
Tue, 12 Sep 2023 08:52:50 +0000 (10:52 +0200)
committerDuncan Dean <git@dunxen.dev>
Tue, 20 Feb 2024 07:15:10 +0000 (09:15 +0200)
lightning/src/ln/channel_id.rs

index 19003961ff1a52bced58e52622dd59add517bfed..90efe3c94be6ba6c40fe9970b56737ed7a3ba93e 100644 (file)
@@ -14,8 +14,13 @@ use crate::io;
 use crate::ln::msgs::DecodeError;
 use crate::sign::EntropySource;
 use crate::util::ser::{Readable, Writeable, Writer};
+use super::channel_keys::RevocationBasepoint;
 
-use bitcoin::hashes::Hash as _;
+use bitcoin::hashes::{
+       Hash as _,
+       HashEngine as _,
+       sha256::Hash as Sha256,
+};
 use core::fmt;
 use core::ops::Deref;
 
@@ -68,6 +73,32 @@ impl ChannelId {
        pub fn is_zero(&self) -> bool {
                self.0[..] == [0; 32]
        }
+
+       /// Create _v2_ channel ID by concatenating the holder revocation basepoint with the counterparty
+       /// revocation basepoint and hashing the result. The basepoints will be concatenated in increasing
+       /// sorted order.
+       pub fn v2_from_revocation_basepoints(
+               ours: &RevocationBasepoint,
+               theirs: &RevocationBasepoint,
+       ) -> Self {
+               let ours = ours.0.serialize();
+               let theirs = theirs.0.serialize();
+               let (lesser, greater) = if ours < theirs {
+                       (ours, theirs)
+               } else {
+                       (theirs, ours)
+               };
+               let mut engine = Sha256::engine();
+               engine.input(&lesser[..]);
+               engine.input(&greater[..]);
+               Self(Sha256::from_engine(engine).to_byte_array())
+       }
+
+       /// Create temporary _v2_ channel ID by concatenating a zeroed out basepoint with the holder
+       /// revocation basepoint and hashing the result.
+       pub fn temporary_v2_from_revocation_basepoint(our_revocation_basepoint: &RevocationBasepoint) -> Self {
+               Self(Sha256::hash(&[[0u8; 33], our_revocation_basepoint.0.serialize()].concat()).to_byte_array())
+       }
 }
 
 impl Writeable for ChannelId {
@@ -91,9 +122,17 @@ impl fmt::Display for ChannelId {
 
 #[cfg(test)]
 mod tests {
+       use bitcoin::hashes::{
+               Hash as _,
+               HashEngine as _,
+               hex::FromHex as _,
+               sha256::Hash as Sha256,
+       };
+       use bitcoin::secp256k1::PublicKey;
        use hex::DisplayHex;
 
        use crate::ln::ChannelId;
+       use crate::ln::channel_keys::RevocationBasepoint;
        use crate::util::ser::{Readable, Writeable};
        use crate::util::test_utils;
        use crate::prelude::*;
@@ -139,4 +178,29 @@ mod tests {
                let channel_id = ChannelId::v1_from_funding_txid(&[2; 32], 1);
                assert_eq!(format!("{}", &channel_id), "0202020202020202020202020202020202020202020202020202020202020203");
        }
+
+       #[test]
+       fn test_channel_id_v2_from_basepoints() {
+               // Ours greater than theirs
+               let ours = RevocationBasepoint(PublicKey::from_slice(&<Vec<u8>>::from_hex("0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c").unwrap()[..]).unwrap());
+               let theirs = RevocationBasepoint(PublicKey::from_slice(&<Vec<u8>>::from_hex("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()[..]).unwrap());
+
+               let mut engine = Sha256::engine();
+               engine.input(&theirs.0.serialize());
+               engine.input(&ours.0.serialize());
+               let expected_id = ChannelId(Sha256::from_engine(engine).to_byte_array());
+
+               assert_eq!(ChannelId::v2_from_revocation_basepoints(&ours, &theirs), expected_id);
+
+               // Theirs greater than ours
+               let ours = RevocationBasepoint(PublicKey::from_slice(&<Vec<u8>>::from_hex("027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007").unwrap()[..]).unwrap());
+               let theirs = RevocationBasepoint(PublicKey::from_slice(&<Vec<u8>>::from_hex("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()[..]).unwrap());
+
+               let mut engine = Sha256::engine();
+               engine.input(&ours.0.serialize());
+               engine.input(&theirs.0.serialize());
+               let expected_id = ChannelId(Sha256::from_engine(engine).to_byte_array());
+
+               assert_eq!(ChannelId::v2_from_revocation_basepoints(&ours, &theirs), expected_id);
+       }
 }