1use super::channel_keys::RevocationBasepoint;
13
14use crate::chain::transaction::OutPoint;
15use crate::io;
16use crate::ln::msgs::DecodeError;
17use crate::sign::EntropySource;
18use crate::util::ser::{Readable, Writeable, Writer};
19
20#[allow(unused_imports)]
21use crate::prelude::*;
22
23use bitcoin::hashes::{sha256::Hash as Sha256, Hash as _, HashEngine as _};
24use bitcoin::hex::display::impl_fmt_traits;
25
26use core::borrow::Borrow;
27use core::ops::Deref;
28
29#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
38pub struct ChannelId(pub [u8; 32]);
39
40impl ChannelId {
41 pub fn v1_from_funding_txid(txid: &[u8; 32], output_index: u16) -> Self {
43 let mut res = [0; 32];
44 res[..].copy_from_slice(&txid[..]);
45 res[30] ^= ((output_index >> 8) & 0xff) as u8;
46 res[31] ^= ((output_index >> 0) & 0xff) as u8;
47 Self(res)
48 }
49
50 pub fn v1_from_funding_outpoint(outpoint: OutPoint) -> Self {
52 Self::v1_from_funding_txid(outpoint.txid.as_byte_array(), outpoint.index)
53 }
54
55 pub fn temporary_from_entropy_source<ES: Deref>(entropy_source: &ES) -> Self
57 where
58 ES::Target: EntropySource,
59 {
60 Self(entropy_source.get_secure_random_bytes())
61 }
62
63 pub fn from_bytes(data: [u8; 32]) -> Self {
66 Self(data)
67 }
68
69 pub fn new_zero() -> Self {
71 Self([0; 32])
72 }
73
74 pub fn is_zero(&self) -> bool {
76 self.0[..] == [0; 32]
77 }
78
79 pub fn v2_from_revocation_basepoints(
83 ours: &RevocationBasepoint, theirs: &RevocationBasepoint,
84 ) -> Self {
85 let ours = ours.0.serialize();
86 let theirs = theirs.0.serialize();
87 let (lesser, greater) = if ours < theirs { (ours, theirs) } else { (theirs, ours) };
88 let mut engine = Sha256::engine();
89 engine.input(&lesser[..]);
90 engine.input(&greater[..]);
91 Self(Sha256::from_engine(engine).to_byte_array())
92 }
93
94 pub fn temporary_v2_from_revocation_basepoint(
97 our_revocation_basepoint: &RevocationBasepoint,
98 ) -> Self {
99 let our_revocation_point_bytes = our_revocation_basepoint.0.serialize();
100 Self(Sha256::hash(&[[0u8; 33], our_revocation_point_bytes].concat()).to_byte_array())
101 }
102
103 pub fn is_v2_channel_id(
105 &self, ours: &RevocationBasepoint, theirs: &RevocationBasepoint,
106 ) -> bool {
107 *self == Self::v2_from_revocation_basepoints(ours, theirs)
108 }
109}
110
111impl Writeable for ChannelId {
112 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
113 self.0.write(w)
114 }
115}
116
117impl Readable for ChannelId {
118 fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
119 let buf: [u8; 32] = Readable::read(r)?;
120 Ok(ChannelId(buf))
121 }
122}
123
124impl Borrow<[u8]> for ChannelId {
125 fn borrow(&self) -> &[u8] {
126 &self.0[..]
127 }
128}
129
130impl_fmt_traits! {
131 impl fmt_traits for ChannelId {
132 const LENGTH: usize = 32;
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use bitcoin::hashes::{sha256::Hash as Sha256, Hash as _, HashEngine as _};
139 use bitcoin::hex::DisplayHex;
140 use bitcoin::secp256k1::PublicKey;
141
142 use super::ChannelId;
143
144 use crate::io;
145 use crate::ln::channel_keys::RevocationBasepoint;
146 use crate::prelude::*;
147 use crate::util::ser::{Readable, Writeable};
148 use crate::util::test_utils;
149
150 use core::str::FromStr;
151
152 #[test]
153 fn test_channel_id_v1_from_funding_txid() {
154 let channel_id = ChannelId::v1_from_funding_txid(&[2; 32], 1);
155 let expected = "0202020202020202020202020202020202020202020202020202020202020203";
156 assert_eq!(channel_id.0.as_hex().to_string(), expected);
157 }
158
159 #[test]
160 fn test_channel_id_new_from_data() {
161 let data: [u8; 32] = [2; 32];
162 let channel_id = ChannelId::from_bytes(data.clone());
163 assert_eq!(channel_id.0, data);
164 }
165
166 #[test]
167 fn test_channel_id_equals() {
168 let channel_id11 = ChannelId::v1_from_funding_txid(&[2; 32], 2);
169 let channel_id12 = ChannelId::v1_from_funding_txid(&[2; 32], 2);
170 let channel_id21 = ChannelId::v1_from_funding_txid(&[2; 32], 42);
171 assert_eq!(channel_id11, channel_id12);
172 assert_ne!(channel_id11, channel_id21);
173 }
174
175 #[test]
176 fn test_channel_id_write_read() {
177 let data: [u8; 32] = [2; 32];
178 let channel_id = ChannelId::from_bytes(data.clone());
179
180 let mut w = test_utils::TestVecWriter(Vec::new());
181 channel_id.write(&mut w).unwrap();
182
183 let channel_id_2 = ChannelId::read(&mut io::Cursor::new(&w.0)).unwrap();
184 assert_eq!(channel_id_2, channel_id);
185 assert_eq!(channel_id_2.0, data);
186 }
187
188 #[test]
189 fn test_channel_id_display() {
190 let channel_id = ChannelId::v1_from_funding_txid(&[2; 32], 1);
191 let expected = "0202020202020202020202020202020202020202020202020202020202020203";
192 assert_eq!(format!("{}", &channel_id), expected);
193 }
194
195 #[test]
196 fn test_channel_id_v2_from_basepoints() {
197 let our_pk = "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c";
199 let ours = RevocationBasepoint(PublicKey::from_str(&our_pk).unwrap());
200 let their_pk = "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619";
201 let theirs = RevocationBasepoint(PublicKey::from_str(&their_pk).unwrap());
202
203 let mut engine = Sha256::engine();
204 engine.input(&theirs.0.serialize());
205 engine.input(&ours.0.serialize());
206 let expected_id = ChannelId(Sha256::from_engine(engine).to_byte_array());
207
208 assert_eq!(ChannelId::v2_from_revocation_basepoints(&ours, &theirs), expected_id);
209
210 let our_pk = "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007";
212 let ours = RevocationBasepoint(PublicKey::from_str(&our_pk).unwrap());
213 let their_pk = "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619";
214 let theirs = RevocationBasepoint(PublicKey::from_str(&their_pk).unwrap());
215
216 let mut engine = Sha256::engine();
217 engine.input(&ours.0.serialize());
218 engine.input(&theirs.0.serialize());
219 let expected_id = ChannelId(Sha256::from_engine(engine).to_byte_array());
220
221 assert_eq!(ChannelId::v2_from_revocation_basepoints(&ours, &theirs), expected_id);
222 }
223
224 #[test]
225 fn test_is_v2_channel_id() {
226 let our_pk = "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c";
227 let ours = RevocationBasepoint(PublicKey::from_str(&our_pk).unwrap());
228 let their_pk = "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619";
229 let theirs = RevocationBasepoint(PublicKey::from_str(&their_pk).unwrap());
230
231 let channel_id = ChannelId::v2_from_revocation_basepoints(&ours, &theirs);
232 assert!(channel_id.is_v2_channel_id(&ours, &theirs));
233
234 let channel_id = ChannelId::v1_from_funding_txid(&[2; 32], 1);
235 assert!(!channel_id.is_v2_channel_id(&ours, &theirs))
236 }
237}