Skip to content

Commit edab29e

Browse files
authored
Merge pull request #404 from TheBlueMatt/2019-11-signer-api
Replace keys API with Signer API to support hardware wallets eventually
2 parents 71e6995 + 35814b6 commit edab29e

13 files changed

+396
-170
lines changed

fuzz/src/chanmon_consistency.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use bitcoin_hashes::sha256d::Hash as Sha256d;
2424
use lightning::chain::chaininterface;
2525
use lightning::chain::transaction::OutPoint;
2626
use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,ChainListener,FeeEstimator,ChainWatchInterfaceUtil};
27-
use lightning::chain::keysinterface::{ChannelKeys, KeysInterface};
27+
use lightning::chain::keysinterface::{InMemoryChannelKeys, KeysInterface};
2828
use lightning::ln::channelmonitor;
2929
use lightning::ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, HTLCUpdate};
3030
use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, ChannelManagerReadArgs};
@@ -130,6 +130,8 @@ struct KeyProvider {
130130
channel_id: atomic::AtomicU8,
131131
}
132132
impl KeysInterface for KeyProvider {
133+
type ChanKeySigner = InMemoryChannelKeys;
134+
133135
fn get_node_secret(&self) -> SecretKey {
134136
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()
135137
}
@@ -146,8 +148,8 @@ impl KeysInterface for KeyProvider {
146148
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())
147149
}
148150

