Skip to content

Commit 0fade58

Browse files
committed
Make ChannelKeys an API and template Channel with it.
Instead of having in-memory access to the list of private keys associated with a channel, we should have a generic API which allows us to request signing, allowing the user to store private keys any way they like. The first step is the (rather mechanical) process of templating the entire tree of ChannelManager -> Channel impls by the key-providing type. In a later commit we should expose only public keys where possible.
1 parent 2344c91 commit 0fade58

9 files changed

+180
-133
lines changed

fuzz/fuzz_targets/chanmon_fail_consistency.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use bitcoin_hashes::sha256d::Hash as Sha256d;
3232
use lightning::chain::chaininterface;
3333
use lightning::chain::transaction::OutPoint;
3434
use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,ChainListener,FeeEstimator,ChainWatchInterfaceUtil};
35-
use lightning::chain::keysinterface::{ChannelKeys, KeysInterface};
35+
use lightning::chain::keysinterface::{InMemoryChannelKeys, KeysInterface};
3636
use lightning::ln::channelmonitor;
3737
use lightning::ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, HTLCUpdate};
3838
use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, ChannelManagerReadArgs};
@@ -139,6 +139,8 @@ struct KeyProvider {
139139
channel_id: atomic::AtomicU8,
140140
}
141141
impl KeysInterface for KeyProvider {
142+
type ChanKeySigner = InMemoryChannelKeys;
143+
142144
fn get_node_secret(&self) -> SecretKey {
143145
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, self.node_id]).unwrap()
144146
}
@@ -155,8 +157,8 @@ impl KeysInterface for KeyProvider {
155157
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, self.node_id]).unwrap())
156158
}
157159

158-
fn get_channel_keys(&self, _inbound: bool) -> ChannelKeys {
159-
ChannelKeys {
160+
fn get_channel_keys(&self, _inbound: bool) -> InMemoryChannelKeys {
161+
InMemoryChannelKeys {
160162
funding_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, self.node_id]).unwrap(),
161163
revocation_base_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, self.node_id]).unwrap(),
162164
payment_base_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, self.node_id]).unwrap(),
@@ -232,7 +234,7 @@ pub fn do_test(data: &[u8]) {
232234
channel_monitors: &monitor_refs,
233235
};
234236

235-
let res = (<(Sha256d, ChannelManager)>::read(&mut Cursor::new(&$ser.0), read_args).expect("Failed to read manager").1, monitor);
237+
let res = (<(Sha256d, ChannelManager<InMemoryChannelKeys>)>::read(&mut Cursor::new(&$ser.0), read_args).expect("Failed to read manager").1, monitor);
236238
for (_, was_good) in $old_monitors.latest_updates_good_at_last_ser.lock().unwrap().iter() {
237239
if !was_good {
238240
// If the last time we updated a monitor we didn't successfully update (and we

fuzz/fuzz_targets/full_stack_target.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use bitcoin_hashes::sha256d::Hash as Sha256dHash;
2828

2929
use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,ChainListener,FeeEstimator,ChainWatchInterfaceUtil};
3030
use lightning::chain::transaction::OutPoint;
31-
use lightning::chain::keysinterface::{ChannelKeys, KeysInterface};
31+
use lightning::chain::keysinterface::{InMemoryChannelKeys, KeysInterface};
3232
use lightning::ln::channelmonitor;
3333
use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage};
3434
use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor};
@@ -145,7 +145,7 @@ impl<'a> Hash for Peer<'a> {
145145
}
146146

