gossmap: reduce load times by 20%
What changed, and why it matters
This commit speeds up how Core Lightning loads its network map by replacing a strong hash function with a cheaper, simpler one. The change is framed as a performance optimization. The new hash for node IDs is weaker and uses a random byte offset, which could in theory allow a specially crafted node ID to collide with another in the hash table. However, the commit message argues that creating such collisions is expensive because it requires opening real Lightning channels. There is no direct evidence in the commit or supplied references that this is exploitable as a security bug.
Treat as a performance optimization rather than a vulnerability unless independent analysis demonstrates a practical collision attack against the new hash in the gossip map context. If concerned, review whether the weaker node_id hash could enable denial-of-service via hash collisions in pathfinding or gossip processing, and consider reintroducing a keyed hash if the threat model changes.
Security signals we found
Hash function deliberately weakened for performance
Commit message acknowledges collision resistance trade-off
Hash output derived from a small, contiguous slice of a public key at a random offset
No bounds issue: BUILD_ASSERT ensures offset + size fits within id.k
No explicit security claim or CVE reference in commit
Evidence from the diff
The patch modifies common/gossmap.c to replace siphash24-based hashing for short_channel_id and node_id with simpler hash functions. For short_channel_id, it switches to an existing short_channel_id_hash. For node_id, it introduces a hash that copies sizeof(size_t) bytes from a random offset within the 33-byte pubkey, using siphash_seed only to pick the offset. The commit message explicitly notes that collision resistance is relaxed intentionally, justifying it by the economic cost of creating channels. The change reduces gossip_store load time by roughly 20%.
Changed components
common/gossmap.cgossmap hash table for node_idgossmap hash table for short_channel_idInspect captured patch +9 / −6
diff --git a/common/gossmap.c b/common/gossmap.c
index 9d52569d..744890bb 100644
--- a/common/gossmap.c
+++ b/common/gossmap.c
@@ -29,11 +29,7 @@ static bool chanidx_eq_id(const ptrint_t *pidx,
struct short_channel_id pidxid = chanidx_id(pidx);
return short_channel_id_eq(pidxid, scid);
}
-static size_t scid_hash(const struct short_channel_id scid)
-{
- return siphash24(siphash_seed(), &scid, sizeof(scid));
-}
-HTABLE_DEFINE_NODUPS_TYPE(ptrint_t, chanidx_id, scid_hash, chanidx_eq_id,
+HTABLE_DEFINE_NODUPS_TYPE(ptrint_t, chanidx_id, short_channel_id_hash, chanidx_eq_id,
chanidx_htable);
static struct node_id nodeidx_id(const ptrint_t *pidx);
@@ -42,9 +38,16 @@ static bool nodeidx_eq_id(const ptrint_t *pidx, const struct node_id id)
struct node_id pidxid = nodeidx_id(pidx);
return node_id_eq(&pidxid, &id);
}
+/* You need to spend sats to create a channel to advertize your nodeid,
+ * so creating clashes is not free: we can be lazy! */
static size_t nodeid_hash(const struct node_id id)
{
- return siphash24(siphash_seed(), &id, PUBKEY_CMPR_LEN);
+ size_t val;
+ size_t off = siphash_seed()->u.u8[0] % 16;
+
+ BUILD_ASSERT(15 + sizeof(val) < sizeof(id.k));
+ memcpy(&val, id.k + off, sizeof(val));
+ return val;
}
HTABLE_DEFINE_NODUPS_TYPE(ptrint_t, nodeidx_id, nodeid_hash, nodeidx_eq_id,
nodeidx_htable);
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.