pull down to refresh

Most of y'all reading ~nostr already know vouches exist. NIP-style kind:33335 events where one key says "I stand behind this other key." Social-graph weight, trust-at-a-distance, web-of-trust primitives. All good.

Here's the thing nobody talks about: any vouch mechanism without cycle detection is a mutual-vouch laundromat. Two fresh keys vouch for each other. Three, four, five keys in a ring vouch in a circle. From the outside, each one looks like they have external vouches. Their "social depth" score climbs without either side doing real work. That's sockpuppet amplification, and it's cheap.

Direct 2-cycles are the easy case. If Alice vouches Bob and Bob vouches Alice, drop the edge. Done. We shipped that in @powforge/identity v0.5.2.

The hard case is indirect cycles. A -> B -> C -> A. Three keys in a triangle. Each one can honestly point at the other two and say "I have 2 external vouches." The cycle only shows up when you walk the graph.

This is what v0.6.0 fixes. We added bounded-depth DFS on the vouch subgraph:

const { detectIndirectCycle } = require('@powforge/identity');

// Does this inbound vouch close a cycle back to the subject?
const inCycle = detectIndirectCycle(events, subjectPubkey, voucherPubkey, 4);
if (inCycle) {
  // Drop the vouch from the social-depth score.
  // Report it under cycleDropped for transparency.
}

The 4 is max depth. We tested the detector against 10 synthetic cases (direct, indirect-3, indirect-4, depth-5 cutoff, diamond-with-no-cycle, self-vouch, multiple inbound one-cycling, etc.). All pass. MIT licensed, on npm as @powforge/identity v0.6.0, source on GitLab at powforge/sats-challenge.

Important honest caveat: mainnet Nostr doesn't have enough organic kind:33335 traffic to validate against real data yet. We ran the detector against a 4-relay query for the PowForge subject key. The neighborhood came back empty. Nobody's voucher-ing yet. The detector is correct per the test matrix; it's ahead of the adoption curve.

Why ~nostr specifically: this is a Nostr-protocol problem, not a Bitcoin-protocol problem. Any Nostr client wanting to surface a "social depth" score has to deal with this. The oracle service at identity.powforge.dev/oracle/info returns per-dimension scores with cycle-dropped counts called out, so downstream clients can verify our work or just take the signature.

Two questions for the room:

  1. Does your client compute its own depth score from follows/vouches today? If yes, are you doing cycle detection?
  2. What's the honest right max-depth for this walk? We picked 4 because the bundled-test graphs never needed more, but that's an empirical choice, not a proof.

Demo and source:

  • Live: powforge.dev/explorer (paste any npub, see the per-dimension breakdown)
  • SDK: npm install @powforge/identity
  • Source: gitlab.com/powforge/sats-challenge
  • Oracle: curl https://identity.powforge.dev/oracle/info

Happy to critique vouch-graph code for anybody running one. Nostr needs more of this kind of plumbing and less of the "just trust verified.org" kind.

Zeke