Skip to content

Commit d080d3a

Browse files
committed
Add NodeSigner::sign_gossip_message
Adds signing capability to NodeSigner for all gossip messages that require a node signature.
1 parent aee9952 commit d080d3a

File tree

6 files changed

+78
-21
lines changed

6 files changed

+78
-21
lines changed

fuzz/src/chanmon_consistency.rs

+23-16
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use bitcoin::network::constants::Network;
2929

3030
use bitcoin::hashes::Hash as TraitImport;
3131
use bitcoin::hashes::sha256::Hash as Sha256;
32+
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
3233
use bitcoin::hash_types::{BlockHash, WPubkeyHash};
3334

3435
use lightning::chain;
@@ -54,10 +55,9 @@ use lightning::routing::router::{InFlightHtlcs, Route, RouteHop, RouteParameters
5455
use crate::utils::test_logger::{self, Output};
5556
use crate::utils::test_persister::TestPersister;
5657

57-
use bitcoin::secp256k1::{PublicKey, SecretKey, Scalar};
58+
use bitcoin::secp256k1::{Message, PublicKey, SecretKey, Scalar, Secp256k1};
5859
use bitcoin::secp256k1::ecdh::SharedSecret;
59-
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
60-
use bitcoin::secp256k1::Secp256k1;
60+
use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
6161

6262
use std::mem;
6363
use std::cmp::{self, Ordering};
@@ -174,23 +174,23 @@ impl chain::Watch<EnforcingSigner> for TestChainMonitor {
174174
}
175175

176176
struct KeyProvider {
177-
node_id: u8,
177+
node_secret: SecretKey,
178178
rand_bytes_id: atomic::AtomicU32,
179179
enforcement_states: Mutex<HashMap<[u8;32], Arc<Mutex<EnforcementState>>>>,
180180
}
181181

182182
impl EntropySource for KeyProvider {
183183
fn get_secure_random_bytes(&self) -> [u8; 32] {
184184
let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed);
185-
let mut res = [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, 11, self.node_id];
185+
let mut res = [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, 11, self.node_secret[31]];
186186
res[30-4..30].copy_from_slice(&id.to_le_bytes());
187187
res
188188
}
189189
}
190190

191191
impl NodeSigner for KeyProvider {
192192
fn get_node_secret(&self, _recipient: Recipient) -> Result<SecretKey, ()> {
193-
Ok(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())
193+
Ok(self.node_secret.clone())
194194
}
195195

196196
fn get_node_id(&self, recipient: Recipient) -> Result<PublicKey, ()> {
@@ -207,12 +207,18 @@ impl NodeSigner for KeyProvider {
207207
}
208208

209209
fn get_inbound_payment_key_material(&self) -> KeyMaterial {
210-
KeyMaterial([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])
210+
KeyMaterial([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_secret[31]])
211211
}
212212

213213
fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result<RecoverableSignature, ()> {
214214
unreachable!()
215215
}
216+
217+
fn sign_gossip_message(&self, msg: lightning::ln::msgs::UnsignedGossipMessage) -> Result<Signature, ()> {
218+
let msg_hash = Message::from_slice(&Sha256dHash::hash(&msg.encode()[..])[..]).map_err(|_| ())?;
219+
let secp_ctx = Secp256k1::signing_only();
220+
Ok(secp_ctx.sign_ecdsa(&msg_hash, &self.node_secret))
221+
}
216222
}
217223

218224
impl SignerProvider for KeyProvider {
@@ -229,12 +235,12 @@ impl SignerProvider for KeyProvider {
229235
let keys = InMemorySigner::new(
230236
&secp_ctx,
231237
self.get_node_secret(Recipient::Node).unwrap(),
232-
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(),
233-
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(),
234-
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(),
235-
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, self.node_id]).unwrap(),
236-
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, self.node_id]).unwrap(),
237-
[id, 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, self.node_id],
238+
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_secret[31]]).unwrap(),
239+
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_secret[31]]).unwrap(),
240+
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_secret[31]]).unwrap(),
241+
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, self.node_secret[31]]).unwrap(),
242+
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, self.node_secret[31]]).unwrap(),
243+
[id, 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, self.node_secret[31]],
238244
channel_value_satoshis,
239245
channel_keys_id,
240246
);
@@ -257,14 +263,14 @@ impl SignerProvider for KeyProvider {
257263

258264
fn get_destination_script(&self) -> Script {
259265
let secp_ctx = Secp256k1::signing_only();
260-
let channel_monitor_claim_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, self.node_id]).unwrap();
266+
let channel_monitor_claim_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, self.node_secret[31]]).unwrap();
261267
let our_channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize());
262268
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()
263269
}
264270