147147
struct MoneyLossDetector<'a, 'b> {
148-
manager: Arc<ChannelManager<'b>>,
148+
manager: Arc<ChannelManager<'b, InMemoryChannelKeys>>,
149149
monitor: Arc<channelmonitor::SimpleManyChannelMonitor<OutPoint>>,
150150
handler: PeerManager<Peer<'a>>,
151151

@@ -158,7 +158,7 @@ struct MoneyLossDetector<'a, 'b> {
158158
blocks_connected: u32,
159159
}
160160
impl<'a, 'b> MoneyLossDetector<'a, 'b> {
161-
pub fn new(peers: &'a RefCell<[bool; 256]>, manager: Arc<ChannelManager<'b>>, monitor: Arc<channelmonitor::SimpleManyChannelMonitor<OutPoint>>, handler: PeerManager<Peer<'a>>) -> Self {
161+
pub fn new(peers: &'a RefCell<[bool; 256]>, manager: Arc<ChannelManager<'b, InMemoryChannelKeys>>, monitor: Arc<channelmonitor::SimpleManyChannelMonitor<OutPoint>>, handler: PeerManager<Peer<'a>>) -> Self {
162162
MoneyLossDetector {
163163
manager,
164164
monitor,
@@ -238,6 +238,8 @@ struct KeyProvider {
238238
counter: AtomicU64,
239239
}
240240
impl KeysInterface for KeyProvider {
241+
type ChanKeySigner = InMemoryChannelKeys;
242+
241243
fn get_node_secret(&self) -> SecretKey {
242244
self.node_secret.clone()
243245
}
@@ -254,10 +256,10 @@ impl KeysInterface for KeyProvider {
254256
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap())
255257
}
256258

257-
fn get_channel_keys(&self, inbound: bool) -> ChannelKeys {
259+
fn get_channel_keys(&self, inbound: bool) -> InMemoryChannelKeys {
258260
let ctr = self.counter.fetch_add(1, Ordering::Relaxed) as u8;
259261
if inbound {
260-
ChannelKeys {
262+
InMemoryChannelKeys {
261263
funding_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ctr]).unwrap(),
262264
revocation_base_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, ctr]).unwrap(),
263265
payment_base_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, ctr]).unwrap(),
@@ -266,7 +268,7 @@ impl KeysInterface for KeyProvider {
266268
commitment_seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, ctr],
267269
}
268270
} else {
269-
ChannelKeys {
271+
InMemoryChannelKeys {
270272
funding_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, ctr]).unwrap(),
271273
revocation_base_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, ctr]).unwrap(),
272274
payment_base_key: SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, ctr]).unwrap(),