149-
fn get_channel_keys(&self, _inbound: bool) -> ChannelKeys {
150-
ChannelKeys {
151+
fn get_channel_keys(&self, _inbound: bool) -> InMemoryChannelKeys {
152+
InMemoryChannelKeys {
151153
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(),
152154
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(),
153155
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(),
@@ -223,7 +225,7 @@ pub fn do_test(data: &[u8]) {
223225
channel_monitors: &monitor_refs,
224226
};
225227

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

fuzz/src/full_stack.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use bitcoin_hashes::sha256d::Hash as Sha256dHash;
2020

2121
use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,ChainListener,FeeEstimator,ChainWatchInterfaceUtil};
2222
use lightning::chain::transaction::OutPoint;
23-
use lightning::chain::keysinterface::{ChannelKeys, KeysInterface};
23+
use lightning::chain::keysinterface::{InMemoryChannelKeys, KeysInterface};
2424
use lightning::ln::channelmonitor;
2525
use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage};
2626
use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor};
@@ -135,7 +135,7 @@ impl<'a> Hash for Peer<'a> {
135135
}
136136

137137
struct MoneyLossDetector<'a, 'b> {
138-
manager: Arc<ChannelManager<'b>>,
138+
manager: Arc<ChannelManager<'b, InMemoryChannelKeys>>,
139139
monitor: Arc<channelmonitor::SimpleManyChannelMonitor<OutPoint>>,
140140
handler: PeerManager<Peer<'a>>,
141141

@@ -148,7 +148,7 @@ struct MoneyLossDetector<'a, 'b> {
148148
blocks_connected: u32,
149149
}
150150
impl<'a, 'b> MoneyLossDetector<'a, 'b> {
151-
pub fn new(peers: &'a RefCell<[bool; 256]>, manager: Arc<ChannelManager<'b>>, monitor: Arc<channelmonitor::SimpleManyChannelMonitor<OutPoint>>, handler: PeerManager<Peer<'a>>) -> Self {
151+
pub fn new(peers: &'a RefCell<[bool; 256]>, manager: Arc<ChannelManager<'b, InMemoryChannelKeys>>, monitor: Arc<channelmonitor::SimpleManyChannelMonitor<OutPoint>>, handler: PeerManager<Peer<'a>>) -> Self {
152152
MoneyLossDetector {
153153
manager,
154154
monitor,
@@ -228,6 +228,8 @@ struct KeyProvider {
228228
counter: AtomicU64,
229229
}
230230
impl KeysInterface for KeyProvider {
231+
type ChanKeySigner = InMemoryChannelKeys;
232+
231233
fn get_node_secret(&self) -> SecretKey {
232234
self.node_secret.clone()
233235
}
@@ -244,10 +246,10 @@ impl KeysInterface for KeyProvider {
244246
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())
245247
}
246248

247-
fn get_channel_keys(&self, inbound: bool) -> ChannelKeys {
249+
fn get_channel_keys(&self, inbound: bool) -> InMemoryChannelKeys {
248250
let ctr = self.counter.fetch_add(1, Ordering::Relaxed) as u8;
249251
if inbound {
250-
ChannelKeys {
252+
InMemoryChannelKeys {
251253
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(),
252254
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(),
253255
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(),
@@ -256,7 +258,7 @@ impl KeysInterface for KeyProvider {
256258
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],
257259
}
258260
} else {
259-
ChannelKeys {
261+
InMemoryChannelKeys {
260262
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(),
261263
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(),
262264
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

+101-8
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,28 @@
22
//! spendable on-chain outputs which the user owns and is responsible for using just as any other
33
//! on-chain output which is theirs.
44
5-
use bitcoin::blockdata::transaction::{OutPoint, TxOut};
5+
use bitcoin::blockdata::transaction::{Transaction, OutPoint, TxOut};
66
use bitcoin::blockdata::script::{Script, Builder};
77
use bitcoin::blockdata::opcodes;
88
use bitcoin::network::constants::Network;
99
use bitcoin::util::bip32::{ExtendedPrivKey, ExtendedPubKey, ChildNumber};
10+
use bitcoin::util::bip143;
1011

1112
use bitcoin_hashes::{Hash, HashEngine};
1213
use bitcoin_hashes::sha256::HashEngine as Sha256State;
1314
use bitcoin_hashes::sha256::Hash as Sha256;
1415
use bitcoin_hashes::hash160::Hash as Hash160;
1516

1617
use secp256k1::key::{SecretKey, PublicKey};
17-
use secp256k1::Secp256k1;
18+
use secp256k1::{Secp256k1, Signature};
1819
use secp256k1;
1920

2021
use util::byte_utils;
2122
use util::logger::Logger;
2223

24+
use ln::chan_utils;
25+
use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment};
26+
2327
use std::sync::Arc;
2428
use std::sync::atomic::{AtomicUsize, Ordering};
2529

@@ -68,6 +72,9 @@ pub enum SpendableOutputDescriptor {
6872

6973
/// A trait to describe an object which can get user secrets and key material.
7074
pub trait KeysInterface: Send + Sync {
75+
/// A type which implements ChannelKeys which will be returned by get_channel_keys.
76+
type ChanKeySigner : ChannelKeys;
77+
7178
/// Get node secret key (aka node_id or network_key)
7279
fn get_node_secret(&self) -> SecretKey;
7380
/// Get destination redeemScript to encumber static protocol exit points.
@@ -76,7 +83,7 @@ pub trait KeysInterface: Send + Sync {
7683
fn get_shutdown_pubkey(&self) -> PublicKey;
7784
/// Get a new set of ChannelKeys for per-channel secrets. These MUST be unique even if you
7885
/// restarted with some stale data!
79-
fn get_channel_keys(&self, inbound: bool) -> ChannelKeys;
86+
fn get_channel_keys(&self, inbound: bool) -> Self::ChanKeySigner;
8087
/// Get a secret and PRNG seed for construting an onion packet
8188
fn get_onion_rand(&self) -> (SecretKey, [u8; 32]);
8289
/// Get a unique temporary channel id. Channels will be referred to by this until the funding
@@ -85,9 +92,59 @@ pub trait KeysInterface: Send + Sync {
8592
fn get_channel_id(&self) -> [u8; 32];
8693
}
8794

88-
/// Set of lightning keys needed to operate a channel as described in BOLT 3
95+
/// Set of lightning keys needed to operate a channel as described in BOLT 3.
96+
///
97+
/// Signing services could be implemented on a hardware wallet. In this case,
98+
/// the current ChannelKeys would be a front-end on top of a communication
99+
/// channel connected to your secure device and lightning key material wouldn't
100+
/// reside on a hot server. Nevertheless, a this deployment would still need
101+
/// to trust the ChannelManager to avoid loss of funds as this latest component
102+
/// could ask to sign commitment transaction with HTLCs paying to attacker pubkeys.
103+
///
104+
/// A more secure iteration would be to use hashlock (or payment points) to pair
105+
/// invoice/incoming HTLCs with outgoing HTLCs to implement a no-trust-ChannelManager
106+
/// at the price of more state and computation on the hardware wallet side. In the future,
107+
/// we are looking forward to design such interface.
108+
///
109+
/// In any case, ChannelMonitor or fallback watchtowers are always going to be trusted
110+
/// to act, as liveness and breach reply correctness are always going to be hard requirements
111+
/// of LN security model, orthogonal of key management issues.
112+
///
113+
/// If you're implementing a custom signer, you almost certainly want to implement
114+
/// Readable/Writable to serialize out a unique reference to this set of keys so
115+
/// that you can serialize the full ChannelManager object.
116+
///
117+
/// (TODO: We shouldn't require that, and should have an API to get them at deser time, due mostly
118+
/// to the possibility of reentrancy issues by calling the user's code during our deserialization
119+
/// routine).
120+
pub trait ChannelKeys : Send {
121+
/// Gets the private key for the anchor tx
122+
fn funding_key<'a>(&'a self) -> &'a SecretKey;
123+
/// Gets the local secret key for blinded revocation pubkey
124+
fn revocation_base_key<'a>(&'a self) -> &'a SecretKey;
125+
/// Gets the local secret key used in to_remote output of remote commitment tx
126+
/// (and also as part of obscured commitment number)
127+
fn payment_base_key<'a>(&'a self) -> &'a SecretKey;
128+
/// Gets the local secret key used in HTLC-Success/HTLC-Timeout txn and to_local output
129+
fn delayed_payment_base_key<'a>(&'a self) -> &'a SecretKey;
130+
/// Gets the local htlc secret key used in commitment tx htlc outputs
131+
fn htlc_base_key<'a>(&'a self) -> &'a SecretKey;
132+
/// Gets the commitment seed
133+
fn commitment_seed<'a>(&'a self) -> &'a [u8; 32];
134+
135+
/// Create a signature for a remote commitment transaction and associated HTLC transactions.
136+
///
137+
/// Note that if signing fails or is rejected, the channel will be force-closed.
138+
///
139+
/// TODO: Document the things someone using this interface should enforce before signing.
140+
/// TODO: Add more input vars to enable better checking (preferably removing commitment_tx and
141+
/// making the callee generate it via some util function we expose)!
142+
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_script: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
143+
}
144+
89145
#[derive(Clone)]
90-
pub struct ChannelKeys {
146+
/// A simple implementation of ChannelKeys that just keeps the private keys in memory.
147+
pub struct InMemoryChannelKeys {
91148
/// Private key of anchor tx
92149
pub funding_key: SecretKey,
93150
/// Local secret key for blinded revocation pubkey
@@ -102,7 +159,41 @@ pub struct ChannelKeys {
102159
pub commitment_seed: [u8; 32],
103160
}
104161

105-
impl_writeable!(ChannelKeys, 0, {
162+
impl ChannelKeys for InMemoryChannelKeys {
163+
fn funding_key(&self) -> &SecretKey { &self.funding_key }
164+
fn revocation_base_key(&self) -> &SecretKey { &self.revocation_base_key }
165+
fn payment_base_key(&self) -> &SecretKey { &self.payment_base_key }
166+
fn delayed_payment_base_key(&self) -> &SecretKey { &self.delayed_payment_base_key }
167+
fn htlc_base_key(&self) -> &SecretKey { &self.htlc_base_key }
168+
fn commitment_seed(&self) -> &[u8; 32] { &self.commitment_seed }
169+
170+
171+
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_script: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
172+
if commitment_tx.input.len() != 1 { return Err(()); }
173+
let commitment_sighash = hash_to_message!(&bip143::SighashComponents::new(&commitment_tx).sighash_all(&commitment_tx.input[0], &channel_funding_script, channel_value_satoshis)[..]);
174+
let commitment_sig = secp_ctx.sign(&commitment_sighash, &self.funding_key);
175+
176+
let commitment_txid = commitment_tx.txid();
177+
178+
let mut htlc_sigs = Vec::with_capacity(htlcs.len());
179+
for ref htlc in htlcs {
180+
if let Some(_) = htlc.transaction_output_index {
181+
let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, feerate_per_kw, to_self_delay, htlc, &keys.a_delayed_payment_key, &keys.revocation_key);
182+
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
183+
let htlc_sighash = hash_to_message!(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]);
184+
let our_htlc_key = match chan_utils::derive_private_key(&secp_ctx, &keys.per_commitment_point, &self.htlc_base_key) {
185+
Ok(s) => s,
186+
Err(_) => return Err(()),
187+
};
188+
htlc_sigs.push(secp_ctx.sign(&htlc_sighash, &our_htlc_key));
189+
}
190+
}
191+
192+
Ok((commitment_sig, htlc_sigs))
193+
}
194+
}
195+
196+
impl_writeable!(InMemoryChannelKeys, 0, {
106197
funding_key,
107198
revocation_base_key,
108199
payment_base_key,
@@ -203,6 +294,8 @@ impl KeysManager {
203294
}
204295

205296
impl KeysInterface for KeysManager {
297+
type ChanKeySigner = InMemoryChannelKeys;
298+
206299
fn get_node_secret(&self) -> SecretKey {
207300
self.node_secret.clone()
208301
}
@@ -215,7 +308,7 @@ impl KeysInterface for KeysManager {
215308
self.shutdown_pubkey.clone()
216309
}
217310

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

251-
ChannelKeys {
344+
InMemoryChannelKeys {
252345
funding_key,
253346
revocation_base_key,
254347
payment_base_key,

0 commit comments

Comments
 (0)