Avoid parsing PublicKeys when applying an unsigned chan update

`PublicKey` parsing is relatively expensive as we have to check if
the point is actually on the curve. To avoid it, our `NetworkGraph`
uses `NodeId`s which don't have the validity requirement.

Sadly, we were always parsing the broadcasting node's `PublicKey`
from the `node_id` in the network graph whenever we see an update
for that channel, whether we have a corresponding signature or not.

Here we fix this, only parsing the public key (and hashing the
message) if we're going to check a signature.
This commit is contained in:
Matt Corallo 2025-01-31 17:33:26 +00:00
parent 1434e9c1e2
commit eb5198ac34
2 changed files with 23 additions and 8 deletions

View file

@ -2379,8 +2379,8 @@ mod tests {
42,
53,
features,
$nodes[0].node.get_our_node_id(),
$nodes[1].node.get_our_node_id(),
$nodes[0].node.get_our_node_id().into(),
$nodes[1].node.get_our_node_id().into(),
)
.expect("Failed to update channel from partial announcement");
let original_graph_description = $nodes[0].network_graph.to_string();

View file

@ -2537,7 +2537,7 @@ where
}
};
let node_pubkey;
let mut node_pubkey = None;
{
let channels = self.channels.read().unwrap();
match channels.get(&msg.short_channel_id) {
@ -2556,16 +2556,31 @@ where
} else {
channel.node_one.as_slice()
};
node_pubkey = PublicKey::from_slice(node_id).map_err(|_| LightningError {
err: "Couldn't parse source node pubkey".to_owned(),
action: ErrorAction::IgnoreAndLog(Level::Debug),
})?;
if sig.is_some() {
// PublicKey parsing isn't entirely trivial as it requires that we check
// that the provided point is on the curve. Thus, if we don't have a
// signature to verify, we want to skip the parsing step entirely.
// This represents a substantial speedup in applying RGS snapshots.
node_pubkey =
Some(PublicKey::from_slice(node_id).map_err(|_| LightningError {
err: "Couldn't parse source node pubkey".to_owned(),
action: ErrorAction::IgnoreAndLog(Level::Debug),
})?);
}
},
}
}
let msg_hash = hash_to_message!(&message_sha256d_hash(&msg)[..]);
if let Some(sig) = sig {
let msg_hash = hash_to_message!(&message_sha256d_hash(&msg)[..]);
let node_pubkey = if let Some(pubkey) = node_pubkey {
pubkey
} else {
debug_assert!(false, "node_pubkey should have been decoded above");
let err = "node_pubkey wasn't decoded but we need it to check a sig".to_owned();
let action = ErrorAction::IgnoreAndLog(Level::Error);
return Err(LightningError { err, action });
};
secp_verify_sig!(self.secp_ctx, &msg_hash, &sig, &node_pubkey, "channel_update");
}