lightning/src/chain/keysinterface.rs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ pub enum SpendableOutputDescriptor {
6868

6969
/// A trait to describe an object which can get user secrets and key material.
7070
pub trait KeysInterface: Send + Sync {
71+
/// A type which implements ChannelKeys which will be returned by get_channel_keys.
72+
type ChanKeySigner : ChannelKeys;
73+
7174
/// Get node secret key (aka node_id or network_key)
7275
fn get_node_secret(&self) -> SecretKey;
7376
/// Get destination redeemScript to encumber static protocol exit points.
@@ -76,7 +79,7 @@ pub trait KeysInterface: Send + Sync {
7679
fn get_shutdown_pubkey(&self) -> PublicKey;
7780
/// Get a new set of ChannelKeys for per-channel secrets. These MUST be unique even if you
7881
/// restarted with some stale data!
79-
fn get_channel_keys(&self, inbound: bool) -> ChannelKeys;
82+
fn get_channel_keys(&self, inbound: bool) -> Self::ChanKeySigner;
8083
/// Get a secret and PRNG seed for construting an onion packet
8184
fn get_onion_rand(&self) -> (SecretKey, [u8; 32]);
8285
/// Get a unique temporary channel id. Channels will be referred to by this until the funding
@@ -85,9 +88,33 @@ pub trait KeysInterface: Send + Sync {
8588
fn get_channel_id(&self) -> [u8; 32];
8689
}
8790

88-
/// Set of lightning keys needed to operate a channel as described in BOLT 3
91+
/// Set of lightning keys needed to operate a channel as described in BOLT 3.
92+
///
93+
/// If you're implementing a custom signer, you almost certainly want to implement
94+
/// Readable/Writable to serialize out a unique reference to this set of keys so
95+
/// that you can serialize the full ChannelManager object.
96+
///
97+
/// (TODO: We shouldn't require that, and should have an API to get them at deser time, due mostly
98+
/// to the possibility of reentrancy issues by calling the user's code during our deserialization
99+
/// routine).
100+
pub trait ChannelKeys : Clone + Send {
101+
/// Gets the private key for the anchor tx
102+
fn funding_key<'a>(&'a self) -> &'a SecretKey;
103+
/// Gets the local secret key for blinded revocation pubkey
104+
fn revocation_base_key<'a>(&'a self) -> &'a SecretKey;
105+
/// Gets the local secret key used in commitment tx htlc outputs
106+
fn payment_base_key<'a>(&'a self) -> &'a SecretKey;
107+
/// Gets the local secret key used in HTLC tx
108+
fn delayed_payment_base_key<'a>(&'a self) -> &'a SecretKey;
109+
/// Gets the local htlc secret key used in commitment tx htlc outputs
110+
fn htlc_base_key<'a>(&'a self) -> &'a SecretKey;
111+
/// Gets the commitment seed
112+
fn commitment_seed<'a>(&'a self) -> &'a [u8; 32];
113+
}
114+
89115
#[derive(Clone)]
90-
pub struct ChannelKeys {
116+
/// A simple implementation of ChannelKeys that just keeps the private keys in memory.
117+
pub struct InMemoryChannelKeys {
91118
/// Private key of anchor tx
92119
pub funding_key: SecretKey,
93120
/// Local secret key for blinded revocation pubkey
@@ -102,7 +129,16 @@ pub struct ChannelKeys {
102129
pub commitment_seed: [u8; 32],
103130
}
104131

105-
impl_writeable!(ChannelKeys, 0, {
132+
impl ChannelKeys for InMemoryChannelKeys {
133+
fn funding_key(&self) -> &SecretKey { &self.funding_key }
134+
fn revocation_base_key(&self) -> &SecretKey { &self.revocation_base_key }
135+
fn payment_base_key(&self) -> &SecretKey { &self.payment_base_key }
136+
fn delayed_payment_base_key(&self) -> &SecretKey { &self.delayed_payment_base_key }
137+
fn htlc_base_key(&self) -> &SecretKey { &self.htlc_base_key }
138+
fn commitment_seed(&self) -> &[u8; 32] { &self.commitment_seed }
139+
}
140+
141+
impl_writeable!(InMemoryChannelKeys, 0, {
106142
funding_key,
107143
revocation_base_key,
108144
payment_base_key,
@@ -203,6 +239,8 @@ impl KeysManager {
203239
}
204240

205241
impl KeysInterface for KeysManager {
242+
type ChanKeySigner = InMemoryChannelKeys;
243+
206244
fn get_node_secret(&self) -> SecretKey {
207245
self.node_secret.clone()
208246
}
@@ -215,7 +253,7 @@ impl KeysInterface for KeysManager {
215253
self.shutdown_pubkey.clone()
216254
}
217255

218-
fn get_channel_keys(&self, _inbound: bool) -> ChannelKeys {
256+
fn get_channel_keys(&self, _inbound: bool) -> InMemoryChannelKeys {
219257
// We only seriously intend to rely on the channel_master_key for true secure
220258
// entropy, everything else just ensures uniqueness. We rely on the unique_start (ie
221259
// starting_time provided in the constructor) to be unique.
@@ -248,7 +286,7 @@ impl KeysInterface for KeysManager {
248286
let delayed_payment_base_key = key_step!(b"delayed payment base key", payment_base_key);
249287
let htlc_base_key = key_step!(b"HTLC base key", delayed_payment_base_key);
250288

251-
ChannelKeys {
289+
InMemoryChannelKeys {
252290
funding_key,
253291
revocation_base_key,
254292
payment_base_key,

lightning/src/ln/chan_utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ pub const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663;
2020
// Various functions for key derivation and transaction creation for use within channels. Primarily
2121
// used in Channel and ChannelMonitor.
2222

23-
pub fn build_commitment_secret(commitment_seed: [u8; 32], idx: u64) -> [u8; 32] {
24-
let mut res: [u8; 32] = commitment_seed;
23+
pub fn build_commitment_secret(commitment_seed: &[u8; 32], idx: u64) -> [u8; 32] {
24+
let mut res: [u8; 32] = commitment_seed.clone();
2525
for i in 0..48 {
2626
let bitpos = 47 - i;
2727
if idx & (1 << bitpos) == (1 << bitpos) {

0 commit comments

Comments
 (0)