Signet is an open-source, decentralised identity verification protocol for Nostr. It lets users prove claims about who they are — human, professional, adult, organisation — without exposing personal data. Verification is anchored to professional bodies (law societies, medical boards, notary commissions) rather than any central authority. Trust accumulates as a continuous Signet Score score (0–200, where 100 represents the current government standard) assembled from weighted signals, and is expressed as a tier badge any Nostr client can display.
Person
|
| signs a kind 31000 self-declaration (`type: credential`)
v
Tier 1 — Self-declared
|
| three or more peers sign kind 31000 vouches (`type: vouch`)
v
Tier 2 — Web-of-trust
|
| licensed professional issues kind 31000 credential (`type: credential`)
| with zero-knowledge age proof and document nullifier
v
Tier 3 — Professionally verified (adult)
|
| same ceremony, scope extended to child supervision
v
Tier 4 — Professionally verified (adult + child)
|
v
Trust signals accumulated (professional verif, vouches, account age, identity bridges)
|
v
Signet Score computed (0-200, where 100 = government standard)
|
v
Badge displayed by client e.g. "Verified (Tier 3) — Signet Score 106"
| Tier | Name | Who issues | What it proves | Score contribution |
|---|---|---|---|---|
| 1 | Self-declared | Subject themselves | "I exist and I own this key" | — |
| 2 | Web-of-trust | Peers (kind 31000, type: vouch) |
Enough known people can vouch for this identity | +2–8 per vouch |
| 3 | Professionally verified | Licensed professional (kind 31000, type: credential) |
Government document seen; adult age confirmed | +40 |
| 4 | Professional + child safety | Licensed professional (kind 31000, type: credential) |
Tier 3 plus authorisation to interact with minors | +40 |
Tier 2 requires at least 3 vouches from Tier 2+ peers (configurable per community via kind 30078 (NIP-78) policy). Tiers 3 and 4 are issued in a two-credential ceremony: one Natural Person credential (carries document nullifier and Merkle root) and one anonymous Persona credential (carries age range only, no identifying data).
Read kind 31000 (type: credential and type: vouch) from relays, call computeBadge, show a label.
No cryptography required beyond Schnorr signature verification (optional).
Add kind 31000 (type: vouch) vouch issuance. Requires Schnorr signing, relay write access, and basic
kind 30078 (NIP-78) policy parsing so your client respects community verification thresholds.
Issue professional credentials, manage verifier lifecycle (kind 31000 types: verifier, challenge, revocation), build
guardian delegation (kind 31000, type: delegation), support credential chains (supersedes / superseded-by),
and integrate the voting extension (kinds 30482–30484).
Subject Verifier
| |
|--- presents document -->|
| |
| Verifier computes nullifier:
| SHA-256(docType || country || docNumber || salt)
| (prevents duplicate identity; document never stored)
| |
| Verifier builds Merkle tree:
| leaves = verified attributes (name, DOB, address, ...)
| only root is published on-chain
| |
| Verifier creates zero-knowledge age range proof
| (proves "subject is 18+" without revealing birth date)
| |
| Two credentials signed and published:
| kind 31000 Natural Person (nullifier + Merkle root, type: credential)
| kind 31000 Persona (age range only, anonymous, type: credential)
| |
v v
Both events published to Nostr relays
Professional verifiers are themselves credentialed (kind 31000, type: verifier) and require cross-verification
by two other licensed professionals before becoming active. A challenge / revocation mechanism
(kind 31000 types: challenge and revocation) allows the community to remove a fraudulent verifier.
| Kind | Type tag | Purpose |
|---|---|---|
| 31000 | credential |
Verification credential for any tier |
| 31000 | vouch |
Peer attestation (Tier 2 building block) |
| 30078 | — | Policy: community verification requirements (NIP-78) |
| 31000 | verifier |
Professional verifier credential |
| 31000 | challenge |
Report a suspected fraudulent verifier |
| 31000 | revocation |
Remove a verifier after threshold confirmations |
| 31000 | identity-bridge |
Link two keypairs via ring signature |
| 31000 | delegation |
Guardian / agent delegation with scoped permission |
| 30482 | — | Voting extension: define an election |
| 30483 | — | Voting extension: cast an anonymous ballot |
| 30484 | — | Voting extension: publish tallied result |
Install the library:
npm install signet-protocol
Fetch events from a relay, then call computeBadge:
import { computeBadge, buildBadgeFilters, meetsMinimumTier } from 'signet-protocol';
import type { NostrEvent } from 'signet-protocol';
// 1. Build relay filters for one or more pubkeys
const pubkeys = ['<hex-pubkey>'];
const filters = buildBadgeFilters(pubkeys);
// filters = [{ kinds: [31000], '#d': ['<hex-pubkey>'] }]
// 2. Fetch events from your relay (using whatever WebSocket client you prefer)
const events: NostrEvent[] = await fetchFromRelay(filters);
// 3. Compute the badge
const badge = computeBadge(pubkeys[0], events, { verifySignatures: true });
// badge.displayLabel => "Verified (Tier 3)"
// badge.score => 106
// badge.tier => 3
// badge.vouchCount => 5
// 4. Gate a feature on minimum tier
if (meetsMinimumTier(badge, 2)) {
// allow posting in a verified-only community
}computeBadge accepts any mix of kind 31000 (type: credential and type: vouch) events. It handles expiry, deduplication
(one vouch counted per voucher pubkey), and optional Schnorr signature verification. The result is
a plain object — no rendering assumptions are made.
The buildBadgeFilters helper returns a standard Nostr REQ filter array ready for use with any
relay client library.
- Full protocol specification:
spec/protocol.md - Voting extension:
spec/voting.md - Level 1 badge library:
src/badge.ts - Signet Score details:
src/trust-score.ts - Full working example:
examples/full-flow.ts - Jurisdiction-specific examples:
examples/jurisdictions/ - "Signet me" peer verification:
examples/signet-me.ts