Private reputation queries for Urbit using Diffie-Hellman Private Set Intersection.
You can query any other ship running %repu to get a reputation score. The score is computed from your mutual peers — ships that appear in both your peer lists — weighted by the private votes each of you has assigned. Neither party reveals their full peer list or individual votes.
Peers are sourced from two places (either or both may be absent):
- %pals — mutual (bidirectional) friendships
- %contacts — deliberately added contact book entries (not the full interaction history)
Comets and moons are filtered out; only galaxies, stars, and planets participate.
Each user privately assigns votes to their peers: positive (+1), neutral (+1), or negative (-2). These votes are never transmitted. When two ships complete a reputation query, the score is computed by summing the vote values across their mutual peers. Both parties learn:
- The number of mutual peers
- The counterparty's aggregate score (how your mutual peers rate them)
- Your own aggregate score (how their mutual peers rate you)
Nobody learns which specific peers are mutual, only the count and scores.
The cryptographic core is a 3-round Diffie-Hellman Private Set Intersection protocol over the RFC 3526 2048-bit MODP safe prime (IKE Group 14).
Each Urbit ship @p is an integer. To avoid trivial fixed points (0^a = 0, 1^a = 1), each ship is mapped to (ship + 2) before exponentiation.
Round 1 — Init. Alice generates a random 256-bit secret a, computes {(s+2)^a mod p} for each of her peers s, and sends the blinded set to Bob.
Round 2 — Reply. Bob generates his own secret b, computes his blinded set {(s+2)^b mod p}, and doubly-blinds Alice's set by raising each element to b: {((s+2)^a)^b mod p}. He sends both to Alice and stores session state.
Round 3 — Final. Alice doubly-blinds Bob's set by raising each element to a: {((s+2)^b)^a mod p}. Because (s+2)^(a*b) = (s+2)^(b*a), the doubly-blinded representations of the same ship are identical regardless of blinding order. Alice finds the intersection by comparing her doubly-blinded set against Bob's, computes the score, and sends Bob's doubly-blinded set back along with her score and mutual count. Bob performs the same intersection and score computation on his side.
The security rests on the Decisional Diffie-Hellman assumption over the 2048-bit prime group. An observer (or either party) cannot determine which elements are in the other's set without solving the discrete logarithm problem. The secret exponents are ephemeral (generated from eny entropy per session) and never reused.
app/repu.hoon Gall agent: PSI protocol, HTTP API, state management
sur/repu.hoon Types: vote, wire-msg, action, rep-result, psi-session
mar/repu-wire.hoon Inter-ship message mark
mar/repu-action.hoon Local action mark
site/index.html Frontend
site/repu.js API client, rendering
site/style.css Dark theme
All endpoints are served by the agent via Eyre at /apps/repu/.
| Method | Path | Description |
|---|---|---|
| GET | /api/pals |
Combined peer list (pals + contacts) |
| GET | /api/votes |
Your private votes |
| GET | /api/results |
Past query results |
| POST | /api/action |
{"set-vote": {"ship": "~zod", "vote": "pos"}} |
| POST | /api/action |
{"query": {"ship": "~zod"}} |
Both ships must have %repu installed. Copy the desk contents into a new desk, |commit %repu, then |install our %repu.