265271
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
266272
let secp_ctx = Secp256k1::signing_only();
267-
let secret_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, self.node_id]).unwrap();
273+
let secret_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, self.node_secret[31]]).unwrap();
268274
let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize());
269275
ShutdownScript::new_p2wpkh(&pubkey_hash)
270276
}
@@ -402,7 +408,8 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
402408
macro_rules! make_node {
403409
($node_id: expr, $fee_estimator: expr) => { {
404410
let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new($node_id.to_string(), out.clone()));
405-
let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU32::new(0), enforcement_states: Mutex::new(HashMap::new()) });
411+
let node_secret = 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, $node_id]).unwrap();
412+
let keys_manager = Arc::new(KeyProvider { node_secret, rand_bytes_id: atomic::AtomicU32::new(0), enforcement_states: Mutex::new(HashMap::new()) });
406413
let monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), $fee_estimator.clone(),
407414
Arc::new(TestPersister {
408415
update_ret: Mutex::new(ChannelMonitorUpdateStatus::Completed)

fuzz/src/full_stack.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use bitcoin::network::constants::Network;
2626
use bitcoin::hashes::Hash as TraitImport;
2727
use bitcoin::hashes::HashEngine as TraitImportEngine;
2828
use bitcoin::hashes::sha256::Hash as Sha256;
29+
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
2930
use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};
3031

3132
use lightning::chain;
@@ -47,15 +48,14 @@ use lightning::util::errors::APIError;
4748
use lightning::util::events::Event;
4849
use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
4950
use lightning::util::logger::Logger;
50-
use lightning::util::ser::ReadableArgs;
51+
use lightning::util::ser::{ReadableArgs, Writeable};
5152

5253
use crate::utils::test_logger;
5354
use crate::utils::test_persister::TestPersister;
5455

55-
use bitcoin::secp256k1::{PublicKey, SecretKey, Scalar};
56+
use bitcoin::secp256k1::{Message, PublicKey, SecretKey, Scalar, Secp256k1};
5657
use bitcoin::secp256k1::ecdh::SharedSecret;
57-
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
58-
use bitcoin::secp256k1::Secp256k1;
58+
use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
5959

6060
use std::cell::RefCell;
6161
use hashbrown::{HashMap, hash_map};
@@ -317,6 +317,12 @@ impl NodeSigner for KeyProvider {
317317
fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result<RecoverableSignature, ()> {
318318
unreachable!()
319319
}
320+
321+
fn sign_gossip_message(&self, msg: lightning::ln::msgs::UnsignedGossipMessage) -> Result<Signature, ()> {
322+
let msg_hash = Message::from_slice(&Sha256dHash::hash(&msg.encode()[..])[..]).map_err(|_| ())?;
323+
let secp_ctx = Secp256k1::signing_only();
324+
Ok(secp_ctx.sign_ecdsa(&msg_hash, &self.node_secret))
325+
}
320326
}
321327

322328
impl SignerProvider for KeyProvider {

fuzz/src/onion_message.rs

+4
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ impl NodeSigner for KeyProvider {
122122
fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result<RecoverableSignature, ()> {
123123
unreachable!()
124124
}
125+
126+
fn sign_gossip_message(&self, _msg: lightning::ln::msgs::UnsignedGossipMessage) -> Result<bitcoin::secp256k1::ecdsa::Signature, ()> {
127+
unreachable!()
128+
}
125129
}
126130

127131
impl SignerProvider for KeyProvider {

lightning/src/chain/keysinterface.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use crate::chain::transaction::OutPoint;
4141
use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI;
4242
use crate::ln::{chan_utils, PaymentPreimage};
4343
use crate::ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction};
44-
use crate::ln::msgs::UnsignedChannelAnnouncement;
44+
use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage};
4545
use crate::ln::script::ShutdownScript;
4646

4747
use crate::prelude::*;
@@ -494,6 +494,14 @@ pub trait NodeSigner {
494494
///
495495
/// Errors if the [`Recipient`] variant is not supported by the implementation.
496496
fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result<RecoverableSignature, ()>;
497+
498+
/// Sign a gossip message.
499+
///
500+
/// Note that if this fails, LDK may panic and the message will not be broadcast to the network
501+
/// or a possible channel counterparty. If LDK panics, the error should be resolved to allow the
502+
/// message to be broadcast, as otherwise it may prevent one from receiving funds over the
503+
/// corresponding channel.
504+
fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result<Signature, ()>;
497505
}
498506

499507
/// A trait that can return signer instances for individual channels.
@@ -1290,6 +1298,11 @@ impl NodeSigner for KeysManager {
12901298
};
12911299
Ok(self.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), &secret))
12921300
}
1301+
1302+
fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result<Signature, ()> {
1303+
let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
1304+
Ok(sign(&self.secp_ctx, &msg_hash, &self.node_secret))
1305+
}
12931306
}
12941307

