Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 101 additions & 1 deletion smite/src/bolt/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

use super::{FeatureBit, Features};
use bitcoin::OutPoint;
use bitcoin::hashes::Hash;
use bitcoin::hashes::{Hash, sha256};
use bitcoin::hex::DisplayHex;
use bitcoin::secp256k1::PublicKey;
use serde::{Deserialize, Serialize};
use std::fmt;

Expand Down Expand Up @@ -79,6 +80,37 @@ impl ChannelId {
res[31] ^= (outpoint.vout & 0xff) as u8;
Self(res)
}

/// Creates a _v2_ channel ID from both peers' revocation basepoints.
#[must_use]
pub fn v2_from_revocation_basepoints(basepoint1: &PublicKey, basepoint2: &PublicKey) -> Self {
Self::v2_from_serialized_basepoints(basepoint1.serialize(), basepoint2.serialize())
}

/// Creates a _v2_ `temporary_channel_id` from the opener's revocation
/// basepoint.
#[must_use]
pub fn v2_temporary_from_revocation_basepoint(
opener_basepoint: &PublicKey,
) -> TemporaryChannelId {
Self::v2_from_serialized_basepoints([0u8; PUBLIC_KEY_SIZE], opener_basepoint.serialize())
}

/// Hashes two already-serialized basepoints in BOLT 2's canonical order.
fn v2_from_serialized_basepoints(
basepoint1: [u8; PUBLIC_KEY_SIZE],
basepoint2: [u8; PUBLIC_KEY_SIZE],
) -> Self {
let (lesser, greater) = if basepoint1 <= basepoint2 {
(basepoint1, basepoint2)
} else {
(basepoint2, basepoint1)
};
let mut preimage = [0u8; PUBLIC_KEY_SIZE * 2];
preimage[..PUBLIC_KEY_SIZE].copy_from_slice(&lesser);
preimage[PUBLIC_KEY_SIZE..].copy_from_slice(&greater);
Self(sha256::Hash::hash(&preimage).to_byte_array())
}
}

impl fmt::Display for ChannelId {
Expand Down Expand Up @@ -426,6 +458,16 @@ mod tests {
use super::*;
use bitcoin::{OutPoint, Txid};

/// The two `funding_pubkey`s of the 2-of-2 output in the BOLT 3
/// "Appendix G: Dual Funded Transaction Test Vectors".
const BASEPOINT_1: &str = "0292edb5f7bbf9e900f7e024be1c1339c6d149c11930e613af3a983d2565f4e41e";
const BASEPOINT_2: &str = "02e16172a41e928cbd78f761bd1c657c4afc7495a1244f7f30166b654fbf7661e3";

fn pubkey(hex_str: &str) -> PublicKey {
let bytes = hex::decode(hex_str).expect("valid hex");
PublicKey::from_slice(&bytes).expect("valid pubkey")
}

#[test]
fn bigsize_new() {
let bs = BigSize::new(42);
Expand Down Expand Up @@ -516,6 +558,64 @@ mod tests {
}
}

#[test]
fn channel_id_v2_hashes_sorted_basepoints() {
// Expected value computed by LDK's `ChannelId::v2_from_revocation_basepoints`.
let channel_id =
ChannelId::v2_from_revocation_basepoints(&pubkey(BASEPOINT_1), &pubkey(BASEPOINT_2));

assert_eq!(
channel_id.to_string(),
"59bc22f722836ce5095a37504f8ab87b1b2dbdc8aad638b77da3f5f3e8330edd",
);
}

#[test]
fn channel_id_v2_from_revocation_basepoints_is_order_independent() {
let basepoint_1 = pubkey(BASEPOINT_1);
let basepoint_2 = pubkey(BASEPOINT_2);

assert_eq!(
ChannelId::v2_from_revocation_basepoints(&basepoint_1, &basepoint_2),
ChannelId::v2_from_revocation_basepoints(&basepoint_2, &basepoint_1),
);
}

#[test]
fn channel_id_v2_temporary_hashes_zeroed_basepoint_first() {
// Expected values computed by LDK's `ChannelId::temporary_v2_from_revocation_basepoint`.
assert_eq!(
ChannelId::v2_temporary_from_revocation_basepoint(&pubkey(BASEPOINT_1)).to_string(),
"90fc2d0fcef3376e4c26de47e9c86a7362adecf87c8c1a01cdaa3263abd74c5a",
);
assert_eq!(
ChannelId::v2_temporary_from_revocation_basepoint(&pubkey(BASEPOINT_2)).to_string(),
"270d4e8fa33e0c15f46c4978186d02c51a5307229ba5689c9f600c68360e25e3",
);
}

#[test]
fn channel_id_v2_temporary_differs_from_final() {
let basepoint_1 = pubkey(BASEPOINT_1);
let basepoint_2 = pubkey(BASEPOINT_2);

assert_ne!(
ChannelId::v2_temporary_from_revocation_basepoint(&basepoint_1),
ChannelId::v2_from_revocation_basepoints(&basepoint_1, &basepoint_2),
);
}

#[test]
fn channel_id_v2_distinguishes_basepoints() {
let basepoint_1 = pubkey(BASEPOINT_1);
let basepoint_2 = pubkey(BASEPOINT_2);

assert_ne!(
ChannelId::v2_from_revocation_basepoints(&basepoint_1, &basepoint_1),
ChannelId::v2_from_revocation_basepoints(&basepoint_1, &basepoint_2),
);
}

#[test]
fn short_channel_id_ord_matches_packed_u64() {
let a = ShortChannelId::new(100, 0, 0);
Expand Down
Loading