mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-03-15 15:39:09 +01:00
Add NodeSigner::sign_gossip_message
Adds signing capability to NodeSigner for all gossip messages that require a node signature.
This commit is contained in:
parent
aee9952ea3
commit
db0d6ecdbb
6 changed files with 78 additions and 21 deletions
|
@ -29,6 +29,7 @@ use bitcoin::network::constants::Network;
|
|||
|
||||
use bitcoin::hashes::Hash as TraitImport;
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
|
||||
use bitcoin::hash_types::{BlockHash, WPubkeyHash};
|
||||
|
||||
use lightning::chain;
|
||||
|
@ -54,10 +55,9 @@ use lightning::routing::router::{InFlightHtlcs, Route, RouteHop, RouteParameters
|
|||
use crate::utils::test_logger::{self, Output};
|
||||
use crate::utils::test_persister::TestPersister;
|
||||
|
||||
use bitcoin::secp256k1::{PublicKey, SecretKey, Scalar};
|
||||
use bitcoin::secp256k1::{Message, PublicKey, SecretKey, Scalar, Secp256k1};
|
||||
use bitcoin::secp256k1::ecdh::SharedSecret;
|
||||
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
|
||||
use bitcoin::secp256k1::Secp256k1;
|
||||
use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
|
||||
|
||||
use std::mem;
|
||||
use std::cmp::{self, Ordering};
|
||||
|
@ -174,7 +174,7 @@ impl chain::Watch<EnforcingSigner> for TestChainMonitor {
|
|||
}
|
||||
|
||||
struct KeyProvider {
|
||||
node_id: u8,
|
||||
node_secret: SecretKey,
|
||||
rand_bytes_id: atomic::AtomicU32,
|
||||
enforcement_states: Mutex<HashMap<[u8;32], Arc<Mutex<EnforcementState>>>>,
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ struct KeyProvider {
|
|||
impl EntropySource for KeyProvider {
|
||||
fn get_secure_random_bytes(&self) -> [u8; 32] {
|
||||
let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed);
|
||||
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];
|
||||
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]];
|
||||
res[30-4..30].copy_from_slice(&id.to_le_bytes());
|
||||
res
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ impl EntropySource for KeyProvider {
|
|||
|
||||
impl NodeSigner for KeyProvider {
|
||||
fn get_node_secret(&self, _recipient: Recipient) -> Result<SecretKey, ()> {
|
||||
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())
|
||||
Ok(self.node_secret.clone())
|
||||
}
|
||||
|
||||
fn get_node_id(&self, recipient: Recipient) -> Result<PublicKey, ()> {
|
||||
|
@ -207,12 +207,18 @@ impl NodeSigner for KeyProvider {
|
|||
}
|
||||
|
||||
fn get_inbound_payment_key_material(&self) -> KeyMaterial {
|
||||
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])
|
||||
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]])
|
||||
}
|
||||
|
||||
fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result<RecoverableSignature, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn sign_gossip_message(&self, msg: lightning::ln::msgs::UnsignedGossipMessage) -> Result<Signature, ()> {
|
||||
let msg_hash = Message::from_slice(&Sha256dHash::hash(&msg.encode()[..])[..]).map_err(|_| ())?;
|
||||
let secp_ctx = Secp256k1::signing_only();
|
||||
Ok(secp_ctx.sign_ecdsa(&msg_hash, &self.node_secret))
|
||||
}
|
||||
}
|
||||
|
||||
impl SignerProvider for KeyProvider {
|
||||
|
@ -229,12 +235,12 @@ impl SignerProvider for KeyProvider {
|
|||
let keys = InMemorySigner::new(
|
||||
&secp_ctx,
|
||||
self.get_node_secret(Recipient::Node).unwrap(),
|
||||
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(),
|
||||
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(),
|
||||
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(),
|
||||
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(),
|
||||
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(),
|
||||
[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],
|
||||
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(),
|
||||
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(),
|
||||
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(),
|
||||
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(),
|
||||
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(),
|
||||
[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]],
|
||||
channel_value_satoshis,
|
||||
channel_keys_id,
|
||||
);
|
||||
|
@ -257,14 +263,14 @@ impl SignerProvider for KeyProvider {
|
|||
|
||||
fn get_destination_script(&self) -> Script {
|
||||
let secp_ctx = Secp256k1::signing_only();
|
||||
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();
|
||||
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();
|
||||
let our_channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize());
|
||||
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()
|
||||
}
|
||||
|
||||
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
|
||||
let secp_ctx = Secp256k1::signing_only();
|
||||
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();
|
||||
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();
|
||||
let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize());
|
||||
ShutdownScript::new_p2wpkh(&pubkey_hash)
|
||||
}
|
||||
|
@ -402,7 +408,8 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
|
|||
macro_rules! make_node {
|
||||
($node_id: expr, $fee_estimator: expr) => { {
|
||||
let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new($node_id.to_string(), out.clone()));
|
||||
let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU32::new(0), enforcement_states: Mutex::new(HashMap::new()) });
|
||||
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();
|
||||
let keys_manager = Arc::new(KeyProvider { node_secret, rand_bytes_id: atomic::AtomicU32::new(0), enforcement_states: Mutex::new(HashMap::new()) });
|
||||
let monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), $fee_estimator.clone(),
|
||||
Arc::new(TestPersister {
|
||||
update_ret: Mutex::new(ChannelMonitorUpdateStatus::Completed)
|
||||
|
|
|
@ -26,6 +26,7 @@ use bitcoin::network::constants::Network;
|
|||
use bitcoin::hashes::Hash as TraitImport;
|
||||
use bitcoin::hashes::HashEngine as TraitImportEngine;
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
|
||||
use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};
|
||||
|
||||
use lightning::chain;
|
||||
|
@ -47,15 +48,14 @@ use lightning::util::errors::APIError;
|
|||
use lightning::util::events::Event;
|
||||
use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
|
||||
use lightning::util::logger::Logger;
|
||||
use lightning::util::ser::ReadableArgs;
|
||||
use lightning::util::ser::{ReadableArgs, Writeable};
|
||||
|
||||
use crate::utils::test_logger;
|
||||
use crate::utils::test_persister::TestPersister;
|
||||
|
||||
use bitcoin::secp256k1::{PublicKey, SecretKey, Scalar};
|
||||
use bitcoin::secp256k1::{Message, PublicKey, SecretKey, Scalar, Secp256k1};
|
||||
use bitcoin::secp256k1::ecdh::SharedSecret;
|
||||
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
|
||||
use bitcoin::secp256k1::Secp256k1;
|
||||
use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
|
||||
|
||||
use std::cell::RefCell;
|
||||
use hashbrown::{HashMap, hash_map};
|
||||
|
@ -317,6 +317,12 @@ impl NodeSigner for KeyProvider {
|
|||
fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result<RecoverableSignature, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn sign_gossip_message(&self, msg: lightning::ln::msgs::UnsignedGossipMessage) -> Result<Signature, ()> {
|
||||
let msg_hash = Message::from_slice(&Sha256dHash::hash(&msg.encode()[..])[..]).map_err(|_| ())?;
|
||||
let secp_ctx = Secp256k1::signing_only();
|
||||
Ok(secp_ctx.sign_ecdsa(&msg_hash, &self.node_secret))
|
||||
}
|
||||
}
|
||||
|
||||
impl SignerProvider for KeyProvider {
|
||||
|
|
|
@ -122,6 +122,10 @@ impl NodeSigner for KeyProvider {
|
|||
fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result<RecoverableSignature, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn sign_gossip_message(&self, _msg: lightning::ln::msgs::UnsignedGossipMessage) -> Result<bitcoin::secp256k1::ecdsa::Signature, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl SignerProvider for KeyProvider {
|
||||
|
|
|
@ -41,7 +41,7 @@ use crate::chain::transaction::OutPoint;
|
|||
use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI;
|
||||
use crate::ln::{chan_utils, PaymentPreimage};
|
||||
use crate::ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction};
|
||||
use crate::ln::msgs::UnsignedChannelAnnouncement;
|
||||
use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage};
|
||||
use crate::ln::script::ShutdownScript;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
@ -494,6 +494,14 @@ pub trait NodeSigner {
|
|||
///
|
||||
/// Errors if the [`Recipient`] variant is not supported by the implementation.
|
||||
fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result<RecoverableSignature, ()>;
|
||||
|
||||
/// Sign a gossip message.
|
||||
///
|
||||
/// Note that if this fails, LDK may panic and the message will not be broadcast to the network
|
||||
/// or a possible channel counterparty. If LDK panics, the error should be resolved to allow the
|
||||
/// message to be broadcast, as otherwise it may prevent one from receiving funds over the
|
||||
/// corresponding channel.
|
||||
fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result<Signature, ()>;
|
||||
}
|
||||
|
||||
/// A trait that can return signer instances for individual channels.
|
||||
|
@ -1290,6 +1298,11 @@ impl NodeSigner for KeysManager {
|
|||
};
|
||||
Ok(self.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), &secret))
|
||||
}
|
||||
|
||||
fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result<Signature, ()> {
|
||||
let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
|
||||
Ok(sign(&self.secp_ctx, &msg_hash, &self.node_secret))
|
||||
}
|
||||
}
|
||||
|
||||
impl SignerProvider for KeysManager {
|
||||
|
@ -1394,6 +1407,10 @@ impl NodeSigner for PhantomKeysManager {
|
|||
let secret = self.get_node_secret(recipient)?;
|
||||
Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), &secret))
|
||||
}
|
||||
|
||||
fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result<Signature, ()> {
|
||||
self.inner.sign_gossip_message(msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl SignerProvider for PhantomKeysManager {
|
||||
|
|
|
@ -632,6 +632,25 @@ impl Readable for NetAddress {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents the set of gossip messages that require a signature from a node's identity key.
|
||||
pub enum UnsignedGossipMessage<'a> {
|
||||
/// An unsigned channel announcement.
|
||||
ChannelAnnouncement(&'a UnsignedChannelAnnouncement),
|
||||
/// An unsigned channel update.
|
||||
ChannelUpdate(&'a UnsignedChannelUpdate),
|
||||
/// An unsigned node announcement.
|
||||
NodeAnnouncement(&'a UnsignedNodeAnnouncement)
|
||||
}
|
||||
|
||||
impl<'a> Writeable for UnsignedGossipMessage<'a> {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
|
||||
match self {
|
||||
UnsignedGossipMessage::ChannelAnnouncement(ref msg) => msg.write(writer),
|
||||
UnsignedGossipMessage::ChannelUpdate(ref msg) => msg.write(writer),
|
||||
UnsignedGossipMessage::NodeAnnouncement(ref msg) => msg.write(writer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The unsigned part of a [`node_announcement`] message.
|
||||
///
|
||||
|
|
|
@ -659,6 +659,10 @@ impl NodeSigner for TestKeysInterface {
|
|||
fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result<RecoverableSignature, ()> {
|
||||
self.backing.sign_invoice(hrp_bytes, invoice_data, recipient)
|
||||
}
|
||||
|
||||
fn sign_gossip_message(&self, msg: msgs::UnsignedGossipMessage) -> Result<Signature, ()> {
|
||||
self.backing.sign_gossip_message(msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl SignerProvider for TestKeysInterface {
|
||||
|
|
Loading…
Add table
Reference in a new issue