1use alloc::boxed::Box;
2
3use bitcoin::bip32::{ChildNumber, Xpriv, Xpub};
4use bitcoin::hashes::sha256::Hash as Sha256;
5use bitcoin::hashes::{Hash, HashEngine};
6use bitcoin::secp256k1::{PublicKey, SecretKey};
7use bitcoin::{secp256k1, secp256k1::Secp256k1, Network};
8
9use crate::channel::ChannelId;
10use crate::util::byte_utils;
11use crate::util::crypto_utils::{hkdf_sha256, hkdf_sha256_keys};
12
13pub trait KeyDerive {
15 fn master_key(&self, seed: &[u8]) -> Xpriv;
17 fn node_keys(
19 &self,
20 seed: &[u8],
21 secp_ctx: &Secp256k1<secp256k1::All>,
22 ) -> (PublicKey, SecretKey);
23 fn keys_id(&self, channel_id: ChannelId, channel_seed_base: &[u8; 32]) -> [u8; 32] {
26 hkdf_sha256(channel_seed_base, "per-peer seed".as_bytes(), channel_id.as_slice())
27 }
28
29 fn channels_seed(&self, seed: &[u8]) -> [u8; 32] {
31 hkdf_sha256(seed, "peer seed".as_bytes(), &[])
32 }
33
34 fn channel_keys(
37 &self,
38 seed: &[u8],
39 keys_id: &[u8; 32],
40 basepoint_index: u32,
41 master_key: &Xpriv,
42 secp_ctx: &Secp256k1<secp256k1::All>,
43 ) -> (SecretKey, SecretKey, SecretKey, SecretKey, SecretKey, [u8; 32]);
44}
45
46#[derive(Clone, Debug)]
48pub struct NativeKeyDerive {
49 network: Network,
50}
51
52impl NativeKeyDerive {
53 pub fn new(network: Network) -> Self {
55 Self { network }
56 }
57}
58
59impl KeyDerive for NativeKeyDerive {
60 fn master_key(&self, seed: &[u8]) -> Xpriv {
61 let master_seed = hkdf_sha256(seed, "bip32 seed".as_bytes(), &[]);
62 Xpriv::new_master(self.network, &master_seed).expect("Your RNG is busted")
63 }
64
65 fn node_keys(
66 &self,
67 seed: &[u8],
68 secp_ctx: &Secp256k1<secp256k1::All>,
69 ) -> (PublicKey, SecretKey) {
70 let node_private_bytes = hkdf_sha256(seed, "nodeid".as_bytes(), &[]);
71 let node_secret_key = SecretKey::from_slice(&node_private_bytes).unwrap();
72 let node_id = PublicKey::from_secret_key(&secp_ctx, &node_secret_key);
73 (node_id, node_secret_key)
74 }
75
76 fn channel_keys(
77 &self,
78 _seed: &[u8],
79 keys_id: &[u8; 32],
80 _basepoint_index: u32,
81 _master_key: &Xpriv,
82 _secp_ctx: &Secp256k1<secp256k1::All>,
83 ) -> (SecretKey, SecretKey, SecretKey, SecretKey, SecretKey, [u8; 32]) {
84 let hkdf_info = "c-lightning";
85 let keys_buf: [u8; 192] = hkdf_sha256_keys(keys_id, hkdf_info.as_bytes(), &[]);
86
87 let mut ndx = 0;
89 let funding_key = SecretKey::from_slice(&keys_buf[ndx..ndx + 32]).unwrap();
90 ndx += 32;
91 let revocation_base_key = SecretKey::from_slice(&keys_buf[ndx..ndx + 32]).unwrap();
92 ndx += 32;
93 let htlc_base_key = SecretKey::from_slice(&keys_buf[ndx..ndx + 32]).unwrap();
94 ndx += 32;
95 let payment_key = SecretKey::from_slice(&keys_buf[ndx..ndx + 32]).unwrap();
96 ndx += 32;
97 let delayed_payment_base_key = SecretKey::from_slice(&keys_buf[ndx..ndx + 32]).unwrap();
98 ndx += 32;
99 let commitment_seed = keys_buf[ndx..ndx + 32].try_into().unwrap();
100 (
101 funding_key,
102 revocation_base_key,
103 htlc_base_key,
104 payment_key,
105 delayed_payment_base_key,
106 commitment_seed,
107 )
108 }
109}
110
111pub struct LdkKeyDerive {
113 network: Network,
114}
115
116impl KeyDerive for LdkKeyDerive {
117 fn master_key(&self, seed: &[u8]) -> Xpriv {
118 Xpriv::new_master(self.network, &seed).expect("Your RNG is busted")
119 }
120
121 fn node_keys(
122 &self,
123 seed: &[u8],
124 secp_ctx: &Secp256k1<secp256k1::All>,
125 ) -> (PublicKey, SecretKey) {
126 let master = self.master_key(seed);
127 let node_secret_key = master
128 .derive_priv(&secp_ctx, &[ChildNumber::from_hardened_idx(0).unwrap()])
129 .expect("Your RNG is busted")
130 .private_key;
131 let node_id = PublicKey::from_secret_key(&secp_ctx, &node_secret_key);
132 (node_id, node_secret_key)
133 }
134
135 fn channel_keys(
136 &self,
137 seed: &[u8],
138 keys_id: &[u8; 32],
139 _basepoint_index: u32,
140 master_key: &Xpriv,
141 secp_ctx: &Secp256k1<secp256k1::All>,
142 ) -> (SecretKey, SecretKey, SecretKey, SecretKey, SecretKey, [u8; 32]) {
143 let chan_id = byte_utils::slice_to_be64(&keys_id[0..8]);
144 assert!(chan_id <= core::u32::MAX as u64); let mut unique_start = Sha256::engine();
146 unique_start.input(keys_id);
147 unique_start.input(seed);
148
149 let channel_master_key = master_key
150 .derive_priv(&secp_ctx, &[ChildNumber::from_hardened_idx(3).unwrap()])
151 .expect("Your RNG is busted");
152
153 let child_privkey = channel_master_key
157 .derive_priv(
158 secp_ctx,
159 &[ChildNumber::from_hardened_idx(chan_id as u32).expect("key space exhausted")],
160 )
161 .expect("Your RNG is busted");
162 unique_start.input(child_privkey.private_key.as_ref());
163
164 let channel_seed = Sha256::from_engine(unique_start).to_byte_array();
165
166 let commitment_seed = {
167 let mut sha = Sha256::engine();
168 sha.input(&channel_seed);
169 sha.input(&b"commitment seed"[..]);
170 Sha256::from_engine(sha).to_byte_array()
171 };
172 macro_rules! key_step {
173 ($info: expr, $prev_key: expr) => {{
174 let mut sha = Sha256::engine();
175 sha.input(&channel_seed);
176 sha.input(&$prev_key[..]);
177 sha.input(&$info[..]);
178 SecretKey::from_slice(Sha256::from_engine(sha).as_ref()).unwrap()
179 }};
180 }
181 let funding_key = key_step!(b"funding key", commitment_seed);
182 let revocation_base_key = key_step!(b"revocation base key", funding_key);
183 let payment_key = key_step!(b"payment key", revocation_base_key);
184 let delayed_payment_base_key = key_step!(b"delayed payment base key", payment_key);
185 let htlc_base_key = key_step!(b"HTLC base key", delayed_payment_base_key);
186 (
187 funding_key,
188 revocation_base_key,
189 htlc_base_key,
190 payment_key,
191 delayed_payment_base_key,
192 commitment_seed,
193 )
194 }
195
196 fn keys_id(&self, channel_id: ChannelId, channel_seed_base: &[u8; 32]) -> [u8; 32] {
197 let mut res =
198 hkdf_sha256(channel_seed_base, "per-peer seed".as_bytes(), channel_id.as_slice());
199 res[0] = 0;
203 res[1] = 0;
204 res[2] = 0;
205 res[3] = 0;
206 res[4] &= 0x7f;
207 res
208 }
209}
210
211pub struct LndKeyDerive {
213 network: Network,
214}
215
216impl KeyDerive for LndKeyDerive {
217 fn master_key(&self, seed: &[u8]) -> Xpriv {
218 Xpriv::new_master(self.network, seed).expect("Your RNG is busted")
219 }
220
221 fn node_keys(
222 &self,
223 seed: &[u8],
224 secp_ctx: &Secp256k1<secp256k1::All>,
225 ) -> (PublicKey, SecretKey) {
226 let key_family_node_key = 6;
227 let index = 0;
228 let master = self.master_key(seed);
229 derive_key_lnd(secp_ctx, self.network, &master, key_family_node_key, index)
230 }
231
232 fn channel_keys(
233 &self,
234 _seed: &[u8],
235 keys_id: &[u8; 32],
236 basepoint_index: u32,
237 master_key: &Xpriv,
238 _secp_ctx: &Secp256k1<secp256k1::All>,
239 ) -> (SecretKey, SecretKey, SecretKey, SecretKey, SecretKey, [u8; 32]) {
240 let hkdf_info = "c-lightning";
241 let keys_buf: [u8; 192] = hkdf_sha256_keys(keys_id, hkdf_info.as_bytes(), &[]);
242
243 let mut ndx = 0;
245 ndx += 32;
246 ndx += 32;
247 ndx += 32;
248 ndx += 32;
249 ndx += 32;
250 let commitment_seed = keys_buf[ndx..ndx + 32].try_into().unwrap();
251
252 let secp_ctx = Secp256k1::new();
253
254 let (_, funding_key) =
261 derive_key_lnd(&secp_ctx, self.network, master_key, 0, basepoint_index);
262 let (_, revocation_base_key) =
263 derive_key_lnd(&secp_ctx, self.network, master_key, 1, basepoint_index);
264 let (_, htlc_base_key) =
265 derive_key_lnd(&secp_ctx, self.network, master_key, 2, basepoint_index);
266 let (_, payment_key) =
267 derive_key_lnd(&secp_ctx, self.network, master_key, 3, basepoint_index);
268 let (_, delayed_payment_base_key) =
269 derive_key_lnd(&secp_ctx, self.network, master_key, 4, basepoint_index);
270 (
271 funding_key,
272 revocation_base_key,
273 htlc_base_key,
274 payment_key,
275 delayed_payment_base_key,
276 commitment_seed,
277 )
278 }
279}
280
281pub fn key_derive(style: KeyDerivationStyle, network: Network) -> Box<dyn KeyDerive> {
283 match style {
284 KeyDerivationStyle::Native => Box::new(NativeKeyDerive { network }),
285 KeyDerivationStyle::Ldk => Box::new(LdkKeyDerive { network }),
286 KeyDerivationStyle::Lnd => Box::new(LndKeyDerive { network }),
287 }
288}
289
290#[derive(Clone, Copy, Debug)]
295pub enum KeyDerivationStyle {
296 Native = 1,
298 Ldk = 2,
300 Lnd = 3,
302}
303
304impl TryFrom<u8> for KeyDerivationStyle {
305 type Error = ();
306
307 fn try_from(v: u8) -> Result<Self, Self::Error> {
308 use KeyDerivationStyle::{Ldk, Lnd, Native};
309 match v {
310 x if x == Native as u8 => Ok(Native),
311 x if x == Ldk as u8 => Ok(Ldk),
312 x if x == Lnd as u8 => Ok(Lnd),
313 _ => Err(()),
314 }
315 }
316}
317
318impl core::fmt::Display for KeyDerivationStyle {
319 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
320 f.pad(match *self {
321 KeyDerivationStyle::Native => "native",
322 KeyDerivationStyle::Ldk => "ldk",
323 KeyDerivationStyle::Lnd => "lnd",
324 })
325 }
326}
327
328impl core::str::FromStr for KeyDerivationStyle {
329 type Err = ();
330 #[inline]
331 fn from_str(s: &str) -> Result<Self, Self::Err> {
332 match s {
333 "native" => Ok(KeyDerivationStyle::Native),
334 "ldk" => Ok(KeyDerivationStyle::Ldk),
335 "lnd" => Ok(KeyDerivationStyle::Lnd),
336 _ => Err(()),
337 }
338 }
339}
340
341impl KeyDerivationStyle {
342 pub(crate) fn get_key_path_len(&self) -> Option<usize> {
343 match self {
344 KeyDerivationStyle::Native => Some(1),
347 KeyDerivationStyle::Ldk => None,
350 KeyDerivationStyle::Lnd => Some(2),
353 }
354 }
355
356 pub(crate) fn get_account_extended_key(
357 &self,
358 secp_ctx: &Secp256k1<secp256k1::All>,
359 network: Network,
360 seed: &[u8],
361 ) -> Xpriv {
362 match self {
363 KeyDerivationStyle::Native => get_account_extended_key_native(secp_ctx, network, seed),
364 KeyDerivationStyle::Ldk => get_account_extended_key_native(secp_ctx, network, seed),
365 KeyDerivationStyle::Lnd => get_account_extended_key_lnd(secp_ctx, network, seed),
366 }
367 }
368}
369
370pub(crate) fn get_account_extended_key_native(
373 secp_ctx: &Secp256k1<secp256k1::All>,
374 network: Network,
375 node_seed: &[u8],
376) -> Xpriv {
377 let bip32_seed = hkdf_sha256(node_seed, "bip32 seed".as_bytes(), &[]);
378 let master = Xpriv::new_master(network, &bip32_seed).unwrap();
379 master
380 .derive_priv(&secp_ctx, &[ChildNumber::from_normal_idx(0).unwrap()])
381 .unwrap()
382 .derive_priv(&secp_ctx, &[ChildNumber::from_normal_idx(0).unwrap()])
383 .unwrap()
384}
385
386pub(crate) fn get_account_extended_key_lnd(
389 secp_ctx: &Secp256k1<secp256k1::All>,
390 network: Network,
391 node_seed: &[u8],
392) -> Xpriv {
393 let master = Xpriv::new_master(network, node_seed).unwrap();
395 let purpose = 84;
396 let cointype = 0;
397 let account = 0;
398 master
399 .derive_priv(&secp_ctx, &[ChildNumber::from_hardened_idx(purpose).unwrap()])
400 .unwrap()
401 .derive_priv(&secp_ctx, &[ChildNumber::from_hardened_idx(cointype).unwrap()])
402 .unwrap()
403 .derive_priv(&secp_ctx, &[ChildNumber::from_hardened_idx(account).unwrap()])
404 .unwrap()
405}
406
407pub(crate) fn derive_key_lnd(
408 secp_ctx: &Secp256k1<secp256k1::All>,
409 network: Network,
410 master: &Xpriv,
411 key_family: u32,
412 index: u32,
413) -> (PublicKey, SecretKey) {
414 let bip43purpose = 1017;
415 #[rustfmt::skip]
416 let coin_type = match network {
417 Network::Bitcoin => 0,
418 Network::Testnet => 1,
419 Network::Regtest => 1,
420 Network::Signet => 1,
421 _ => unreachable!(),
422 };
423 let branch = 0;
424 let node_ext_prv = master
425 .derive_priv(&secp_ctx, &[ChildNumber::from_hardened_idx(bip43purpose).unwrap()])
426 .unwrap()
427 .derive_priv(&secp_ctx, &[ChildNumber::from_hardened_idx(coin_type).unwrap()])
428 .unwrap()
429 .derive_priv(&secp_ctx, &[ChildNumber::from_hardened_idx(key_family).unwrap()])
430 .unwrap()
431 .derive_priv(&secp_ctx, &[ChildNumber::from_normal_idx(branch).unwrap()])
432 .unwrap()
433 .derive_priv(&secp_ctx, &[ChildNumber::from_normal_idx(index).unwrap()])
434 .unwrap();
435 let node_ext_pub = &Xpub::from_priv(&secp_ctx, &node_ext_prv);
436 (node_ext_pub.public_key, node_ext_prv.private_key)
437}
438
439#[cfg(test)]
440mod tests {
441 use super::*;
442 use bitcoin::Network::Testnet;
443 use hex;
444
445 struct ExpectedValues {
446 master_key: &'static str,
447 node_secret_key: &'static str,
448 node_id: &'static str,
449 channels_seed: &'static str,
450 keys_id: &'static str,
451 funding_key: &'static str,
452 commitment_seed: &'static str,
453 account_extended_key: &'static str,
454 }
455
456 #[test]
457 fn test_key_path_len() {
458 assert_eq!(Some(1), KeyDerivationStyle::Native.get_key_path_len());
459 assert_eq!(Some(2), KeyDerivationStyle::Lnd.get_key_path_len());
460 assert_eq!(None, KeyDerivationStyle::Ldk.get_key_path_len());
461 }
462
463 #[test]
464 fn test_derivation() {
465 let tests = [
466 (
467 KeyDerivationStyle::Native,
468 ExpectedValues {
469 master_key: "tprv8ZgxMBicQKsPfBjs724zXetsAfo8GqUTLKFgWsb92txrGoW9De1DTABH7htVkp1jS9ZhNws7do3UNPZreZru8MNXvWDrTxoecc2wnTYrb4S",
470 node_secret_key: "aae7ec5943df6bf7f26773729b3ac9a12ee428bbc4e6e2fbd27f3cf78cfe6d86",
471 node_id: "026f61d7ee82f937f9697f4f3e44bfaaa25849cc4f526b3a57326130eba6346002",
472 channels_seed: "7e273adccc072169f5a1cb1aee23a2d6986b6cbbeff4f0995d2762ac7c0b2511",
473 keys_id: "36814b08b8410cf33c02217de2c24f800b46642355d5c4be3a78c7d5d924af38",
474 funding_key: "b70812d9d05617ac829ffa666bd0a7ddbbd5303b562fa2ead2a842440333eff4",
475 commitment_seed: "fd8c46daa8eda9211b6cf4461003c8cc6aaa98024b438779f08254e4e67ae60c",
476 account_extended_key: "tprv8eoZddcAfpUQZNYYcJEVkpyfpss9vmBPvFMQ3CZrAxhoKpc6cM36XQJZ8jRbSuH7bouYBbKL6iQ5F4W3H2sh6NobCi4A9CJ3LJEUfDvmKib",
477 },
478 ),
479 (
480 KeyDerivationStyle::Ldk,
481 ExpectedValues {
482 master_key: "tprv8ZgxMBicQKsPdDdJFAqvG3mt4VqsVV125X4vsor5NxK366upt6qvovLQqaCi5SJiCE1aLkt3HtxsnTpzeGu27kPC5RUCr4h3oPBPYnAvhdE",
483 node_secret_key: "31bbbef9e06c9ffe3fec8fa24030bccd561ca8e92dded97af7cea6ca3ac85a84",
484 node_id: "0355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c23",
485 channels_seed: "7e273adccc072169f5a1cb1aee23a2d6986b6cbbeff4f0995d2762ac7c0b2511",
486 keys_id: "0000000038410cf33c02217de2c24f800b46642355d5c4be3a78c7d5d924af38",
487 funding_key: "6c0816a87b3a49abcf9fb4d8f2dfa8fd422a26c80ed1c8ca125a5ef2b028308b",
488 commitment_seed: "4589ed83ea68e56ce041918fdd17bd3bb47ca8bcc992f8be1495da0a05a54ba5",
489 account_extended_key: "tprv8eoZddcAfpUQZNYYcJEVkpyfpss9vmBPvFMQ3CZrAxhoKpc6cM36XQJZ8jRbSuH7bouYBbKL6iQ5F4W3H2sh6NobCi4A9CJ3LJEUfDvmKib",
490 },
491 ),
492 (
493 KeyDerivationStyle::Lnd,
494 ExpectedValues {
495 master_key: "tprv8ZgxMBicQKsPdDdJFAqvG3mt4VqsVV125X4vsor5NxK366upt6qvovLQqaCi5SJiCE1aLkt3HtxsnTpzeGu27kPC5RUCr4h3oPBPYnAvhdE",
496 node_secret_key: "a0794f0889ab261bd7ebdd8f33bfcea8497a0c429c58bde6e60ef157923fa787",
497 node_id: "02be197c34dccb4c23a6312404b78f8570519105f79dea0bdc947200354b6d1d34",
498 channels_seed: "7e273adccc072169f5a1cb1aee23a2d6986b6cbbeff4f0995d2762ac7c0b2511",
499 keys_id: "36814b08b8410cf33c02217de2c24f800b46642355d5c4be3a78c7d5d924af38",
500 funding_key: "78575e487b25b2cb527a0a67596841e4663e3b37c1da8015f290d1b951d701c2",
501 commitment_seed: "fd8c46daa8eda9211b6cf4461003c8cc6aaa98024b438779f08254e4e67ae60c",
502 account_extended_key: "tprv8fwV3nqr6mWFtQMxEmSGN9gbgxaoNzRms4dVeFSp3nG8chPHTmHA6razFaCUrtStcczbFDpazwBnsLkQ2uXK7rR9SxW3L92E7k6ZwTiMpwZ",
503 },
504 ),
505 ];
506
507 for (style, expected) in tests {
508 let secp_ctx = Secp256k1::new();
509 let seed = [0x01; 32];
510 let channel_id = ChannelId::new(&[0x01; 32]);
511 let channel_seed_base = [0x02; 32];
512 let keys_id = [0u8; 32];
513 let derive = key_derive(style, Testnet);
514
515 let master_key = derive.master_key(&seed);
517 assert_eq!(
518 master_key.to_string(),
519 expected.master_key,
520 "master_key mismatch for {}",
521 style
522 );
523
524 let (node_id, node_secret_key) = derive.node_keys(&seed, &secp_ctx);
526 assert_eq!(
527 hex::encode(node_secret_key.secret_bytes()),
528 expected.node_secret_key,
529 "node_secret_key mismatch for {}",
530 style
531 );
532 assert_eq!(node_id.to_string(), expected.node_id, "node_id mismatch for {}", style);
533
534 let channels_seed = derive.channels_seed(&seed);
536 assert_eq!(
537 hex::encode(channels_seed),
538 expected.channels_seed,
539 "channels_seed mismatch for {}",
540 style
541 );
542
543 let keys_id_result = derive.keys_id(channel_id.clone(), &channel_seed_base);
545 assert_eq!(
546 hex::encode(keys_id_result),
547 expected.keys_id,
548 "keys_id mismatch for {}",
549 style
550 );
551
552 let (funding_key, _, _, _, _, commitment_seed) =
554 derive.channel_keys(&seed, &keys_id, 0, &master_key, &secp_ctx);
555 assert_eq!(
556 hex::encode(funding_key.secret_bytes()),
557 expected.funding_key,
558 "funding_key mismatch for {}",
559 style
560 );
561 assert_eq!(
562 hex::encode(commitment_seed),
563 expected.commitment_seed,
564 "commitment_seed mismatch for {}",
565 style
566 );
567
568 let account_key = style.get_account_extended_key(&secp_ctx, Testnet, &seed);
570 assert_eq!(
571 account_key.to_string(),
572 expected.account_extended_key,
573 "account_extended_key mismatch for {}",
574 style
575 );
576 }
577 }
578}