Skip to content

Commit 04c2bfc

Browse files
committed
Make payment_key derivation deterministic
Previously, `KeysManager::derive_channel_keys` would derive the channel's `payment_key` uniquely on a per-channel basis which would disallow users losing their `channel_keys_id` to recover funds. As it's no real necessity to have `payment_key` derivation depend on `channel_keys_id` we can allow for easier recovery of any non-HTLC encumbered funds if we make `payment_key` derivation deterministic. To this end, we use the first byte of `channel_keys_id` as a versioning byte indicating the version of the used channel keys derivation scheme. Note that Previously `KeysManager::generate_channel_keys_id` would with very high likelyhood never have generated a `channel_keys_id` with a non-null first byte, which makes this a backwards-compatible change for any users that didn't run custom implementations of `SignerProvider::generate_channel_keys_id` conflicting with this assumption.
1 parent 6756dde commit 04c2bfc

File tree

1 file changed

+57
-12
lines changed

1 file changed

+57
-12
lines changed

lightning/src/sign/mod.rs

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1983,29 +1983,61 @@ impl KeysManager {
19831983
.expect("Your RNG is busted");
19841984
unique_start.input(&child_privkey.private_key[..]);
19851985

1986-
let seed = Sha256::from_engine(unique_start).to_byte_array();
1986+
let unique_seed = Sha256::from_engine(unique_start).to_byte_array();
19871987

19881988
let commitment_seed = {
19891989
let mut sha = Sha256::engine();
1990-
sha.input(&seed);
1990+
sha.input(&unique_seed);
19911991
sha.input(&b"commitment seed"[..]);
19921992
Sha256::from_engine(sha).to_byte_array()
19931993
};
19941994
macro_rules! key_step {
19951995
($info: expr, $prev_key: expr) => {{
19961996
let mut sha = Sha256::engine();
1997-
sha.input(&seed);
1997+
sha.input(&unique_seed);
19981998
sha.input(&$prev_key[..]);
19991999
sha.input(&$info[..]);
20002000
SecretKey::from_slice(&Sha256::from_engine(sha).to_byte_array())
20012001
.expect("SHA-256 is busted")
20022002
}};
20032003
}
2004-
let funding_key = key_step!(b"funding key", commitment_seed);
2005-
let revocation_base_key = key_step!(b"revocation base key", funding_key);
2006-
let payment_key = key_step!(b"payment key", revocation_base_key);
2007-
let delayed_payment_base_key = key_step!(b"delayed payment base key", payment_key);
2008-
let htlc_base_key = key_step!(b"HTLC base key", delayed_payment_base_key);
2004+
2005+
let funding_key;
2006+
let revocation_base_key;
2007+
let payment_key;
2008+
let delayed_payment_base_key;
2009+
let htlc_base_key;
2010+
2011+
let channel_keys_derivation_version =
2012+
channel_keys_derivation_version_from_id(channel_keys_id);
2013+
if channel_keys_derivation_version < 1 {
2014+
// In LDK versions prior to 0.1 we used to derive the `payment_key` uniquely on a
2015+
// per-channel basis, which disallowed users to re-derive them if they lost their
2016+
// `channel_keys_id`.
2017+
funding_key = key_step!(b"funding key", commitment_seed);
2018+
revocation_base_key = key_step!(b"revocation base key", funding_key);
2019+
payment_key = key_step!(b"payment key", revocation_base_key);
2020+
delayed_payment_base_key = key_step!(b"delayed payment base key", payment_key);
2021+
htlc_base_key = key_step!(b"HTLC base key", delayed_payment_base_key);
2022+
} else {
2023+
funding_key = key_step!(b"funding key", commitment_seed);
2024+
revocation_base_key = key_step!(b"revocation base key", funding_key);
2025+
delayed_payment_base_key = key_step!(b"delayed payment base key", revocation_base_key);
2026+
htlc_base_key = key_step!(b"HTLC base key", delayed_payment_base_key);
2027+
2028+
// Starting with LDK v0.1, we derive `payment_key` directly from our seed, allowing
2029+
// users to re-derive it even when losing all channel state. This allows them to
2030+
// recover any non-HTLC-encumbered funds in case of data loss if the counterparty is so
2031+
// nice to force-closure for them.
2032+
payment_key = {
2033+
let mut sha = Sha256::engine();
2034+
sha.input(&self.seed);
2035+
sha.input(&b"static payment key"[..]);
2036+
SecretKey::from_slice(&Sha256::from_engine(sha).to_byte_array())
2037+
.expect("SHA-256 is busted")
2038+
};
2039+
};
2040+
20092041
let prng_seed = self.get_secure_random_bytes();
20102042

20112043
InMemorySigner::new(
@@ -2249,6 +2281,14 @@ impl OutputSpender for KeysManager {
22492281
}
22502282
}
22512283

2284+
/// The version of the channel key derivation scheme.
2285+
pub(crate) const CHANNEL_KEYS_DERIVATION_VERSION: u8 = 1;
2286+
2287+
/// Returns the keys derviation version set in `channel_keys_id`.
2288+
pub(crate) fn channel_keys_derivation_version_from_id(channel_keys_id: [u8; 32]) -> u8 {
2289+
channel_keys_id[0]
2290+
}
2291+
22522292
impl SignerProvider for KeysManager {
22532293
type EcdsaSigner = InMemorySigner;
22542294
#[cfg(taproot)]
@@ -2261,11 +2301,16 @@ impl SignerProvider for KeysManager {
22612301
// `child_idx` is the only thing guaranteed to make each channel unique without a restart
22622302
// (though `user_channel_id` should help, depending on user behavior). If it manages to
22632303
// roll over, we may generate duplicate keys for two different channels, which could result
2264-
// in loss of funds. Because we only support 32-bit+ systems, assert that our `AtomicUsize`
2265-
// doesn't reach `u32::MAX`.
2266-
assert!(child_idx < core::u32::MAX as usize, "2^32 channels opened without restart");
2304+
// in loss of funds. Because we only support 32-bit+ systems, and we use the first byte as
2305+
// a versioning field, assert that our `AtomicUsize`
2306+
// doesn't reach the maximal 24-bit value, i.e., `U24_MAX`.
2307+
const U24_MAX: usize = 0xFFFFFFF;
2308+
assert!(child_idx < U24_MAX, "2^31 channels opened without restart");
2309+
let child_idx_be_bytes = (child_idx as u32).to_be_bytes();
2310+
22672311
let mut id = [0; 32];
2268-
id[0..4].copy_from_slice(&(child_idx as u32).to_be_bytes());
2312+
id[0] = CHANNEL_KEYS_DERIVATION_VERSION;
2313+
id[1..4].copy_from_slice(&child_idx_be_bytes[1..4]);
22692314
id[4..8].copy_from_slice(&self.starting_time_nanos.to_be_bytes());
22702315
id[8..16].copy_from_slice(&self.starting_time_secs.to_be_bytes());
22712316
id[16..32].copy_from_slice(&user_channel_id.to_be_bytes());

0 commit comments

Comments
 (0)