12951308
impl SignerProvider for KeysManager {
@@ -1394,6 +1407,10 @@ impl NodeSigner for PhantomKeysManager {
13941407
let secret = self.get_node_secret(recipient)?;
13951408
Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), &secret))
13961409
}
1410+
1411+
fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result<Signature, ()> {
1412+
self.inner.sign_gossip_message(msg)
1413+
}
13971414
}
13981415

13991416
impl SignerProvider for PhantomKeysManager {

lightning/src/ln/msgs.rs

+19
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,25 @@ impl Readable for NetAddress {
632632
}
633633
}
634634

635+
/// Represents the set of gossip messages that require a signature from a node's identity key.
636+
pub enum UnsignedGossipMessage<'a> {
637+
/// An unsigned channel announcement.
638+
ChannelAnnouncement(&'a UnsignedChannelAnnouncement),
639+
/// An unsigned channel update.
640+
ChannelUpdate(&'a UnsignedChannelUpdate),
641+
/// An unsigned node announcement.
642+
NodeAnnouncement(&'a UnsignedNodeAnnouncement)
643+
}
644+
645+
impl<'a> Writeable for UnsignedGossipMessage<'a> {
646+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
647+
match self {
648+
UnsignedGossipMessage::ChannelAnnouncement(ref msg) => msg.write(writer),
649+
UnsignedGossipMessage::ChannelUpdate(ref msg) => msg.write(writer),
650+
UnsignedGossipMessage::NodeAnnouncement(ref msg) => msg.write(writer),
651+
}
652+
}
653+
}
635654

636655
/// The unsigned part of a [`node_announcement`] message.
637656
///

lightning/src/util/test_utils.rs

+4
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,10 @@ impl NodeSigner for TestKeysInterface {
659659
fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result<RecoverableSignature, ()> {
660660
self.backing.sign_invoice(hrp_bytes, invoice_data, recipient)
661661
}
662+
663+
fn sign_gossip_message(&self, msg: msgs::UnsignedGossipMessage) -> Result<Signature, ()> {
664+
self.backing.sign_gossip_message(msg)
665+
}
662666
}
663667

664668
impl SignerProvider for TestKeysInterface {

0 commit comments

Comments
 (0)