signet-protocol 1.11.1 → 1.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2628 @@
1
+ # The Signet Protocol
2
+
3
+ **Decentralised Identity Verification for Nostr**
4
+
5
+ **Version:** 0.1.0 (Draft)
6
+ **Date:** 2026-03-02
7
+ **Status:** Draft specification — seeking community feedback
8
+ **Licence:** MIT
9
+
10
+ ---
11
+
12
+ ## Abstract
13
+
14
+ Signet is an open protocol for decentralised identity verification on Nostr. It enables users to prove claims about their identity — age, parenthood, professional status — using zero-knowledge proofs, without revealing personal data or relying on a central authority.
15
+
16
+ The protocol defines four verification tiers, nine entity types, a continuous Signet Score, a verifier accountability framework, and uses a single generic Verifiable Attestation kind (31000, NIP-VA Verifiable Attestations) for all identity attestations, plus NIP-78 (kind 30078) for policies. A separate voting extension uses kinds 30482-30484. Every professionally verified person receives two credentials — a Natural Person (real identity with Merkle-bound attributes and document nullifier) and a Persona (anonymous alias with age-range proof only). This two-credential model makes privacy a first-class design goal.
17
+
18
+ Any Nostr client can implement Signet. Any community can set verification policies. Any licensed professional can become a verifier.
19
+
20
+ **Child safety is the killer app. Social proof (blue checkmarks) drives adoption across all of Nostr.**
21
+
22
+ ---
23
+
24
+ ## Table of Contents
25
+
26
+ 1. [Motivation](#1-motivation)
27
+ 2. [Design Principles](#2-design-principles)
28
+ 3. [Credential Tiers](#3-credential-tiers)
29
+ 4. [Signet IQ](#4-signet-iq)
30
+ 5. [Service Policies](#5-service-policies)
31
+ 6. [Verifier Network](#6-verifier-network)
32
+ 7. [Anti-Corruption Framework](#7-anti-corruption-framework)
33
+ 8. [Event Kinds](#8-event-kinds)
34
+ 9. [Cryptographic Stack](#9-cryptographic-stack)
35
+ 10. [Social Proof — The Blue Checkmark](#10-social-proof--the-blue-checkmark)
36
+ 11. [Alignment with Existing Standards](#11-alignment-with-existing-standards)
37
+ 12. [Regulatory Compatibility](#12-regulatory-compatibility)
38
+ 13. [Limitations](#13-limitations)
39
+ 14. [Reference Implementation](#14-reference-implementation)
40
+ 15. [Identity Management & Peer Verification](#15-identity-management--peer-verification)
41
+ 16. [Identity Bridge](#16-identity-bridge)
42
+ 17. [Entity Type Classification](#17-entity-type-classification)
43
+ 18. [Adversarial Resilience](#18-adversarial-resilience)
44
+ 19. [Civic Identity](#19-civic-identity)
45
+ 20. [Two-Credential Verification](#20-two-credential-verification)
46
+ 21. [Credential Lifecycle](#21-credential-lifecycle)
47
+ 22. [Child Online Safety](#22-child-online-safety)
48
+ 23. [Inclusivity](#23-inclusivity)
49
+ 24. [Jurisdiction Confidence](#24-jurisdiction-confidence)
50
+ 25. [Implementation Levels](#25-implementation-levels)
51
+
52
+ ---
53
+
54
+ ## 1. Motivation
55
+
56
+ ### The Identity Gap on Nostr
57
+
58
+ Nostr has no identity verification. Anyone can claim to be anyone. There is no blue checkmark, no web-of-trust scoring, no way to prove "I met this person" or "a professional verified this person's identity." The result: spam, impersonation, and zero basis for trust beyond "I recognise this pubkey."
59
+
60
+ ### For Children
61
+
62
+ Every kids' social platform that failed (Club Penguin, Messenger Kids, Wizz, Yubo) collapsed because safety was policy-based, not cryptographic. Adults could create child accounts to impersonate children. Age verification was self-declaration or nonexistent. No platform could prove:
63
+
64
+ - This parent is a real person
65
+ - This child is a real child
66
+ - This parent actually has this child
67
+
68
+ ### For Everyone
69
+
70
+ Nostr needs a trust layer that:
71
+
72
+ - Proves claims without revealing personal data
73
+ - Works without a central authority
74
+ - Starts with nothing (any account can get verified retroactively)
75
+ - Scales from casual peer vouching to professional identity verification
76
+ - Lets communities set their own policies
77
+
78
+ ### The Regulatory Landscape
79
+
80
+ The world is moving to mandatory age verification:
81
+
82
+ - **EU eIDAS 2.0** (December 2026): Every Member State must offer a digital identity wallet with selective disclosure
83
+ - **France SREN law** (April 2025): Adult sites must implement ZKP-based age verification
84
+ - **UK Online Safety Act** (2023): Platforms liable for children's exposure; Ofcom requires "highly effective age assurance"
85
+ - **US COPPA 2.0** (pending): Extends protections to under-17
86
+ - **US FTC COPPA flexibility** (March 2026): FTC will not enforce against data collected solely for age verification — but requires robust deletion and clear notice. Signet exceeds this: no personal data is collected at all.
87
+ - **Australia under-16 ban** (2024): $50M AUD fines on platforms
88
+ - **ISO/IEC 27566-1:2025**: New global age assurance standard
89
+
90
+ Nobody has built this for the decentralised world. Signet fills that gap.
91
+
92
+ ---
93
+
94
+ ## 2. Design Principles
95
+
96
+ 1. **The credential states facts, the service sets policy.** Credentials say "here's what was verified and how." Communities decide "here's what we require." Separation of attestation and enforcement.
97
+
98
+ 2. **Privacy by default.** ZKP means proving a claim without revealing the underlying data. "This parent has a child aged 8-12" without revealing which parent, which child, or the exact age.
99
+
100
+ 3. **No central authority.** Professional bodies (Law Society, Medical Board, notary commissions) are the trust anchors. No single entity approves verifiers. No DAO. No token.
101
+
102
+ 4. **Progressive — more than nothing is better than nothing.** Users who refuse to show documents can still accumulate peer vouches. Less trust weight, but more than zero, which is what everyone has today.
103
+
104
+ 5. **Retroactive.** Verification attaches to existing accounts. Any active Nostr identity — adult or child — can get verified at any time. Not tied to account creation.
105
+
106
+ 6. **Composable.** Discrete tiers for policy gates + continuous score for reputation. Simple for end users, nuanced for power users.
107
+
108
+ 7. **Nostr-native.** Built on secp256k1. Uses existing Nostr event infrastructure. Zero new dependencies for basic functionality.
109
+
110
+ ---
111
+
112
+ ## 3. Credential Tiers
113
+
114
+ Four tiers of verification, each declaring what was proven and by whom.
115
+
116
+ ### Tier 1 — Self-Declared
117
+
118
+ | Aspect | Detail |
119
+ |--------|--------|
120
+ | **What's proven** | Nothing — a signed claim: "I say I'm X" |
121
+ | **Issuer** | Self |
122
+ | **ZKP hides** | N/A |
123
+ | **Use case** | Baseline. What every Nostr account has today. |
124
+ | **Trust weight** | Minimal |
125
+
126
+ ### Tier 2 — Web-of-Trust Vouched
127
+
128
+ | Aspect | Detail |
129
+ |--------|--------|
130
+ | **What's proven** | N verified people (Tier 2+) attest: "I know this person/family" |
131
+ | **Issuer** | Peers |
132
+ | **ZKP hides** | Who vouched (proves count and minimum tier of vouchers without revealing identities) |
133
+ | **Use case** | Local communities, meetup groups, conferences. People who know each other. |
134
+ | **Trust weight** | Moderate. In-person vouches carry more weight than online vouches. |
135
+ | **Threshold** | Configurable per community. Default: 3 vouches from Tier 2+ accounts. |
136
+
137
+ ### Tier 3 — Professional Verified (Adult)
138
+
139
+ | Aspect | Detail |
140
+ |--------|--------|
141
+ | **What's proven** | A licensed professional verified this adult's government-issued ID in person |
142
+ | **Issuer** | Professional (lawyer, doctor, notary) |
143
+ | **ZKP hides** | Which professional, the adult's real name, ID number, address — everything except "a professional verified this person" |
144
+ | **Use case** | High-trust communities. Adults who want strong verification without publishing their identity. |
145
+ | **Trust weight** | High |
146
+
147
+ ### Tier 4 — Professional Verified (Adult + Child)
148
+
149
+ | Aspect | Detail |
150
+ |--------|--------|
151
+ | **What's proven** | A licensed professional verified the adult's ID AND confirmed a child exists in a specific age range |
152
+ | **Issuer** | Professional |
153
+ | **ZKP hides** | Everything in Tier 3 + child's identity, exact age, which documents were shown |
154
+ | **Evidence the professional sees** | Parent's ID (passport, driving licence) + child evidence (birth certificate, passport, school record) |
155
+ | **Use case** | Maximum safety spaces. Proves the child is real and the parent is real. |
156
+ | **Trust weight** | Maximum |
157
+
158
+ ### Why Tier 4 Stops Predators
159
+
160
+ A predator who is a verified real adult (Tier 3) could still create a fake child account. Tier 4 prevents this because:
161
+
162
+ - A professional independently confirms the child exists
163
+ - The professional sees evidence of the child (birth cert, passport)
164
+ - The professional's licence is on the line — fraudulent attestation = professional misconduct
165
+ - The ZKP cryptographically binds the parent's identity to the child's verified age range
166
+ - An adult pretending to have a child cannot produce a child's birth certificate to a lawyer
167
+
168
+ ---
169
+
170
+ ## 4. Signet IQ (Identification Quotient)
171
+
172
+ On top of discrete tiers, a continuous Signet IQ (0-200) measures identity quality — the statistical confidence that an identity is real, not fabricated. It is not a reputation score. A high IQ means independent, verifiable sources confirm this entity exists. What the entity does with that identity is a separate concern.
173
+
174
+ A score of 100 represents the confidence level equivalent to a human checking a passport face-to-face — the standard that governments deem acceptable. Scores above 100 indicate that the identity is harder to fabricate than a government-issued passport, because more independent sources confirm it.
175
+
176
+ ### Score Components
177
+
178
+ | Signal | Weight | Notes |
179
+ |--------|--------|-------|
180
+ | Professional verification (Tier 3/4) | Heavy | Single event, large impact |
181
+ | Identity bridge (kind 31000, `type: identity-bridge`) | Medium | Ring-sig proof linking anon account to verified identity, scaled by ring min tier |
182
+ | In-person peer signature | Strong | Met in person, signed keys face-to-face |
183
+ | Online vouch from verified user | Light | Accumulates — many light vouches add up |
184
+ | Account age | Passive | Time on the network adds weight gradually |
185
+ | Voucher's own Signet Score | Multiplier | A vouch from someone at IQ 150 carries more than from someone at IQ 40 |
186
+
187
+ ### RECOMMENDED Weights
188
+
189
+ | Signal | RECOMMENDED weight | Per-type cap (MUST) | Max contribution |
190
+ |--------|-------------------|---------------------|-----------------|
191
+ | Professional verification | 80 | 1 event | 80 |
192
+ | Identity bridge | 50 × (ringMinTier / 4) | 1 bridge | 50 |
193
+ | In-person vouch (Tier 2+) | 16 × (voucher\_score / 200) | 3 vouches | 48 |
194
+ | Online vouch (Tier 2+) | 4 × (voucher\_score / 200) | 5 vouches | 20 |
195
+ | Account age | 10 / year | 2 years (20 pts) | 20 |
196
+
197
+ Clients MAY adjust individual weight values but MUST enforce per-type caps. Without caps, vouch farming trivially inflates scores: 10 in-person vouches from high-score accounts would yield 160+ points, exceeding a professional verification.
198
+
199
+ The `voucher-score` tag is a snapshot of the voucher's Signet IQ at publication time. Vouchers MAY republish their vouch to update their embedded score. Clients MUST use the score from the most recent version of the vouch event.
200
+
201
+ ### Score Algorithm
202
+
203
+ The exact algorithm is implementation-defined (clients can weight signals differently), but the protocol specifies the **signal types, their relative ordering, and per-type caps**:
204
+
205
+ ```
206
+ professional verification > identity bridge > in-person vouch > online vouch > account age
207
+ ```
208
+
209
+ Clients MUST respect this ordering. A single professional verification always outweighs any number of online vouches. Clients MUST enforce per-type caps as specified in the weights table above. These two constraints together prevent gaming through vouch farms.
210
+
211
+ ### Display
212
+
213
+ ```
214
+ ┌───────────────────────────────────┐
215
+ │ Alice ✓✓ Tier 3 │
216
+ │ Signet IQ: 106 │
217
+ │ │
218
+ │ ● Prof verified (lawyer) │
219
+ │ ● 4 in-person vouches │
220
+ │ ● 12 online vouches │
221
+ │ ● Account age: 2 years │
222
+ └───────────────────────────────────┘
223
+ ```
224
+
225
+ - **Tier** = the gate (can you enter this space?)
226
+ - **Signet IQ** = the identity quality (how confident are we that this identity is real?)
227
+ - End users see a simple tier badge. Power users can drill into the score breakdown.
228
+
229
+ ---
230
+
231
+ ## 5. Service Policies
232
+
233
+ Each community, circle, relay, or client sets a minimum verification requirement.
234
+
235
+ ### Policy Matrix
236
+
237
+ | Community Type | Adult Minimum | Child Minimum | Example |
238
+ |----------------|---------------|---------------|---------|
239
+ | Open | Tier 1 | Tier 1 | Public Nostr feed |
240
+ | Casual group | Tier 2 | Tier 2 | Local meetup group |
241
+ | Curated circle | Tier 3 | Tier 3 | Trusted community |
242
+ | Max safety | Tier 3 | Tier 4 | Children's learning space |
243
+
244
+ ### Policy Options
245
+
246
+ Services can also set:
247
+
248
+ - **Minimum Signet Score**: "Tier 2 AND iq > 100"
249
+ - **Per-role requirements**: "moderators need Tier 3, members need Tier 2"
250
+ - **Child-specific overrides**: "adults can be Tier 2, child accounts must be Tier 4"
251
+
252
+ ### Policy Enforcement
253
+
254
+ Policy is enforced at the **client level** and optionally at the **relay level**:
255
+
256
+ - **Client-side**: Clients check Signet credentials before displaying content or allowing interaction.
257
+ - **Relay-side** (optional): AUTH-gated relays can require minimum verification tier before accepting events. This prevents unverified accounts from even publishing to protected spaces.
258
+
259
+ ---
260
+
261
+ ## 6. Verifier Network
262
+
263
+ ### Open With Credentials — No Central Authority
264
+
265
+ Anyone can become a verifier if they meet the criteria. No single entity approves verifiers. No DAO. No token.
266
+
267
+ ### Professional Verifiers (Issue Tier 3/4)
268
+
269
+ **Becoming a professional verifier:**
270
+
271
+ 1. Publish a verifier attestation (kind 31000 with `type: verifier`) containing your professional licence information (bar number, medical licence number, notary commission ID)
272
+ 2. Get cross-verified by other professional verifiers (prevents fraudulent licence claims)
273
+ 3. You can now issue Tier 3 and Tier 4 attestations
274
+ 4. Your professional body is your accountability — fraudulent attestations = professional misconduct, loss of licence, potential criminal liability
275
+
276
+ **Professional bodies as trust anchors:**
277
+
278
+ The system doesn't create a new trust hierarchy. It uses the ones that already exist: the Law Society, medical licensing boards, notary commissions. These bodies already:
279
+
280
+ - Verify practitioners' identities
281
+ - Hold them to ethical standards
282
+ - Have disciplinary procedures
283
+ - Can revoke licences
284
+
285
+ Signet gives these existing trust relationships a cryptographic expression.
286
+
287
+ **Cross-verification prevents gaming:**
288
+
289
+ A fake lawyer can't just publish a credential claiming to be a lawyer. Other verified lawyers in the network must vouch for the credential. This creates a self-policing professional network — the same professionals who risk their licences have every incentive to call out fakes.
290
+
291
+ ### Peer Verifiers (Contribute to Tier 2 and Score)
292
+
293
+ **Becoming a peer verifier:**
294
+
295
+ 1. Reach Tier 2+ yourself
296
+ 2. You can vouch for others you know
297
+ 3. In-person vouches (key signing at meetups, conferences) carry more weight than online vouches
298
+ 4. Your vouches' weight scales with your own Signet Score
299
+
300
+ **The already-doxed advantage:**
301
+
302
+ People who are already public figures (conference speakers, known community members) can vouch freely for people they meet in person. Their public identity IS their credential. When they sign someone's key at a meetup, that signature carries real weight because the voucher is already publicly accountable.
303
+
304
+ ### Verification Flow
305
+
306
+ ```
307
+ Professional Verification (Tier 3/4):
308
+
309
+ User ──── meets in person ────► Lawyer/Doctor/Notary
310
+ │
311
+ sees passport
312
+ (+ child evidence for Tier 4)
313
+ │
314
+ issues Signet credential
315
+ │
316
+ publishes to Nostr relay
317
+ │
318
+ User's account ◄──── credential attached ────┘
319
+
320
+
321
+ Peer Verification (Tier 2 / score):
322
+
323
+ User A ──── meets User B in person ────► key signing
324
+ │
325
+ mutual vouch events
326
+ published to relay
327
+ │
328
+ Both users' scores increase ◄───────────────┘
329
+
330
+
331
+ Online Vouching (score only):
332
+
333
+ Verified User ──── "I vouch for this person" ────► vouch event
334
+ │
335
+ Target user's score increases ◄───────────────────────┘
336
+ (weight depends on voucher's own score)
337
+ ```
338
+
339
+ ---
340
+
341
+ ## 7. Anti-Corruption Framework
342
+
343
+ A registered professional can still be corrupt — doctors sell black market prescriptions, lawyers take bribes. No single measure prevents this. The defence is layered: make corruption expensive, detectable, and permanently traceable.
344
+
345
+ ### Layer 1 — Public Registry Verification
346
+
347
+ Every verifier attestation (kind 31000 with `type: verifier`) includes a licence number and jurisdiction. Any client can link directly to the relevant public register for users to verify:
348
+
349
+ | Jurisdiction | Register | URL |
350
+ |-------------|----------|-----|
351
+ | UK solicitors | SRA | sra.org.uk/consumers/register |
352
+ | UK doctors | GMC | gmc-uk.org/registration-and-licensing |
353
+ | US lawyers | State bar (per state) | Varies by state |
354
+ | Notaries | State/county register | Varies by jurisdiction |
355
+
356
+ A fake professional is caught immediately — anyone can look up whether the licence number corresponds to a real, active practitioner. Clients can automate this check where registers expose APIs.
357
+
358
+ ### Layer 2 — Cross-Professional Verification
359
+
360
+ A new verifier needs vouches from verified professionals in **other** fields. A corrupt doctor needs corrupt friends who are lawyers, notaries, or accountants. Cross-profession collusion rings are exponentially harder to build than single-profession ones.
361
+
362
+ Minimum requirement for verifier activation:
363
+
364
+ - At least 2 vouches from verified professionals
365
+ - At least 2 different professions represented
366
+ - Vouchers must themselves be active, non-revoked verifiers
367
+
368
+ ### Layer 3 — Rate Limiting / Anomaly Detection
369
+
370
+ All credentials are public Nostr events. Issuance volume is visible to the entire network.
371
+
372
+ Clients perform statistical anomaly detection:
373
+
374
+ - **Volume flags:** A doctor issuing 200 verifications/week vs. the network average of 5/week is automatically flagged.
375
+ - **Geographic flags:** A solicitor in Manchester verifying 50 families in Tokyo is suspicious.
376
+ - **Temporal flags:** 30 verifications in one hour suggests rubber-stamping, not in-person ID checks.
377
+ - **Display:** Clients show a warning badge on credentials from flagged verifiers: "This verifier's issuance pattern is unusual."
378
+
379
+ This is purely client-side — no central authority decides what's suspicious. Each client applies its own heuristics. The transparency of Nostr events makes this possible without surveillance.
380
+
381
+ ### Layer 4 — Optional External Bond (Skin in the Game)
382
+
383
+ Communities may require professional verifiers to maintain an externally
384
+ enforceable Bitcoin bond. If they do, the external mechanism defines how funds
385
+ are locked, adjudicated, slashed, or returned. Signet records the community's
386
+ threshold and the verifier's evidence; it does not custody or move the funds.
387
+
388
+ An enforceable external bond can be:
389
+
390
+ - **Locked** when the verifier attestation (kind 31000 with `type: verifier`) is published
391
+ - **Slashed** (burned or redistributed to reporters) if the verifier is found fraudulent and revoked
392
+ - **Returned** if the verifier deactivates cleanly (retires, leaves the network)
393
+
394
+ Bond amount is configurable per community policy. A casual group might require
395
+ 100,000 sats. A high-security community might require 1,000,000 sats. The
396
+ economic deterrent exists only when the community independently verifies that
397
+ the required funds are actually locked and slashable.
398
+
399
+ The core protocol currently carries a BIP-322 address-control attestation with a
400
+ declared amount. BIP-322 proves control of the named address and binds the
401
+ declaration to the verifier's Nostr key. It does **not** prove the address balance,
402
+ lock funds, monitor reserves, or enforce slashing. Clients MUST NOT treat that
403
+ attestation alone as an active economic bond. They need independent evidence from
404
+ the community's chosen bond mechanism. NWC is a wallet communication protocol;
405
+ it neither locks nor escrows funds and has no role in Signet bond verification.
406
+
407
+ The bond mechanism is optional. Communities that do not require one omit the
408
+ bond threshold from their policy (kind 30078).
409
+
410
+ ### Layer 5 — Community Reporting and Revocation
411
+
412
+ Anyone can publish a **challenge attestation** (kind 31000 with `type: challenge`) against a verifier, presenting evidence of fraudulent behaviour.
413
+
414
+ Challenge flow:
415
+
416
+ ```
417
+ Reporter ──── publishes kind 31000 (type: challenge) ────► challenge attestation
418
+ │
419
+ includes evidence
420
+ (screenshots, registry status,
421
+ anomaly data, testimony)
422
+ │
423
+ ◄──── community reviews ──────┘
424
+ │
425
+ If N trusted accounts (Tier 3+) confirm:
426
+ │
427
+ ├─ Verifier's kind 31000 verifier attestation is superseded
428
+ │ by a revocation attestation (kind 31000, type: revocation)
429
+ │
430
+ ├─ External bond provider may slash under its own rules
431
+ │ (Signet records the claimed bond action only)
432
+ │
433
+ └─ All credentials issued by this verifier
434
+ are flagged in clients
435
+ ```
436
+
437
+ The threshold for revocation (how many confirmations needed) is set per community policy. Default: 5 confirmations from Tier 3+ accounts.
438
+
439
+ ### Layer 6 — Credential Provenance Trail
440
+
441
+ Every credential attestation (kind 31000 with `type: credential`) traces back to its issuer via the `pubkey` field. This is an immutable, public audit trail on Nostr relays.
442
+
443
+ If a verifier is revoked:
444
+
445
+ - Clients display a warning on all credentials they issued: "This verification was issued by a now-revoked verifier. Re-verification recommended."
446
+ - The credentials are not automatically invalidated — the community policy decides whether to require re-verification or grandfather existing credentials.
447
+ - The subject can get re-verified by a different professional. The old credential remains as a historical record.
448
+
449
+ ### The Cumulative Cost of Corruption
450
+
451
+ A corrupt professional in this system must:
452
+
453
+ 1. Be genuinely registered with a professional body (or be caught instantly by registry check)
454
+ 2. Convince professionals in *other* fields to vouch for them (cross-profession requirement)
455
+ 3. Keep issuance volume low enough to avoid anomaly detection (limits the profit from corruption)
456
+ 4. Risk losing an independently verified external bond, if the community requires one
457
+ 5. Risk community reporting, public revocation, and permanent reputation damage on Nostr
458
+ 6. Accept that every fake credential they ever issued is permanently traceable back to them
459
+
460
+ Compare this to centralised identity verification: a company scans your ID, stores it in a database that gets breached, and has no accountability when it fails. Signet doesn't prevent all corruption — nothing does — but it makes corruption more expensive and more detectable than any centralised alternative.
461
+
462
+ ---
463
+
464
+ ## 8. Event Kinds
465
+
466
+ Signet uses two Nostr event kinds for all identity attestations:
467
+
468
+ 1. **Kind 31000** — Generic Verifiable Attestation (NIP-VA, NIP-VA Verifiable Attestations). All 7 identity attestation types share this kind, differentiated by the `type` tag.
469
+ 2. **Kind 30078** — NIP-78 App-specific Data. Used for community verification policies.
470
+
471
+ Voting kinds (30482-30484) are documented in `spec/voting.md`.
472
+
473
+ ### Attestation Event Structure
474
+
475
+ All attestation events use kind 31000 with the following common tags:
476
+
477
+ - `["type", "<attestation_type>"]` — one of: `credential`, `vouch`, `verifier`, `challenge`, `revocation`, `identity-bridge`, `delegation`
478
+ - `["d", "..."]` — d-tag format depends on the attestation pattern (see below)
479
+ - `["summary", "<human-readable description>"]` — brief description of the attestation
480
+ - `["algo", "secp256k1"]` — cryptographic algorithm
481
+ - `["L", "signet"]` — protocol namespace label
482
+
483
+ ### Attestation Patterns
484
+
485
+ Each attestation type uses the NIP-VA pattern that matches its speech act:
486
+
487
+ - **Assertion-first (Tier 2-4 credentials):** The subject publishes a Tier 1 self-declaration. The verifier references it via `e` tag with `"assertion"` marker. d-tag: `assertion:<tier-1-event-id>`. The `type: credential` tag is included as a hybrid override for relay filtering and resilience.
488
+ - **Direct claim (vouches, challenges):** The attestor originates the claim. d-tag: `<type>:<subject-pubkey>`.
489
+ - **Self-attestation (Tier 1, verifier registration):** The publisher is also the subject. d-tag: `<type>:<own-pubkey>`.
490
+
491
+ ### Attestation Type: Credential
492
+
493
+ Tier 1 is a self-declaration (direct claim, `pubkey` equals `p` tag):
494
+
495
+ ```jsonc
496
+ {
497
+ "kind": 31000,
498
+ "pubkey": "<subject_pubkey>",
499
+ "tags": [
500
+ ["d", "credential:<subject_pubkey>"], // direct claim (self-issued)
501
+ ["p", "<subject_pubkey>"],
502
+ ["type", "credential"],
503
+ ["tier", "1"],
504
+ ["verification-type", "self"],
505
+ ["scope", "adult"],
506
+ ["method", "self-declaration"],
507
+ ["algo", "secp256k1"],
508
+ ["L", "signet"]
509
+ ],
510
+ "content": ""
511
+ }
512
+ ```
513
+
514
+ Tier 3 uses the assertion-first hybrid pattern, referencing the subject's Tier 1 self-declaration:
515
+
516
+ ```jsonc
517
+ {
518
+ "kind": 31000,
519
+ "pubkey": "<verifier_pubkey>",
520
+ "tags": [
521
+ ["d", "assertion:<tier-1-event-id>"], // assertion-first d-tag
522
+ ["e", "<tier-1-event-id>", "wss://relay.example.com", "assertion"], // references Tier 1
523
+ ["type", "credential"], // hybrid: explicit type for filtering
524
+ ["p", "<subject_pubkey>"],
525
+ ["tier", "3"],
526
+ ["verification-type", "professional"],
527
+ ["scope", "adult"],
528
+ ["method", "in-person-id"],
529
+ ["profession", "solicitor"],
530
+ ["jurisdiction", "GB"],
531
+ ["expiration", "<unix_timestamp>"],
532
+ ["summary", "professional verification (tier 3) for abc123..."],
533
+ ["algo", "secp256k1"],
534
+ ["L", "signet"]
535
+ ],
536
+ "content": "<zkp_proof_blob>"
537
+ }
538
+ ```
539
+
540
+ ### Attestation Type: Vouch
541
+
542
+ A replaceable event published by a peer vouching for another user.
543
+
544
+ ```jsonc
545
+ {
546
+ "kind": 31000,
547
+ "pubkey": "<voucher_pubkey>",
548
+ "tags": [
549
+ ["d", "vouch:<subject_pubkey>"], // type-prefixed d-tag
550
+ ["p", "<subject_pubkey>"],
551
+ ["type", "vouch"], // attestation type
552
+ ["method", "in-person"], // "in-person" or "online"
553
+ ["context", "bitcoin-meetup"], // optional: where/how they met
554
+ ["voucher-tier", "3"], // voucher's own tier at time of vouch
555
+ ["voucher-score", "87"], // voucher's own score at time of vouch
556
+ ["summary", "in-person vouch for abc123..."],
557
+ ["algo", "secp256k1"], // cryptographic algorithm (§9.5)
558
+ ["L", "signet"],
559
+ ["l", "vouch", "signet"]
560
+ ],
561
+ "content": "" // no personal data
562
+ }
563
+ ```
564
+
565
+ ### Community Verification Policy (NIP-78)
566
+
567
+ A NIP-78 app-specific data event published by a community operator defining minimum verification requirements. Uses kind 30078 with a `signet:policy:` d-tag prefix.
568
+
569
+ ```jsonc
570
+ {
571
+ "kind": 30078,
572
+ "pubkey": "<community_operator_pubkey>",
573
+ "tags": [
574
+ ["d", "signet:policy:<community_identifier>"],
575
+ ["adult-min-tier", "2"],
576
+ ["child-min-tier", "3"],
577
+ ["min-score", "50"], // optional minimum score
578
+ ["mod-min-tier", "3"], // optional moderator requirement
579
+ ["enforcement", "client"], // "client", "relay", or "both"
580
+ ["verifier-bond", "100000"], // optional: min sats bond for verifiers
581
+ ["revocation-threshold", "5"], // optional: confirmations needed to revoke
582
+ ["algo", "secp256k1"] // cryptographic algorithm (§9.5)
583
+ ],
584
+ "content": "<human-readable policy description>"
585
+ }
586
+ ```
587
+
588
+ ### Attestation Type: Verifier
589
+
590
+ A replaceable event published by a professional declaring their verifier status.
591
+
592
+ ```jsonc
593
+ {
594
+ "kind": 31000,
595
+ "pubkey": "<verifier_pubkey>",
596
+ "tags": [
597
+ ["d", "verifier"],
598
+ ["type", "verifier"], // attestation type
599
+ ["profession", "solicitor"],
600
+ ["jurisdiction", "UK"],
601
+ ["licence", "<encrypted_or_hashed_licence_number>"],
602
+ ["body", "Law Society of England and Wales"],
603
+ ["summary", "solicitor verifier in UK"],
604
+ ["algo", "secp256k1"], // cryptographic algorithm (§9.5)
605
+ ["L", "signet"],
606
+ ["l", "verifier", "signet"]
607
+ // Cross-verification vouches from other professionals
608
+ // are separate vouch attestation events pointing at this pubkey
609
+ ],
610
+ "content": "<optional: public statement about verification services>"
611
+ }
612
+ ```
613
+
614
+ ### Attestation Type: Challenge
615
+
616
+ An event published by anyone challenging a verifier's legitimacy. Triggers community review.
617
+
618
+ ```jsonc
619
+ {
620
+ "kind": 31000,
621
+ "pubkey": "<reporter_pubkey>",
622
+ "tags": [
623
+ ["d", "challenge:<verifier_pubkey>"], // type-prefixed d-tag
624
+ ["p", "<verifier_pubkey>"],
625
+ ["type", "challenge"], // attestation type
626
+ ["reason", "anomalous-volume"], // "anomalous-volume", "registry-mismatch",
627
+ // "fraudulent-attestation", "licence-revoked",
628
+ // "other"
629
+ ["evidence-type", "registry-screenshot"], // type of evidence provided
630
+ ["reporter-tier", "3"], // reporter's own tier
631
+ ["summary", "Challenge against verifier abc123... (anomalous-volume)"],
632
+ ["algo", "secp256k1"], // cryptographic algorithm (§9.5)
633
+ ["L", "signet"],
634
+ ["l", "challenge", "signet"]
635
+ ],
636
+ "content": "<detailed evidence and explanation>"
637
+ }
638
+ ```
639
+
640
+ ### Attestation Type: Revocation
641
+
642
+ A replaceable event published when a community confirms a challenge.
643
+
644
+ ```jsonc
645
+ {
646
+ "kind": 31000,
647
+ "pubkey": "<revoking_authority_pubkey>", // community operator or threshold of Tier 3+ accounts
648
+ "tags": [
649
+ ["d", "revocation:<verifier_pubkey>"], // type-prefixed d-tag
650
+ ["p", "<verifier_pubkey>"],
651
+ ["type", "revocation"], // attestation type
652
+ ["challenge", "<challenge_event_id>"], // the challenge that triggered this
653
+ ["confirmations", "7"], // number of Tier 3+ accounts that confirmed
654
+ ["bond-action", "slashed"], // "slashed", "returned", "held"
655
+ ["scope", "full"], // "full" = all credentials flagged,
656
+ // "partial" = specific credentials flagged
657
+ ["effective", "<unix_timestamp>"], // when revocation takes effect
658
+ ["summary", "Revocation of verifier abc123..."],
659
+ ["algo", "secp256k1"], // cryptographic algorithm (§9.5)
660
+ ["L", "signet"],
661
+ ["l", "revocation", "signet"]
662
+ ],
663
+ "content": "<summary of findings>"
664
+ }
665
+ ```
666
+
667
+ **Client behaviour on revocation:**
668
+
669
+ 1. Display a warning on all credentials issued by the revoked verifier
670
+ 2. Reduce the Signet Score contribution of those credentials to zero
671
+ 3. Notify affected users that re-verification is recommended
672
+ 4. Do not automatically invalidate credentials — the community policy decides whether to require re-verification or grandfather existing ones
673
+
674
+ ### Attestation Type: Identity Bridge
675
+
676
+ A replaceable event published by an anonymous account to prove it is controlled by a verified identity, without revealing which one. Uses SAG ring signatures over secp256k1.
677
+
678
+ **Use case:** A user has a real-name account (verified at Tier 3 by a professional) and an anonymous account. The identity bridge lets the anonymous account prove "I am a real verified person" without revealing which verified person. This enables anonymous participation with trust.
679
+
680
+ ```jsonc
681
+ {
682
+ "kind": 31000,
683
+ "pubkey": "<anon_pubkey>", // the anonymous account publishing this
684
+ "tags": [
685
+ ["d", "identity-bridge"],
686
+ ["type", "identity-bridge"], // attestation type
687
+ ["ring-min-tier", "3"], // minimum verification tier of ring members
688
+ ["ring-size", "10"], // number of pubkeys in the ring
689
+ ["algo", "secp256k1"], // cryptographic algorithm (§9.5)
690
+ ["L", "signet"],
691
+ ["l", "identity-bridge", "signet"]
692
+ ],
693
+ "content": "{\"ringSig\":{\"ring\":[...],\"c0\":\"...\",\"responses\":[...],\"message\":\"signet:identity-bridge:<anon_pubkey>:<timestamp>\"},\"timestamp\":...}"
694
+ }
695
+ ```
696
+
697
+ **Ring signature construction:**
698
+
699
+ 1. The real verified account's pubkey is placed at a random position in a ring of N verified pubkeys (minimum N=5).
700
+ 2. The binding message is `signet:identity-bridge:<anon_pubkey>:<timestamp>`.
701
+ 3. The real account's private key signs this message using a SAG ring signature, proving one of the N ring members also controls the anon account.
702
+ 4. The Nostr event itself is signed by the anonymous account's private key.
703
+
704
+ **Verification:**
705
+
706
+ 1. Verify the Nostr event signature (anon account signed the event).
707
+ 2. Parse the ring signature from content.
708
+ 3. Verify the binding message format matches `signet:identity-bridge:<event.pubkey>:<timestamp>`.
709
+ 4. Verify the ring signature (one of the ring members signed the binding message).
710
+ 5. Verify ring size >= 5 (anonymity threshold).
711
+
712
+ **Signet Score contribution:**
713
+
714
+ - Base weight: 50 points (between professional verification and in-person vouch).
715
+ - Scaled by ring minimum tier: `weight = 50 × (ringMinTier / 4)`.
716
+ - Tier 3 ring → 37.5 points. Tier 4 ring → 50 points.
717
+ - Only one bridge per account is counted.
718
+
719
+ **Trust compounding:** When bridged anonymous accounts vouch for each other, each vouch is weighted by the voucher's score (which includes bridge points). This creates natural trust compounding without a special mechanism.
720
+
721
+ **Privacy guarantees:**
722
+
723
+ - The ring signature reveals only that *one of N* verified accounts controls the anon account, not which one.
724
+ - Minimum ring size of 5 provides meaningful anonymity (1-in-5 or better).
725
+ - Larger rings provide stronger anonymity at no additional cost to the verifier.
726
+ - The binding message prevents ring signature reuse across different anon accounts.
727
+
728
+ ---
729
+
730
+ ## 9. Cryptographic Stack
731
+
732
+ The protocol design (tiers, scores, event kinds, policies) is specified independently of the ZKP implementation. The credential format works regardless of which cryptographic library backs the proofs. This section specifies the recommended architecture.
733
+
734
+ ### Recommended Architecture: Hybrid Layers
735
+
736
+ ```
737
+ Layer 1: Schnorr — the base (zero new dependencies)
738
+ │
739
+ ├─ Credential issuance & verification
740
+ │ Verifier signs kind 31000 credential attestation with their Nostr key.
741
+ │ Any client verifies with schnorr.verify().
742
+ │
743
+ ├─ Selective disclosure via Merkle trees
744
+ │ Credential attributes as Merkle leaves, sign root.
745
+ │ Holder reveals chosen attributes + sibling paths.
746
+ │ @noble/secp256k1 + @noble/hashes (already in every Nostr client).
747
+ │
748
+ ├─ Ring signatures for issuer privacy (Tier 3/4)
749
+ │ SAG: "one of these N professionals verified this"
750
+ │ without revealing which one.
751
+ │ Stays on secp256k1.
752
+ │
753
+ ├─ MuSig2 for multi-verifier co-signing
754
+ │ Multiple professionals co-sign → single aggregated Schnorr sig.
755
+ │
756
+ └─ Signet Score computation
757
+ Pure client-side math. Count vouches, weight by voucher score.
758
+ No crypto needed.
759
+
760
+ Layer 2: Pedersen range proofs — targeted addition (for Tier 4 age proofs)
761
+ │
762
+ └─ Age range proofs
763
+ "This child is in age range [8, 12]" without revealing exact age.
764
+ Pedersen commitment + Pedersen range proof range proof on secp256k1.
765
+ ~700 byte proofs. No trusted setup. No new curve.
766
+
767
+ Layer 3: General-purpose ZK (future, if needed)
768
+ │
769
+ ├─ Complex threshold proofs
770
+ │ "I have N vouches from tier 2+ accounts" via recursive composition.
771
+ │
772
+ ├─ Credential binding proofs
773
+ │ Prove credential ownership + attribute predicate in one proof.
774
+ │
775
+ └─ Unlinkable presentations (if required)
776
+ Re-randomisable proofs. For when threat model evolves.
777
+ ```
778
+
779
+ ### What Each Tier Needs
780
+
781
+ | Tier | Crypto Required | New Dependencies |
782
+ |------|----------------|------------------|
783
+ | **Tier 1** (self-declared) | Standard Nostr event signing | None (already present) |
784
+ | **Tier 2** (web-of-trust) | Vouch events + score calculation | None |
785
+ | **Tier 3** (professional, adult) | Ring signature on credential | Ring signature library (secp256k1-based) |
786
+ | **Tier 4** (professional, adult+child) | Ring sig + age range proof | Ring sig + Pedersen range proofs library |
787
+ | **Blue checkmark / score** | Read existing events, compute score | None |
788
+
789
+ ### The Credential Signing Decision
790
+
791
+ Verifiers sign credentials with their **Nostr key** (secp256k1 Schnorr). No second keypair required.
792
+
793
+ | Approach | Pro | Con | Decision |
794
+ |----------|-----|-----|----------|
795
+ | **Nostr key only** | One identity, Nostr-native, no extra keys | Expensive to prove inside ZK circuits if needed later | **Use this.** |
796
+ | ZK-friendly curve (Baby Jubjub) | Cheap to prove in ZK circuits | Verifiers need a second keypair | Defer unless ZK circuit proofs become essential. |
797
+
798
+ Ring signatures handle issuer privacy without ZK circuits. Pedersen range proofs handle age range proofs without leaving secp256k1. The ZK-friendly signature question only arises if the protocol needs to prove "this Nostr key signed this credential" inside a zero-knowledge circuit — and the current design avoids that need.
799
+
800
+ ### Reference Libraries
801
+
802
+ | Library | Purpose | Notes |
803
+ |---------|---------|-------|
804
+ | `@noble/secp256k1` | Core Schnorr sign/verify | Stable, audited, 4.94KB gzipped |
805
+ | `@noble/hashes` | SHA-256 for Merkle trees | Stable, audited |
806
+ | Ring signature lib (e.g. Nostringer) | SAG on Nostr pubkeys | Experimental — needs audit before production |
807
+ | MuSig2 lib | Multi-party signing | Functional, BIP-327 |
808
+ | Pedersen range proofs lib | Range proofs on secp256k1 | Needs audit before production |
809
+
810
+ ### Quantum Readiness
811
+
812
+ Every Signet event carries an `["algo", "secp256k1"]` tag identifying the asymmetric cryptographic algorithm used for event signing and key agreement. This tag serves two purposes:
813
+
814
+ 1. **Forward compatibility.** When post-quantum algorithms (e.g. ML-DSA, SLH-DSA, ML-KEM) are standardised for Nostr, new events will carry a different `algo` value. Parsers can distinguish pre- and post-quantum events without heuristics.
815
+ 2. **Graceful migration.** During a transition period, clients can accept both `secp256k1` and post-quantum algorithm values, enabling a rolling upgrade across the network.
816
+
817
+ **Rules for the `algo` tag:**
818
+
819
+ | Rule | Detail |
820
+ |------|--------|
821
+ | **MUST be present** on all Signet attestation events (kind 31000) | Builders set it to `DEFAULT_CRYPTO_ALGORITHM` (`secp256k1`) |
822
+ | **Parsers MUST default** to `secp256k1` if absent | Ensures backward compatibility with legacy events created before this tag was introduced |
823
+ | **Value is a free-form string** | Allows future algorithms without a protocol revision — just publish events with the new value |
824
+ | **One algorithm per event** | An event is signed under a single algorithm; hybrid constructions would use two separate events |
825
+
826
+ **Current status:** All Signet events use secp256k1 (Schnorr signatures via BIP-340). No post-quantum migration is currently planned, but the tagging ensures the protocol is ready when one becomes necessary.
827
+
828
+ ### Open Implementation Questions
829
+
830
+ 1. **Ring signature audit.** Ring signatures are critical for Tier 3/4 issuer privacy. The SAG math is sound (used by Monero for years) but JS implementations need audit.
831
+ 2. **Pedersen range proofs library choice.** Pure JS (slower, easier to audit) vs WASM (faster, harder to audit the C layer).
832
+ 3. **Ring size.** How many professional verifiers form the anonymity set? Target: 20-50 verifiers per profession per jurisdiction.
833
+ 4. **Credential expiry.** Verification credentials should expire (recommended: 1-2 years) and be renewable.
834
+ 5. **Revocation propagation.** NIP-09 deletion requests are advisory only. The kind 31000 challenge/revocation attestation mechanism handles this at the protocol level.
835
+
836
+ ---
837
+
838
+ ## 10. Social Proof — The Blue Checkmark
839
+
840
+ The verification system is not limited to child safety. It is a general-purpose Nostr identity layer.
841
+
842
+ ### For Users Who Won't Show Documents
843
+
844
+ They can still build trust through:
845
+
846
+ - Peer vouches from verified users
847
+ - In-person key signings at meetups and conferences
848
+ - Account age and consistent behaviour
849
+ - Online vouches from high-IQ accounts
850
+
851
+ This gives them a visible Signet IQ and a checkmark — weaker than professional verification, but more than nothing. And nothing is what everyone on Nostr has today.
852
+
853
+ ### For Public Figures
854
+
855
+ Already-doxed individuals (podcasters, conference speakers, known community members) can leverage their public identity. Their checkmark is backed by the fact that hundreds of people have met them and can vouch. They become trust anchors for their communities.
856
+
857
+ ### For Creators
858
+
859
+ A verified creator can prove they're real without revealing their legal name. Content gated by verification tiers becomes more valuable when the creator has a verified identity backing it.
860
+
861
+ ### Checkmark Display
862
+
863
+ | Display | Meaning |
864
+ |---------|---------|
865
+ | No mark | Unverified (Tier 1) |
866
+ | ✓ | Web-of-trust vouched (Tier 2) |
867
+ | ✓✓ | Professional verified, adult (Tier 3) |
868
+ | ✓✓✓ | Professional verified, adult + child (Tier 4) |
869
+ | Signet IQ | Continuous identity quality (0–200) visible on drill-down |
870
+
871
+ ---
872
+
873
+ ## 11. Alignment with Existing Standards
874
+
875
+ | Standard | Relevance |
876
+ |----------|-----------|
877
+ | **NIP-58** (Badges, kind 30009/8) | Existing attestation system on Nostr. Signet credentials extend this pattern with cryptographic proofs. |
878
+ | **NIP-101** (proposed) | Decentralised trust system integrating W3C VC format with Nostr. Signet is complementary — simpler, Nostr-native, focused on progressive tiers. |
879
+ | **Nostr DID method** (`did:nostr:<hex_pubkey>`) | Enables Nostr keys to participate in W3C DID/VC ecosystem. Signet credentials could be wrapped as W3C VCs for interop. |
880
+ | **SchnorrSecp256k1Signature2019** (DIF) | Proposed proof type for W3C VCs using Schnorr over secp256k1. Would let Signet events be treated as standards-compliant W3C VCs. |
881
+ | **ISO/IEC 27566-1:2025** | Age assurance standard. Signet's architecture is compatible with the outcomes-based framework (effectiveness, privacy, security, acceptability). |
882
+ | **UK DIATF** | Digital Identity and Attributes Trust Framework. Signet's Tier 3/4 architecture aligns. Not yet certified. Certification path exists. |
883
+ | **EU eIDAS 2.0** | European digital identity framework. Signet's selective disclosure via Merkle trees and ZKP proofs aligns with eIDAS requirements for minimal disclosure. |
884
+
885
+ ---
886
+
887
+ ## 12. Regulatory Compatibility
888
+
889
+ Signet is designed to satisfy identity verification requirements across multiple jurisdictions without centralised data collection.
890
+
891
+ | Regulation | How Signet Addresses It |
892
+ |------------|------------------------|
893
+ | **UK Online Safety Act** (ss.9, 11, 12) | Tier 4 provides "highly effective age assurance" via professional in-person verification. Exceeds Ofcom's accepted methods. No centralised ID scanning. |
894
+ | **COPPA / COPPA 2.0** (US) | Cryptographic proof of parental consent via Tier 3/4 credential. Exceeds current parental consent mechanisms. The FTC's March 2026 policy statement permits data collection solely for age verification with robust deletion — Signet goes further by collecting no personal data at all. The ZKP proof contains zero PII. |
895
+ | **EU eIDAS 2.0** | Credential format compatible with eIDAS selective disclosure direction. Could accept EU digital identity wallet credentials as Tier 3 input. |
896
+ | **France SREN law** | ZKP-based age verification is explicitly what the law requires. |
897
+ | **Australia under-16 ban** | Tier 4 proves child's age range without central verification. |
898
+ | **ISO/IEC 27566-1:2025** | Protocol design is compatible with the outcomes-based framework. |
899
+
900
+ ### The FTC's New Position and Signet
901
+
902
+ In March 2026, the FTC issued a policy statement signalling flexibility on COPPA age checks: it will not take enforcement action where personal data is collected solely for age verification purposes, provided the data is robustly deleted and clear notice is given to parents and children.
903
+
904
+ This is significant because it removes a major blocker — platforms were previously reluctant to implement age verification for fear of COPPA liability for collecting the verification data itself. The FTC is now saying: verify ages, just delete the data.
905
+
906
+ Signet leapfrogs this entirely:
907
+
908
+ | FTC Requirement | Signet's Position |
909
+ |----------------|-------------------|
910
+ | Data collected solely for age verification | No data collected — ZKP proves age range without transmitting personal data |
911
+ | Robust data deletion | Nothing to delete — no PII ever enters any system |
912
+ | Clear notice to parents/children | Parent initiates the entire verification process and holds all keys |
913
+ | Don't use data for other purposes | Cryptographically impossible — the proof contains no personal data to repurpose |
914
+
915
+ The FTC lowered the bar. Signet doesn't need the bar — it flies over it.
916
+
917
+ ### The Privacy Argument
918
+
919
+ Every other approach to age verification involves a trade-off: privacy vs safety, user experience vs verification rigour, centralised control vs accountability. Signet is designed to avoid that trade-off:
920
+
921
+ - Professional verifies in person → ZKP credential
922
+ - Credential proves age range without revealing personal data
923
+ - No personal data stored centrally — no database to breach
924
+ - Anti-corruption layers on verifier network
925
+ - Audit trail on Nostr relays
926
+
927
+ ---
928
+
929
+ ## 13. Limitations
930
+
931
+ | Limitation | Why It's Acceptable |
932
+ |------------|---------------------|
933
+ | **A verified parent can still be a bad parent** | True of all systems. The protocol proves identity, not character. But it creates accountability — the parent's verified identity is cryptographically linked. |
934
+ | **Professional verifiers could collude** | Possible but career-ending. Cross-verification and professional body oversight mitigate this. Same risk exists in the existing notary/legal system. |
935
+ | **Doesn't prevent all predators** | A determined predator with a real child could still misuse the system. But they can no longer be anonymous — their Tier 4 credential links back to a professional who verified them in person. |
936
+ | **ZKP crypto is complex** | Implementation risk. Mitigated by using proven libraries and by designing the protocol independently of the crypto stack. |
937
+ | **Adoption requires verifiers** | Chicken-and-egg: users need verifiers, verifiers need users. Mitigated by the web-of-trust tier (no professionals needed) and by starting with existing professional networks. |
938
+
939
+ ---
940
+
941
+ ## 14. Implementation
942
+
943
+ Signet is designed as a standalone NIP. Any Nostr client can implement it independently. The protocol does not depend on any specific client.
944
+
945
+ ### Integration Points
946
+
947
+ Clients implementing Signet can integrate credentials with:
948
+
949
+ - Parent-controlled vault tiers (cryptographic access control)
950
+ - Child account protection (NIP-26 delegation)
951
+ - Community verification policies
952
+ - Age-based permission defaults
953
+
954
+ ### Contributing
955
+
956
+ Signet is open source. Contributions, feedback, and protocol discussion are welcome.
957
+
958
+ - Protocol specification: this document
959
+ - TypeScript library: `signet-protocol` on npm
960
+ - **Attestation kind:** Kind 31000 is used for all Signet identity attestations (credentials, vouches, verifier registration, challenges, revocations, identity bridges, delegation). Kind 30078 (NIP-78) is used for community policies. The voting extension uses kinds 30482–30484.
961
+
962
+ ---
963
+
964
+ ## 15. Identity Management & Peer Verification
965
+
966
+ ### 15.1 Profile Creation (nsec-tree Identity Model)
967
+
968
+ Signet identities are derived using [nsec-tree](https://www.npmjs.com/package/nsec-tree), a hierarchical key derivation library for Nostr. A master secret is established from one of two sources, then child personas are derived deterministically from it.
969
+
970
+ **Establishing the master secret:**
971
+
972
+ Two entry points are supported:
973
+
974
+ 1. **From a BIP-39 mnemonic** (`fromMnemonic()`): Generate a 12-word BIP-39 mnemonic (128 bits of entropy + 4-bit checksum, encoded as 12 English words). The mnemonic is converted to a 64-byte seed via PBKDF2-SHA512, then BIP-32 HD derivation at path `m/44'/1237'/727'/0'/0'` produces the master private key. The 12 words remain the human-readable backup for this flow.
975
+
976
+ 2. **From an existing nsec** (`fromNsec()`): Users with an existing Nostr private key may import it as the master secret. An HMAC-SHA256 separation layer is applied so that the master material differs from the raw private key before any child keys are derived.
977
+
978
+ ```
979
+ Option A (new identity):
980
+ BIP-39 mnemonic (12 words)
981
+ → PBKDF2-SHA512 seed
982
+ → BIP-32 HD path m/44'/1237'/727'/0'/0'
983
+ → master secret
984
+
985
+ Option B (existing nsec):
986
+ nsec (NIP-19 bech32-encoded private key)
987
+ → HMAC-SHA256 separation layer
988
+ → master secret
989
+ ```
990
+
991
+ **Required personas:**
992
+
993
+ Every Signet identity MUST derive two personas from the master secret:
994
+
995
+ | Persona | Purpose string | Role |
996
+ |---------|---------------|------|
997
+ | `natural-person` | `nostr:persona:natural-person` | Real-identity credentials; receives professionally verified attestations |
998
+ | `persona` | `nostr:persona:persona` | Anonymous alias; receives age-range-only credentials from the two-credential ceremony |
999
+
1000
+ Clients MAY derive additional personas using the purpose pattern `nostr:persona:{name}` for application-specific contexts.
1001
+
1002
+ **Child derivation:**
1003
+
1004
+ Each persona is derived from the master secret using HMAC-SHA256 with the following construction:
1005
+
1006
+ ```
1007
+ HMAC-SHA256(
1008
+ key = master_secret,
1009
+ data = "nsec-tree\0" || purpose_string || "\0" || index_be32
1010
+ )
1011
+ ```
1012
+
1013
+ Where `index_be32` is the derivation index encoded as a big-endian uint32. If the HMAC output is not a valid secp256k1 scalar (i.e. it is zero or ≥ the curve order), the index is incremented and the derivation is retried. The maximum index is `MAX_INDEX = 0xFFFFFFFF`.
1014
+
1015
+ The derived scalar becomes the child private key; the corresponding Schnorr x-only public key is the child's Nostr identity.
1016
+
1017
+ **Optional passphrase:** When deriving from a mnemonic, an optional passphrase adds a second factor (the "25th word") — a different passphrase produces an entirely different master secret and identity tree.
1018
+
1019
+ ### 15.1a Linkage Proofs
1020
+
1021
+ Because all personas are derived from a single master secret, the master owner can prove cryptographic ownership of any child identity without revealing the derivation relationship to observers.
1022
+
1023
+ Two proof types are defined:
1024
+
1025
+ | Proof type | What it contains | Privacy |
1026
+ |------------|-----------------|---------|
1027
+ | **Blind proof** | BIP-340 Schnorr signature by the master key over the child pubkey | No derivation metadata — only proves master owns child |
1028
+ | **Full proof** | Same Schnorr signature + purpose string + derivation index | Reveals the purpose and index to the verifying party |
1029
+
1030
+ **Construction:**
1031
+
1032
+ ```
1033
+ blind_proof:
1034
+ message = SHA-256("signet-linkage-v1\0" || child_pubkey_bytes)
1035
+ signature = schnorr_sign(master_private_key, message)
1036
+ proof = { masterPubkey, childPubkey, signature }
1037
+
1038
+ full_proof:
1039
+ message = SHA-256("signet-linkage-v1\0" || child_pubkey_bytes)
1040
+ signature = schnorr_sign(master_private_key, message)
1041
+ proof = { masterPubkey, childPubkey, purpose, index, signature }
1042
+ ```
1043
+
1044
+ **Where proofs are used:**
1045
+
1046
+ Linkage proofs are application-layer data. They are exchanged within bilateral flows — for example, inside the challenge (`["payload", ...]` tag of a kind 31000 challenge attestation) and response (kind 31000 revocation attestation) events of a challenge-response flow. They are **not** published as standalone Nostr events, ensuring privacy by default. A relying party who receives a proof can verify it locally without any relay interaction.
1047
+
1048
+ **Verification:**
1049
+
1050
+ Reconstruct the message from `child_pubkey_bytes`, then verify the Schnorr signature against `master_pubkey`. A valid signature proves the holder of the master private key authorised the child identity.
1051
+
1052
+ ### 15.2 Shared Backup (Shamir's Secret Sharing)
1053
+
1054
+ Writing down a master secret (mnemonic or private key bytes) creates a single point of failure. Shamir's Secret Sharing solves this by splitting the master secret into N shares where any M can reconstruct it.
1055
+
1056
+ **Scheme:** GF(256) polynomial interpolation (same field used by AES).
1057
+
1058
+ **Default:** 2-of-3 — keep one share, give two to trusted people. Any two of the three shares reconstruct the original master secret. No individual share reveals anything about the secret.
1059
+
1060
+ **Share encoding:** Each share is encoded as BIP-39 words (same wordlist, same format) so they look and feel familiar. A share holder sees 12 words that look like a normal mnemonic — but they are mathematically useless without a second share.
1061
+
1062
+ **What is backed up:** The master secret — either the mnemonic entropy (for `fromMnemonic()` users) or the private key bytes (for `fromNsec()` users). The backup mechanism is identical in both cases; only the source material differs.
1063
+
1064
+ ```
1065
+ Option A (mnemonic user):
1066
+ [12-word mnemonic entropy] ← master secret
1067
+ │
1068
+ Shamir's 2-of-3 split
1069
+ │
1070
+ ┌─────────┼─────────┐
1071
+ │ │ │
1072
+ Share 1 Share 2 Share 3
1073
+ Keep Give to Give to
1074
+ this friend A friend B
1075
+
1076
+ Any 2 shares → reconstruct → mnemonic entropy → master secret → all personas
1077
+
1078
+ Option B (nsec user):
1079
+ [private key bytes] ← master secret
1080
+ │
1081
+ Shamir's 2-of-3 split
1082
+ │
1083
+ ┌─────────┼─────────┐
1084
+ │ │ │
1085
+ Share 1 Share 2 Share 3
1086
+
1087
+ Any 2 shares → reconstruct → private key bytes → master secret → all personas
1088
+ ```
1089
+
1090
+ **Parameters:**
1091
+ - Threshold (M): minimum 2, configurable
1092
+ - Shares (N): minimum M, maximum 255, configurable
1093
+ - Practical recommendation: 2-of-3 for personal use, 3-of-5 for high-value keys
1094
+
1095
+ ### 15.3 Peer Connections
1096
+
1097
+ When two Signet users meet in person, they establish a cryptographic connection by exchanging QR codes.
1098
+
1099
+ **Connection flow:**
1100
+
1101
+ ```
1102
+ Alice's phone Bob's phone
1103
+ ───────────── ──────────
1104
+ 1. Shows QR code containing: 1. Shows QR code containing:
1105
+ - Alice's public key - Bob's public key
1106
+ - Random nonce - Random nonce
1107
+ - Selected contact info - Selected contact info
1108
+ (name, mobile, etc.) (name, mobile, etc.)
1109
+
1110
+ 2. Scans Bob's QR 2. Scans Alice's QR
1111
+
1112
+ 3. Computes: 3. Computes:
1113
+ ECDH(alice_priv, bob_pub) ECDH(bob_priv, alice_pub)
1114
+ │ │
1115
+ └──── Same shared secret S ────────────┘
1116
+
1117
+ 4. Stores: 4. Stores:
1118
+ - Bob's pubkey - Alice's pubkey
1119
+ - Shared secret S - Shared secret S
1120
+ - Bob's shared info - Alice's shared info
1121
+ - What Alice shared - What Bob shared
1122
+ ```
1123
+
1124
+ **ECDH shared secret derivation:**
1125
+ - Nostr public keys are x-only (32 bytes). Prepend `02` to assume even y-coordinate.
1126
+ - Multiply the full point by the other party's private key scalar.
1127
+ - SHA-256 hash the x-coordinate of the resulting point → 32-byte shared secret.
1128
+ - The result is symmetric: `ECDH(A_priv, B_pub) === ECDH(B_priv, A_pub)`.
1129
+
1130
+ **Contact info selection:** During the QR exchange, each user selects what to share:
1131
+ - Name
1132
+ - Mobile number
1133
+ - Email
1134
+ - Home address
1135
+ - Children's public keys (for families whose kids play together)
1136
+
1137
+ This data is stored **locally only** — never published to relays. The QR exchange happens entirely in person.
1138
+
1139
+ **Automatic vouch:** The connection optionally triggers a mutual in-person vouch attestation (kind 31000 with `type: vouch`), contributing to both users' Tier 2 web-of-trust and Signet Score.
1140
+
1141
+ ### 15.4 Signet Verification Words ("Signet Me")
1142
+
1143
+ The core peer-to-peer identity verification feature. Given a connection with a shared secret, both parties can independently compute the same words at any time — proving they hold the keys that established the connection.
1144
+
1145
+ **The problem:** Your friend calls, panicked, asking you to send money to a new bank account. It sounds like him — social cues are right, he drops the kids' names. But is it really him?
1146
+
1147
+ **The solution:** "Signet me." Both users open each other's profiles. Both see the same words. The caller reads them out. Match → it's really them.
1148
+
1149
+ **Algorithm (powered by canary-kit):**
1150
+
1151
+ Signet delegates word derivation to the [CANARY protocol](https://www.npmjs.com/package/canary-kit) for protocol alignment. Canary handles real-time spoken verification; Signet handles identity and trust.
1152
+
1153
+ ```
1154
+ Inputs:
1155
+ S = shared secret (32 bytes, from ECDH at connection time)
1156
+ t = current Unix timestamp in milliseconds
1157
+ N = word count (1-16, default: 3)
1158
+ I = epoch interval in seconds (default: 30)
1159
+ T = tolerance in epochs (default: 1)
1160
+
1161
+ Epoch:
1162
+ E = floor(t / (I × 1000))
1163
+
1164
+ Derivation (CANARY-DERIVE):
1165
+ H = HMAC-SHA256(S, utf8("signet:verify") || E_be32) // 32-byte MAC
1166
+
1167
+ Word extraction (N × 16-bit indices from H):
1168
+ For i = 0 to N-1:
1169
+ index = readUint16BE(H, i × 2) mod 2048
1170
+ word[i] = CANARY_WORDLIST[index]
1171
+ ```
1172
+
1173
+ **Wordlist:** The Canary spoken-clarity wordlist (2048 words, curated from BIP-39 with homophones and phonetic near-collisions removed). Optimised for verbal exchange.
1174
+
1175
+ **Defaults:** 3 words, 30-second epoch, ±1 tolerance. These are the recommended settings for in-person and phone verification. Implementations MAY allow configuration of all three parameters for different use cases.
1176
+
1177
+ **Configuration guidelines:**
1178
+
1179
+ | Use Case | Words | Epoch | Tolerance | Effective Window |
1180
+ |----------|-------|-------|-----------|-----------------|
1181
+ | In-person verification | 3 | 30s | ±1 | 90 seconds |
1182
+ | Phone call | 3 | 30s | ±1 | 90 seconds |
1183
+ | Quick in-room check | 1 | 30s | ±1 | 90 seconds |
1184
+ | Async/text channel | 3 | 300s | ±1 | 15 minutes |
1185
+ | High-security | 4 | 30s | 0 | 30 seconds |
1186
+
1187
+ **Entropy by word count:**
1188
+
1189
+ | Words | Entropy | Combinations |
1190
+ |-------|---------|-------------|
1191
+ | 1 | 11 bits | 2,048 |
1192
+ | 2 | 22 bits | ~4 million |
1193
+ | 3 | 33 bits | ~8.6 billion |
1194
+ | 4 | 44 bits | ~17.6 trillion |
1195
+
1196
+ **Maximum word count:** 16 (32 bytes of HMAC output / 2 bytes per word index).
1197
+
1198
+ **Properties:**
1199
+ - **Symmetric:** Both parties compute the same words from the same shared secret.
1200
+ - **Rotating:** Words change every epoch. Stale words cannot be replayed.
1201
+ - **Tolerant:** Verification accepts current epoch ±T (default: ±1, giving a 3× epoch window) to accommodate lag.
1202
+ - **Offline:** No server, no relay, no network needed. Pure local computation.
1203
+ - **Configurable:** Word count, epoch interval, and tolerance are adjustable for different security/usability trade-offs.
1204
+ - **Consistent prefix:** The first N words are always the same regardless of the total word count requested. Asking for 4 words gives the same first 3 as asking for 3.
1205
+ - **Protocol aligned:** Uses canary-kit's CANARY-DERIVE primitive and spoken-clarity wordlist, ensuring consistent vocabulary across Signet (identity establishment) and Canary (ongoing verification, duress signalling).
1206
+
1207
+ **Use cases:**
1208
+
1209
+ | Scenario | Flow |
1210
+ |----------|------|
1211
+ | **Friend asks for money** | "Signet me." Both open the app. Words match → send it. |
1212
+ | **Bank calls about suspicious activity** | "Read me my signet." Agent checks your profile → reads the 3 words. |
1213
+ | **You call the bank** | "What's my signet?" You verify they have access to the bank's private key. |
1214
+ | **Family emergency contact** | Relative calls claiming to be with your child. "Signet me first." |
1215
+ | **Business verification** | Supplier calls to change payment details. "Signet me before I update anything." |
1216
+
1217
+ **Display:**
1218
+
1219
+ ```
1220
+ ┌──────────────────────────────────────┐
1221
+ │ Bob's Profile │
1222
+ │ │
1223
+ │ My Signet: │
1224
+ │ │
1225
+ │ ocean · tiger · marble │
1226
+ │ │
1227
+ │ ████████████░░░░ 18s │
1228
+ │ │
1229
+ │ Tap to verify words read to you │
1230
+ └──────────────────────────────────────┘
1231
+ ```
1232
+
1233
+ The progress bar shows time until the next word rotation. The user sees the words update in real time.
1234
+
1235
+ ### 15.5 Security Considerations
1236
+
1237
+ **Key management:**
1238
+ - The master secret (mnemonic entropy for `fromMnemonic()` users, private key bytes for `fromNsec()` users) must be stored offline (paper, metal backup). It is the root of the entire identity tree.
1239
+ - The optional passphrase (mnemonic flow) adds plausible deniability — a different passphrase produces an entirely different master secret and identity tree.
1240
+ - Shamir shares should be distributed to people in different locations.
1241
+
1242
+ **Shared secrets:**
1243
+ - ECDH shared secrets are derived from the connection and stored locally. They never leave the device.
1244
+ - If a device is compromised, all shared secrets on that device are compromised. Users should re-establish connections from a new device.
1245
+
1246
+ **Signet words:**
1247
+ - The epoch interval prevents replay beyond the tolerance window.
1248
+ - An attacker who compromises one party's device gains their shared secrets and can generate words. This is equivalent to compromising their private key — the defence is device security, not protocol design.
1249
+ - For high-value transactions, use 4+ words with tight tolerance (0), and combine with other verification (video call, previously agreed code phrase).
1250
+ - Using 1 word (1-in-2,048) is acceptable only for low-stakes, physical-proximity scenarios where the threat model is impersonation, not brute force.
1251
+ - Both parties MUST agree on the same configuration (word count, epoch, tolerance) for verification to succeed. Mismatched config will always fail.
1252
+
1253
+ **nsec-tree derivation constraints:**
1254
+ - `MAX_INDEX = 0xFFFFFFFF` — implementations MUST NOT attempt derivation beyond this index.
1255
+ - **Curve-order skip:** if the HMAC-SHA256 output for a given index is not a valid secp256k1 scalar (i.e. zero, or ≥ the curve order `n`), increment the index by one and retry. This is equivalent to BIP-32 hardened child key derivation behaviour and avoids biased keys.
1256
+ - **Memory cleanup:** implementations MUST call `zeroise()` on the `Uint8Array` `privateKey` and `publicKey` fields of `Identity` objects when they are no longer needed. `TreeRoot.destroy()` MUST be called to zeroise the root secret held in memory.
1257
+ - **JS string limitation:** `nsec` and `npub` string fields on `Identity` objects cannot be wiped from memory — JavaScript string primitives are immutable and GC-managed. Only `Uint8Array` fields (`privateKey`, `publicKey`) can be actively zeroed. Implementations should avoid materialising `nsec`/`npub` strings unless required by the application layer.
1258
+
1259
+ ---
1260
+
1261
+ ---
1262
+
1263
+ ## 16. Identity Bridge
1264
+
1265
+ ### 16.1 Overview
1266
+
1267
+ The identity bridge allows users to maintain separate anonymous and real-name accounts while cryptographically proving their anonymous account is backed by a verified identity. This is essential for privacy-respecting participation in communities that require trust.
1268
+
1269
+ **Example flow:**
1270
+
1271
+ 1. Alice has a real-name account verified at Tier 3 by her solicitor.
1272
+ 2. Alice creates an anonymous account for participating in communities where she wants privacy.
1273
+ 3. Alice creates an identity bridge: her real account signs a ring signature (among 10 other verified accounts) proving "one of these 11 people also controls this anon account."
1274
+ 4. The identity bridge attestation (kind 31000 with `type: identity-bridge`) is published from Alice's anon account.
1275
+ 5. Community members see Alice's anon account has a Signet Score of ~38 (from the bridge alone), indicating a verified person is behind it.
1276
+ 6. When other bridged anonymous accounts vouch for Alice's anon account, trust compounds naturally.
1277
+
1278
+ ### 16.2 Ring Construction
1279
+
1280
+ The ring must contain at least 5 verified pubkeys (the `MIN_BRIDGE_RING_SIZE` constant). The user's real pubkey is placed at a random position among decoys selected from the pool of verified accounts on the relay.
1281
+
1282
+ Decoy selection:
1283
+ - Query the relay for pubkeys with kind 31000 credential attestations at or above the desired minimum tier.
1284
+ - Exclude the user's real pubkey from the candidate pool.
1285
+ - Randomly select `ringSize - 1` decoys.
1286
+ - Insert the real pubkey at a random index.
1287
+
1288
+ ### 16.3 nsec Import
1289
+
1290
+ Users may import existing Nostr accounts via nsec (NIP-19 bech32-encoded private keys). When imported via `fromNsec()`, the private key bytes become the master secret after an HMAC-SHA256 separation layer is applied. nsec-imported accounts:
1291
+ - Have no BIP-39 mnemonic, but CAN use Shamir backup (the private key bytes are the material that is split).
1292
+ - Can fully participate in the protocol (vouch, receive credentials, create bridges).
1293
+ - Can derive additional personas from the imported key as the master secret.
1294
+ - Are clearly indicated in the UI as nsec-imported.
1295
+
1296
+ ### 16.4 Multi-Account Management
1297
+
1298
+ A device may hold multiple accounts (real-name + anonymous, or multiple identities). Each account:
1299
+ - Is identified by its pubkey (not a singleton key).
1300
+ - Has its own connections, credentials, and Signet Score.
1301
+ - Can be switched between in the app UI.
1302
+
1303
+ Connections are scoped to the owning account. Credentials and vouches are naturally scoped by pubkey in the Nostr protocol.
1304
+
1305
+ ---
1306
+
1307
+ ## 17. Entity Type Classification
1308
+
1309
+ ### 17.1 Overview
1310
+
1311
+ The protocol classifies accounts along two orthogonal axes:
1312
+
1313
+ - **Verification tier** (1–4): How deeply an account is verified.
1314
+ - **Entity type** (9 types): What kind of entity the account represents.
1315
+
1316
+ These axes are independent. A Natural Person could be Tier 3 or Tier 4. An Unlinked Agent is always Tier 1. Entity type is determined by the cryptographic mechanism that links the account to the chain of trust.
1317
+
1318
+ ### 17.2 Entity Types
1319
+
1320
+ The protocol defines nine entity types in three root categories.
1321
+
1322
+ **Root categories:**
1323
+
1324
+ | Protocol Term | Code | Description |
1325
+ |---|---|---|
1326
+ | Natural Person | `natural_person` | A living human, professionally verified (Tier 3+) |
1327
+ | Juridical Person | `juridical_person` | A legal entity, verified by professional + multi-sig from Natural Persons |
1328
+ | Unlinked Agent | `unlinked_agent` | An unverified account with no chain of trust (the default) |
1329
+
1330
+ **Alias subtypes (anonymous identities):**
1331
+
1332
+ | Protocol Term | Code | Description |
1333
+ |---|---|---|
1334
+ | Persona | `persona` | Anonymous alias of a Natural Person, linked via identity bridge (ring signature) |
1335
+ | Juridical Persona | `juridical_persona` | Anonymous alias of a Juridical Person, linked via identity bridge |
1336
+
1337
+ **Agent subtypes (delegated bots):**
1338
+
1339
+ | Protocol Term | Code | Description |
1340
+ |---|---|---|
1341
+ | Personal Agent | `personal_agent` | Bot delegated by a Natural Person |
1342
+ | Unlinked Personal Agent | `unlinked_personal_agent` | Bot delegated by a Persona |
1343
+ | Organised Agent | `organised_agent` | Bot delegated by a Juridical Person |
1344
+ | Unlinked Organised Agent | `unlinked_organised_agent` | Bot delegated by a Juridical Persona |
1345
+
1346
+ **Naming convention:** The protocol uses legal terminology (Natural Person, Juridical Person, Persona) for precision. Client applications SHOULD use friendly labels (Person, Organisation, Alias) in user interfaces. See §17.8 for the recommended label mapping.
1347
+
1348
+ ### 17.3 Ownership and Delegation Tree
1349
+
1350
+ ```
1351
+ Natural Person ──► Personal Agent
1352
+ │
1353
+ └──► Persona ──► Unlinked Personal Agent
1354
+
1355
+ Juridical Person ──► Organised Agent
1356
+ │
1357
+ └──► Juridical Persona ──► Unlinked Organised Agent
1358
+
1359
+ Unlinked Agent (standalone, no chain of trust)
1360
+ ```
1361
+
1362
+ Every account starts as an Unlinked Agent. Entity type is earned through the appropriate verification mechanism.
1363
+
1364
+ ### 17.4 Mechanism-Based Type Determination
1365
+
1366
+ Entity type is defined by the cryptographic linkage that connects an account to the chain of trust:
1367
+
1368
+ | Entity Type | Linkage Mechanism | Event Kind |
1369
+ |---|---|---|
1370
+ | Natural Person | Professional credential | 31000 (`type: credential`, Tier 3/4) |
1371
+ | Persona | Identity bridge (ring signature) from a Natural Person | 31000 (`type: identity-bridge`) |
1372
+ | Personal Agent | Delegation event from a Natural Person | 31000 (`type: delegation`) |
1373
+ | Unlinked Personal Agent | Delegation event from a Persona | 31000 (`type: delegation`) |
1374
+ | Juridical Person | Professional credential + multi-sig attestation | 31000 (`type: credential`) |
1375
+ | Juridical Persona | Identity bridge (ring signature) from a Juridical Person | 31000 (`type: identity-bridge`) |
1376
+ | Organised Agent | Delegation event from a Juridical Person | 31000 (`type: delegation`) |
1377
+ | Unlinked Organised Agent | Delegation event from a Juridical Persona | 31000 (`type: delegation`) |
1378
+ | Unlinked Agent | None | — |
1379
+
1380
+ ### 17.5 Credential Tag
1381
+
1382
+ The existing credential attestation (kind 31000) gains a new tag:
1383
+
1384
+ ```jsonc
1385
+ ["entity-type", "<type_code>"]
1386
+ ```
1387
+
1388
+ Where `<type_code>` is one of: `natural_person`, `persona`, `personal_agent`, `unlinked_personal_agent`, `juridical_person`, `juridical_persona`, `organised_agent`, `unlinked_organised_agent`, `unlinked_agent`.
1389
+
1390
+ This tag is derived from the verification mechanism used but is included explicitly for relay and client queryability.
1391
+
1392
+ ### 17.6 Agent Delegation Event (Kind 31000, `type: delegation`)
1393
+
1394
+ A replaceable event published by an account owner to delegate authority to an agent (bot).
1395
+
1396
+ ```jsonc
1397
+ {
1398
+ "kind": 31000,
1399
+ "pubkey": "<owner_pubkey>",
1400
+ "tags": [
1401
+ ["d", "<unique_delegation_id>"],
1402
+ ["type", "delegation"], // attestation type
1403
+ ["p", "<agent_pubkey>"], // the bot/agent being delegated
1404
+ ["entity-type", "<agent_type>"], // personal_agent, unlinked_personal_agent,
1405
+ // organised_agent, unlinked_organised_agent
1406
+ ["agent-type", "<type>"], // optional: "ai", "human", or "device"
1407
+ ["expires", "<unix_timestamp>"], // optional: delegation expiry
1408
+ ["algo", "secp256k1"], // cryptographic algorithm (§9.5)
1409
+ ["L", "signet"],
1410
+ ["l", "delegation", "signet"]
1411
+ ],
1412
+ "content": ""
1413
+ }
1414
+ ```
1415
+
1416
+ **Delegation constraints:**
1417
+
1418
+ - A Natural Person may delegate → `personal_agent`
1419
+ - A Persona may delegate → `unlinked_personal_agent`
1420
+ - A Juridical Person may delegate → `organised_agent`
1421
+ - A Juridical Persona may delegate → `unlinked_organised_agent`
1422
+
1423
+ Any other owner→agent type combination is invalid and MUST be rejected by clients and relays.
1424
+
1425
+ **Agent type tag (optional):**
1426
+
1427
+ The `["agent-type", "<type>"]` tag distinguishes what kind of agent is being delegated:
1428
+
1429
+ | Value | Meaning | Example |
1430
+ |---|---|---|
1431
+ | `ai` | An AI/software agent acting on behalf of the owner | Personal AI assistant, DVM operator, moderation bot |
1432
+ | `human` | A human delegate (not an AI) | Guardian, employee, temporary access |
1433
+ | `device` | A physical device (robot, IoT, telepresence) | Humanoid robot, smart lock, drone |
1434
+
1435
+ If omitted, clients SHOULD assume `human` for backwards compatibility. The tag is informational — it helps clients display appropriate trust context (e.g., "This is an AI agent operated by a verified person" vs "This is a human delegate").
1436
+
1437
+ **Revocation:** Delegations are revoked using a kind 31000 revocation attestation (with `type: revocation`), with the `["d", "<agent_pubkey>"]` tag pointing to the agent being revoked.
1438
+
1439
+ ### 17.7 Juridical Person Verification
1440
+
1441
+ A Juridical Person (organisation) requires dual verification:
1442
+
1443
+ 1. **Professional verification:** A Tier 3+ professional verifies the organisation's legal registration documents (articles of incorporation, registration certificate, etc.) and issues a credential attestation (kind 31000 with `type: credential`).
1444
+ 2. **Multi-sig attestation:** N-of-M verified Natural Persons co-sign a credential attesting they represent the organisation (e.g., 3 of 5 board members). Each co-signer must themselves be a verified Natural Person.
1445
+
1446
+ Both proofs must be present for an account to achieve Juridical Person status.
1447
+
1448
+ #### 17.7.1 Domain Proof via `.well-known/signet.json`
1449
+
1450
+ An institution MAY publish its Signet identity and staff roster via `https://<domain>/.well-known/signet.json`. This extends the schema defined in §27.1 (Cold-Call Verification) with fields for entity type, registry cross-referencing, and staff pubkeys.
1451
+
1452
+ ```json
1453
+ {
1454
+ "version": 2,
1455
+ "name": "Baker & Co Solicitors",
1456
+ "entity": "juridical_person",
1457
+ "registry": {
1458
+ "authority": "sra",
1459
+ "id": "654321",
1460
+ "url": "https://www.sra.org.uk/consumers/register/organisation/?sraNumber=654321"
1461
+ },
1462
+ "pubkeys": [
1463
+ {
1464
+ "id": "firm-key-2026",
1465
+ "pubkey": "<64-char hex secp256k1 x-only pubkey>",
1466
+ "label": "Firm Verification Key",
1467
+ "created": "2026-01-15T00:00:00Z"
1468
+ }
1469
+ ],
1470
+ "staff": [
1471
+ {
1472
+ "pubkey": "<64-char hex>",
1473
+ "name": "Jane Smith",
1474
+ "role": "solicitor",
1475
+ "registry": { "authority": "sra", "id": "123456" }
1476
+ },
1477
+ {
1478
+ "pubkey": "<64-char hex>",
1479
+ "name": "John Davies",
1480
+ "role": "solicitor",
1481
+ "registry": { "authority": "sra", "id": "789012" }
1482
+ }
1483
+ ],
1484
+ "relay": "wss://relay.example.com",
1485
+ "policy": {
1486
+ "rotation": "annual",
1487
+ "contact": "compliance@bakerco.co.uk"
1488
+ }
1489
+ }
1490
+ ```
1491
+
1492
+ **Version 2 fields (all optional — version 1 documents remain valid):**
1493
+
1494
+ | Field | Type | Description |
1495
+ |---|---|---|
1496
+ | `entity` | string | Entity type code: `juridical_person` or `juridical_persona` |
1497
+ | `registry` | object | Regulatory body and registration ID for the institution |
1498
+ | `registry.authority` | string | Registry identifier: `sra`, `gmc`, `gdc`, `arb`, `ofsted`, `companies-house`, etc. |
1499
+ | `registry.id` | string | The institution's registration ID on that registry |
1500
+ | `registry.url` | string | Optional: direct URL to the institution's public registry entry |
1501
+ | `staff` | array | Array of verified individuals at this institution |
1502
+ | `staff[].pubkey` | string | 64-char hex secp256k1 x-only pubkey of the staff member |
1503
+ | `staff[].name` | string | Display name (for human cross-referencing) |
1504
+ | `staff[].role` | string | Role at the institution (e.g., `solicitor`, `gp`, `head-teacher`) |
1505
+ | `staff[].registry` | object | Optional: the individual's own registry entry (e.g., their personal SRA ID) |
1506
+
1507
+ **Validation rules (extending §27.1 rules):**
1508
+
1509
+ - `version` MUST be `1` or `2`. Clients MUST accept version 1 documents (which lack `entity`, `registry`, `staff`).
1510
+ - `entity`, if present, MUST be `juridical_person` or `juridical_persona`.
1511
+ - `staff`, if present, MUST be an array with at most 500 entries.
1512
+ - Each `staff[].pubkey` MUST be a 64-character lowercase hexadecimal string.
1513
+ - `registry.authority` values SHOULD use the lowercase identifiers defined in the Signet registry authority table (see §17.7.4).
1514
+ - The document MUST NOT exceed 102,400 bytes (100 KB) to accommodate large staff rosters.
1515
+
1516
+ #### 17.7.2 Juridical Person Onboarding Flow
1517
+
1518
+ The recommended onboarding flow for an institution (e.g., a law firm):
1519
+
1520
+ **Step 1: Create the institution's Signet identity.**
1521
+
1522
+ The managing partner (or designated compliance officer) generates a BIP-39 mnemonic for the institution. This mnemonic is the institution's master key. It SHOULD be:
1523
+ - Generated on a secure device (hardware wallet or air-gapped machine)
1524
+ - Backed up via Shamir Secret Sharing (e.g., 2-of-3 split across partners) using `@forgesworn/shamir-words`
1525
+ - Never stored on a general-purpose computer or cloud service
1526
+
1527
+ The mnemonic derives the institution's `juridical_person` identity via `createSignetIdentity()`.
1528
+
1529
+ **Step 2: Professional verification of the institution.**
1530
+
1531
+ A Tier 3+ verified professional (who is NOT an employee of the institution) verifies:
1532
+ - The institution's legal registration documents (e.g., Companies House certificate, SRA firm registration)
1533
+ - That the persons claiming to represent the institution match their registry records
1534
+
1535
+ The professional issues a credential attestation (kind 31000, `type: credential`, `entity-type: juridical_person`) against the institution's pubkey.
1536
+
1537
+ **Step 3: Multi-sig attestation by directors/partners.**
1538
+
1539
+ N-of-M verified Natural Persons at the institution co-sign a credential attesting they represent the organisation. For example, for a law firm with 5 equity partners, a 3-of-5 attestation. Each co-signer must themselves be a verified Natural Person (Tier 3+).
1540
+
1541
+ **Step 4: Publish `.well-known/signet.json`.**
1542
+
1543
+ The institution publishes the domain proof file on its website. This anchors the institution's pubkey to its domain. For institutions on restricted domains (`.sch.uk`, `.nhs.uk`, `.ac.uk`, `.gov.uk`), the domain itself provides infrastructure-level anti-Sybil — the domain registrar has already verified the institution's legitimacy.
1544
+
1545
+ **Step 5: Staff verification.**
1546
+
1547
+ The institution (via its `juridical_person` identity) issues credentials to individual staff members. Each staff credential:
1548
+ - Is issued by the institution's pubkey (not by the individual professional's own verification chain)
1549
+ - Includes the `entity-type: natural_person` tag on the staff member's pubkey
1550
+ - Includes a `["delegator", "<institution_pubkey>"]` tag linking the credential to the institution
1551
+ - Can be cross-referenced against the staff member's individual registry entry (e.g., their personal SRA ID)
1552
+
1553
+ This means a solicitor at the firm has TWO credential paths:
1554
+ 1. **Via the institution:** SRA register → firm's domain → `.well-known/signet.json` → firm credential → individual
1555
+ 2. **Via personal verification:** Another verified professional vouches for them in person
1556
+
1557
+ Either path is valid. Both together are stronger.
1558
+
1559
+ **Step 6: Staff are listed in `.well-known/signet.json`.**
1560
+
1561
+ The institution adds each verified staff member's pubkey to the `staff` array. This creates a single machine-readable file that lists every verified person at the institution, cross-referenceable against the relevant professional register.
1562
+
1563
+ #### 17.7.3 Staff Verification by the Institution
1564
+
1565
+ When an institution issues a credential to a staff member, the credential event includes tags linking it to the institution:
1566
+
1567
+ ```jsonc
1568
+ {
1569
+ "kind": 31000,
1570
+ "pubkey": "<institution_pubkey>",
1571
+ "tags": [
1572
+ ["d", "<unique_credential_id>"],
1573
+ ["type", "credential"],
1574
+ ["p", "<staff_member_pubkey>"],
1575
+ ["entity-type", "natural_person"],
1576
+ ["delegator", "<institution_pubkey>"],
1577
+ ["delegator-entity", "juridical_person"],
1578
+ ["registry", "sra", "<staff_member_sra_id>"],
1579
+ ["algo", "secp256k1"],
1580
+ ["L", "signet"],
1581
+ ["l", "credential", "signet"]
1582
+ ],
1583
+ "content": ""
1584
+ }
1585
+ ```
1586
+
1587
+ The `["registry", "<authority>", "<id>"]` tag enables automated cross-referencing. A verifying client can:
1588
+
1589
+ 1. Find the credential issued by `<institution_pubkey>`
1590
+ 2. Fetch `https://<institution-domain>/.well-known/signet.json`
1591
+ 3. Confirm `<institution_pubkey>` matches a pubkey in the file
1592
+ 4. Confirm `<staff_member_pubkey>` appears in the `staff` array
1593
+ 5. Look up the `registry` tag value against the relevant professional register (e.g., SRA API)
1594
+ 6. Confirm the named person at the named registry ID works at the named firm
1595
+
1596
+ All six checks must pass for full verification. Steps 1–4 are automatable. Step 5 requires registry integration (API or web scrape). Step 6 is a human-readable cross-check.
1597
+
1598
+ #### 17.7.4 Registry Authority Identifiers
1599
+
1600
+ The protocol defines the following registry authority identifiers for use in `registry.authority` fields and `["registry"]` tags:
1601
+
1602
+ | Identifier | Registry | Country | Profession |
1603
+ |---|---|---|---|
1604
+ | `sra` | Solicitors Regulation Authority | UK | Solicitors |
1605
+ | `bsb` | Bar Standards Board | UK | Barristers |
1606
+ | `gmc` | General Medical Council | UK | Doctors/GPs |
1607
+ | `gdc` | General Dental Council | UK | Dentists |
1608
+ | `gphc` | General Pharmaceutical Council | UK | Pharmacists |
1609
+ | `nmc` | Nursing and Midwifery Council | UK | Nurses, midwives |
1610
+ | `goc` | General Optical Council | UK | Opticians, optometrists |
1611
+ | `hcpc` | Health and Care Professions Council | UK | Physios, paramedics, psychologists, etc. |
1612
+ | `swe` | Social Work England | UK (England) | Social workers |
1613
+ | `arb` | Architects Registration Board | UK | Architects |
1614
+ | `rcvs` | Royal College of Veterinary Surgeons | UK | Veterinarians |
1615
+ | `icaew` | Institute of Chartered Accountants | UK | Chartered accountants |
1616
+ | `acca` | Assoc. of Chartered Certified Accountants | UK | Chartered certified accountants |
1617
+ | `rics` | Royal Institution of Chartered Surveyors | UK | Chartered surveyors |
1618
+ | `engc` | Engineering Council | UK | Chartered engineers |
1619
+ | `gtcs` | General Teaching Council for Scotland | UK (Scotland) | Teachers |
1620
+ | `ofsted` | Office for Standards in Education | UK (England) | Schools, childminders, nurseries |
1621
+ | `companies-house` | Companies House | UK | Companies, LLPs |
1622
+ | `faculty-office` | Faculty Office of the Archbishop of Canterbury | UK | Notaries public |
1623
+
1624
+ This table is non-exhaustive. Implementations SHOULD accept any `registry.authority` value — unknown authorities are not invalid, merely unverifiable by that particular client. International registries may be added by any implementation.
1625
+
1626
+ ### 17.8 Application Label Mapping
1627
+
1628
+ Client applications SHOULD map protocol entity types to user-friendly labels:
1629
+
1630
+ | Protocol Term | Recommended App Label |
1631
+ |---|---|
1632
+ | Natural Person | Person |
1633
+ | Persona | Alias |
1634
+ | Personal Agent | Personal Agent |
1635
+ | Unlinked Personal Agent | Unlinked Personal Agent |
1636
+ | Juridical Person | Organisation |
1637
+ | Juridical Persona | Org Alias |
1638
+ | Organised Agent | Organised Agent |
1639
+ | Unlinked Organised Agent | Unlinked Org Agent |
1640
+ | Unlinked Agent | Unlinked Agent |
1641
+
1642
+ ### 17.9 Dynamic Mode Signaling
1643
+
1644
+ A single account (particularly a physical device such as a humanoid robot or telepresence system) may switch between entity types depending on who or what is in control at a given moment. Events published by such accounts SHOULD include a mode tag:
1645
+
1646
+ ```jsonc
1647
+ ["mode", "<mode>"]
1648
+ ```
1649
+
1650
+ Where `<mode>` is one of:
1651
+
1652
+ | Mode | Meaning |
1653
+ |---|---|
1654
+ | `teleoperated` | A verified person is in direct real-time control (entity acts as Persona) |
1655
+ | `autonomous` | AI/software is acting on behalf of the owner (entity acts as Agent) |
1656
+ | `assisted` | A verified person is in control with AI assistance (entity acts as Persona) |
1657
+
1658
+ **Example:** A paraplegic Natural Person controls a humanoid robot via a brain-computer interface. When the person is directly controlling the robot, it publishes events with `["mode", "teleoperated"]` and operates as a Persona. When the person steps away and onboard AI takes over, it publishes with `["mode", "autonomous"]` and operates as a Personal Agent. This allows others interacting with the robot to know whether they are communicating with the person or their AI.
1659
+
1660
+ This pattern applies to any remote-operated system: telepresence robots, drone operators, remote surgery rigs, VR avatars — any case where a verified person may or may not be in direct control at a given moment.
1661
+
1662
+ ### 17.10 Relay Policy Extensions
1663
+
1664
+ Community verification policies (kind 30078) may include entity type requirements:
1665
+
1666
+ ```jsonc
1667
+ ["allowed-entity-types", "natural_person,persona,juridical_person"]
1668
+ ```
1669
+
1670
+ Relays MAY filter events by entity type. For example, a child-safety relay might only accept events from Natural Persons and Personas (verified humans and their aliases), rejecting Unlinked Agents and unverified bots.
1671
+
1672
+ ### 17.11 Future Extension: Synthetic Person
1673
+
1674
+ The current taxonomy covers entities that are human, human-controlled, human-organised, or unverified. It does not cover fully autonomous beings (e.g., a sentient AI or truly independent robot) that act on their own behalf rather than on behalf of a human or organisation.
1675
+
1676
+ If such entities require their own legal or social standing, a new root category — **Synthetic Person** — may be added alongside Natural Person and Juridical Person, with its own alias and agent subtypes. The taxonomy is designed to accommodate this without breaking changes.
1677
+
1678
+ ---
1679
+
1680
+ ## 18. Adversarial Resilience
1681
+
1682
+ ### 18.1 Overview
1683
+
1684
+ Any identity protocol that achieves meaningful adoption will be evaluated — and potentially co-opted — by adversarial actors, including nation-states. A protocol that works only under cooperative assumptions is not a protocol; it is an invitation to abuse. Signet MUST be designed, evaluated, and maintained under adversarial assumptions, including the scenario where a government mandates Signet ID and then attempts to weaponise it.
1685
+
1686
+ This section defines the threat model, compares Signet's position to the current state and its trajectory, and establishes formal requirements that the protocol must satisfy.
1687
+
1688
+ ### 18.2 Threat Scenarios
1689
+
1690
+ The following table compares ten adversarial scenarios across three contexts: the current state (2026), the trajectory if centralised digital identity continues unchecked, and the position with Signet.
1691
+
1692
+ | Scenario | Current State (2026) | Trajectory Without Decentralised Alternative | With Signet |
1693
+ |---|---|---|---|
1694
+ | **Identity revocation** | Multiple ID forms exist. Losing one doesn't kill identity. | Centralised digital ID (EU eIDAS, UK DIATF) creates single points of failure. One revocation = locked out. India's Aadhaar locks people out of food rations. | Multiple independent credential issuers. No single revocation kills identity. Government revokes their attestation, not identity itself. |
1695
+ | **Anonymous participation** | Possible via cash, physical post, in-person. Diminishing with CCTV, card-only payments, phone tracking. | Cash elimination. Real-name platform verification (EU DSA, UK OSA). Anonymous speech criminalised or de-platformed. Trajectory: zero anonymity. | Ring signatures provide mathematical anonymity. Persona accounts unlinkable to Natural Person. Anonymous but verified participation is a protocol feature, not a loophole. |
1696
+ | **Backdoored identity** | Government holds biometrics. Centralised databases. Citizen doesn't control infrastructure. | Mandatory government wallet apps. Closed-source, government-audited. Apple/Google as gatekeepers. Must use their app to have identity. | Open-source clients. Keys generated offline. Open spec anyone can implement. No mandated app. |
1697
+ | **Retrospective de-anonymisation** | ISP logging (UK IPA). CCTV retained. Much activity still unrecorded. | AI retroactive analysis of CCTV, social media, location, payments. "Reconstruct your 2025" becomes routine. Facial recognition on stored footage. | Risk exists (quantum). Post-quantum crypto migration is plannable. Analogue world has NO defence against retrospective AI analysis. |
1698
+ | **Mass surveillance** | GCHQ/NSA bulk collection. Smart city sensors. Mobile tracking. Mostly passive. | Real-time AI monitoring. IoT everywhere. China-model normalised as "public safety." Active, not passive. | Relay diversity across jurisdictions. Encrypted connections. Signet words work offline. Can't surveil what doesn't touch your infrastructure. |
1699
+ | **Statistical de-anonymisation** | Browser fingerprinting, ad IDs, metadata analysis already de-anonymise routinely. | AI correlation attacks improve exponentially. Pseudonymity provides zero real protection. | Ring signatures stronger than pseudonymity — provable unlinkability. Larger rings = stronger guarantees. |
1700
+ | **Social graph mapping** | Social media, phone contacts, email, payments reveal relationships. Government can request with warrants. | AI real-time social graph analysis. Cross-platform graph merging. No relationship private. | Persona-based connections unlinkable to Natural Person. Government key and social key cryptographically separated. |
1701
+ | **Family structure exploitation** | Birth certs, school records, tax returns link families. Government knows family structure. | Centralised child identity systems. Family graphs cross-linked across all services. | ZKP proves "parent has child aged 8-12" without revealing which child, which school, any detail. |
1702
+ | **Verifier coercion** | Government can pressure professionals via licensing. Professionals have some legal protections. | Professional independence eroded. Licensing bodies politicised. "Comply or lose licence" routine. | Multiple verifiers across jurisdictions and professions. No single jurisdiction's coercion captures entire verification chain. |
1703
+ | **Election manipulation** | Paper ballots work reasonably for secrecy. Postal voting vulnerable. No crypto guarantees. | Digital voting without proper crypto. Centralised "trust us" counting. Convenience over security. | Linkable ring signatures for ballot secrecy. Re-voting for coercion resistance. Verifiable tallying anyone can audit. |
1704
+
1705
+ ### 18.3 Defence Principles
1706
+
1707
+ Every defence follows the same meta-principle: **decentralisation prevents single-entity control.**
1708
+
1709
+ 1. **Multiple credential issuers** — no single entity's revocation kills your identity
1710
+ 2. **Open-source clients** — no mandated app can be secretly backdoored
1711
+ 3. **Relay diversity** — no single jurisdiction controls the communication layer
1712
+ 4. **Large ring signatures** — statistical de-anonymisation requires infeasible computation
1713
+ 5. **Post-quantum migration path** — build crypto agility into the spec now
1714
+ 6. **Multiple election authorities** — no single signer controls ballot issuance
1715
+ 7. **Cross-jurisdiction verifiers** — professionals in different countries provide independent trust paths
1716
+ 8. **Voluntary credential presentation** — the protocol MUST NOT enable compulsory ID through the back door
1717
+
1718
+ ### 18.4 Formal Adversarial Requirement
1719
+
1720
+ The protocol MUST ensure that no single entity — including a nation-state — can unilaterally:
1721
+
1722
+ - **Revoke a person's identity** — only their own attestation, not the keypair or credentials from other issuers
1723
+ - **De-anonymise a Persona** — without possession of the private key
1724
+ - **Coerce a vote** — without detection by the voter or audit trail
1725
+ - **Surveil all activity** — relay diversity defeats centralised monitoring
1726
+ - **Weaponise credentials as social credit** — multiple independent issuers prevent any single issuer from gatekeeping participation
1727
+
1728
+ These properties are non-negotiable. Any proposed protocol change that weakens any of these guarantees MUST be rejected unless it provides an equivalent or stronger guarantee through a different mechanism.
1729
+
1730
+ ---
1731
+
1732
+ ## 19. Civic Identity
1733
+
1734
+ ### 19.1 Government as Verifier
1735
+
1736
+ Governments are simply another class of verifier in the Signet model. A government issues kind 31000 credential attestations to citizens, just as a professional verifier issues credentials to individuals. The critical difference from traditional national ID:
1737
+
1738
+ | Aspect | Traditional National ID | Signet ID |
1739
+ |---|---|---|
1740
+ | Who generates the identity | Government issues it | Citizen generates keypair |
1741
+ | Who holds the master record | Government database | Citizen holds private key |
1742
+ | What government stores | Name, DOB, address, photo, biometrics | Public key + attestation |
1743
+ | Single point of failure | Government database breach = mass identity theft | No central database to breach |
1744
+ | Revocation power | Government can cancel your identity | Government can revoke their attestation; your key still works with other verifiers |
1745
+ | Surveillance capability | Full — they hold all your data | Limited — they hold a public key |
1746
+
1747
+ No new event kinds are required. Governments use kind 31000 for credential issuance (`type: credential`), revocation (`type: revocation`), and identity bridges (`type: identity-bridge`) where applicable, plus kind 30078 for policies.
1748
+
1749
+ ### 19.2 Verification Flow
1750
+
1751
+ Citizen verification follows a six-step process using existing protocol mechanisms:
1752
+
1753
+ 1. **Key generation** — Citizen generates a Nostr keypair using a 12-word BIP-39 mnemonic (via the nsec-tree `fromMnemonic()` derivation path)
1754
+ 2. **In-person appearance** — Citizen visits a government office (analogous to passport issuance)
1755
+ 3. **Document verification** — Government official verifies identity documents in person
1756
+ 4. **Credential issuance** — Government issues a credential attestation (kind 31000 with `type: credential`) to the citizen's pubkey: "This pubkey belongs to a verified citizen"
1757
+ 5. **Connection establishment** — Citizen and government official establish a verified connection (QR exchange, shared secret, or Signet words)
1758
+ 6. **Ongoing verification** — For future interactions, either party can verify the other using "Signet me" time-based word verification
1759
+
1760
+ ### 19.3 Good Standing Credentials
1761
+
1762
+ A government may issue a "good standing" credential — a kind 31000 credential attestation (with `type: credential`) that indicates the citizen has no outstanding warrants or court orders requiring action.
1763
+
1764
+ **Revocation as warrant mechanism:**
1765
+ - When a court issues a warrant, the good standing credential is revoked via a kind 31000 revocation attestation (with `type: revocation`)
1766
+ - The citizen's ZKP can prove non-membership in the revocation set (i.e., "I am not on any warrant list")
1767
+ - Ring signatures anonymise which specific credential is being proven
1768
+ - The credential can be re-issued when the warrant is resolved
1769
+
1770
+ **Privacy guarantee:** The revocation set is public (as all kind 31000 revocation attestations are), but ring signatures prevent observers from linking a specific proof of good standing to a specific citizen.
1771
+
1772
+ ### 19.4 Privacy-Preserving Police Interaction
1773
+
1774
+ **Current process:**
1775
+ 1. Police stop a person
1776
+ 2. Ask for name
1777
+ 3. Run name through Police National Computer / NCIC
1778
+ 4. Check for warrants
1779
+ 5. If clear, person goes — but name, location, and time are all logged
1780
+
1781
+ **Signet process:**
1782
+ 1. Police stop a person
1783
+ 2. Ask to verify status
1784
+ 3. Person's device presents a ZKP: "I hold a valid, non-revoked citizen credential"
1785
+ 4. Officer's device verifies the proof and checks revocation status
1786
+ 5. If clear, person goes — **no identity revealed**
1787
+
1788
+ The officer learns exactly one fact: this person holds a valid, non-revoked citizen credential.
1789
+
1790
+ **Critical constraint:** Presentation of a Signet credential MUST be voluntary. Refusal to present a credential MUST NOT be grounds for detention, search, or further action. Without this constraint, Signet becomes compulsory ID through the back door. This requirement MUST be enshrined in enabling legislation (see §19.6).
1791
+
1792
+ ### 19.5 Separation of Official and Private Identity
1793
+
1794
+ Citizens maintain strict separation between their government-registered identity and their private life:
1795
+
1796
+ ```
1797
+ Citizen's registered pubkey (Natural Person)
1798
+ │ Used ONLY for government interactions:
1799
+ │ taxes, official correspondence, warrant checks
1800
+ │
1801
+ └──► Persona accounts (anonymous aliases)
1802
+ │ Used for private life:
1803
+ │ social media, communities, personal expression
1804
+ │ Ring signature proves "I am a real citizen"
1805
+ │ without revealing which one
1806
+ │
1807
+ └──► Unlinked Personal Agents
1808
+ Bots/services under anonymous identity
1809
+ ```
1810
+
1811
+ The government knows the citizen's registered pubkey. They cannot link it to any Persona account without breaking the ring signature — which is computationally infeasible. This separation is enforced by cryptography, not by policy.
1812
+
1813
+ ### 19.6 Legal Framework Requirements
1814
+
1815
+ For civic identity to function as described, enabling legislation MUST ensure:
1816
+
1817
+ 1. **Voluntary presentation** — no person may be compelled to present a Signet credential outside of contexts where identification is already legally required (e.g., border control, court proceedings)
1818
+ 2. **Refusal without consequence** — refusal to present a credential in a voluntary context must not be treated as grounds for suspicion, detention, or any adverse action
1819
+ 3. **Keypair sovereignty** — the citizen's private key is their property; government may not demand access to it
1820
+ 4. **Credential plurality** — citizens may hold credentials from multiple issuers; no single government credential may be made a prerequisite for participation in civil society
1821
+ 5. **Algorithmic audit** — any government systems that process Signet credentials must be subject to independent audit
1822
+ 6. **Sunset and review** — civic identity legislation must include mandatory review periods to assess whether the system is being used as intended
1823
+
1824
+ ---
1825
+
1826
+ ## 20. Two-Credential Verification
1827
+
1828
+ ### 20.1 Design Principle
1829
+
1830
+ Anonymity is a first-class design goal, not an afterthought. Every person verified through Signet receives **two** credentials on **two** separate keypairs:
1831
+
1832
+ - **Keypair A (Natural Person):** Real identity — name, nationality, document hash, nullifier
1833
+ - **Keypair B (Persona):** Anonymous identity — inherits only the age-range proof and guardian tags (if child)
1834
+
1835
+ The professional verifier sees both keypairs and issues both credentials in a single ceremony. The link between keypairs is known only to the subject and the verifier (protected by professional confidentiality — solicitor-client privilege, notary secrecy, medical confidentiality).
1836
+
1837
+ ### 20.2 The Ceremony
1838
+
1839
+ The two-credential ceremony follows these steps:
1840
+
1841
+ 1. Subject presents two Nostr pubkeys (keypair A and keypair B) to the verifier
1842
+ 2. Subject presents identity documents (passport, national ID, birth certificate)
1843
+ 3. Verifier examines documents and confirms identity of the person present
1844
+ 4. A Merkle tree is built from verified attributes (name, nationality, document type, DOB, nullifier)
1845
+ 5. Verifier computes nullifier using length-prefixed encoding (see §20.7)
1846
+ 6. Verifier generates Pedersen range proof age-range proof from date of birth
1847
+ 7. Verifier issues Natural Person credential (keypair A) with: entity-type, merkle-root, nullifier, age-range, guardian tags (if child)
1848
+ 8. Verifier issues Persona credential (keypair B) with: entity-type=persona, age-range (same proof), guardian tags (if child), NO nullifier, NO merkle-root
1849
+
1850
+ ### 20.3 On-Chain vs Private Data
1851
+
1852
+ | Data | On-chain (public) | Private (Merkle leaf only) |
1853
+ |------|-------------------|---------------------------|
1854
+ | Entity type | Yes | — |
1855
+ | Age range (e.g., "18+") | Yes (ZKP) | — |
1856
+ | Merkle root | Yes (NP only) | — |
1857
+ | Nullifier hash | Yes (NP only) | — |
1858
+ | Guardian pubkey(s) | Yes (if child) | — |
1859
+ | Full name | — | Yes |
1860
+ | Nationality | — | Yes |
1861
+ | Date of birth | — | Yes |
1862
+ | Document type | — | Yes |
1863
+ | Document number | — | Yes (Merkle leaf, for selective disclosure) |
1864
+ | Document expiry | — | Yes (Merkle leaf, for consumer-side validity checks) |
1865
+ | Photo hash | — | Yes (Merkle leaf, SHA-256 of verified photo) |
1866
+
1867
+ **Credential expiry vs document expiry:** The `expires` tag on the credential attestation (kind 31000 with `type: credential`) is the credential's validity period — when the credential itself stops being accepted. The `documentExpiry` Merkle leaf is the underlying document's expiry date — when the passport or licence expires. These are different: a credential might expire in 2 years but the passport doesn't expire for 10. Clients should check both.
1868
+
1869
+ ### 20.4 Date of Birth and Age-Range Proofs
1870
+
1871
+ All tiers carry age-range proofs when issued by a professional:
1872
+
1873
+ - **Tier 1 (self-declared):** No age-range proof (self-declaration is not verification)
1874
+ - **Tier 2 (peer-vouched):** No age-range proof (peers cannot verify DOB)
1875
+ - **Tier 3 (professional, adult):** Age-range proof "18+" from verified DOB
1876
+ - **Tier 4 (professional, adult+child):** Age-range proof with specific range (e.g., "8-12", "13-17")
1877
+
1878
+ Age ranges for children:
1879
+
1880
+ | Age | Range tag | Tier | Scope |
1881
+ |-----|-----------|------|-------|
1882
+ | 0-3 | `0-3` | 4 | adult+child |
1883
+ | 4-7 | `4-7` | 4 | adult+child |
1884
+ | 8-12 | `8-12` | 4 | adult+child |
1885
+ | 13-17 | `13-17` | 4 | adult+child |
1886
+ | 18+ | `18+` | 3 | adult |
1887
+
1888
+ The DOB is NEVER published on-chain. Only the zero-knowledge age-range proof appears. The Pedersen range proof proves "this person's age falls within [min, max]" without revealing the exact age or DOB.
1889
+
1890
+ ### 20.5 Merkle-Bound Name Verification
1891
+
1892
+ The Natural Person credential includes a `merkle-root` tag. The Merkle tree contains verified attributes as leaves:
1893
+
1894
+ ```
1895
+ Merkle Root
1896
+ ├── H("dateOfBirth:1990-05-15")
1897
+ ├── H("documentExpiry:2030-05-15")
1898
+ ├── H("documentNumber:123456789")
1899
+ ├── H("documentType:passport")
1900
+ ├── H("name:Alice Smith")
1901
+ ├── H("nationality:GB")
1902
+ ├── H("nullifier:<hash>")
1903
+ └── H("photoHash:<sha256>")
1904
+ ```
1905
+
1906
+ **Note:** The leaves shown above are an example. The leaf set is variable per credential — different document types may include different attributes. The tree construction (RFC 6962 domain separation) and proof format are identical regardless of the number of leaves.
1907
+
1908
+ Selective disclosure: The subject can reveal any attribute by providing the leaf value and its Merkle proof (sibling hashes). The verifier (or any party) can verify the proof against the published Merkle root without seeing the other attributes.
1909
+
1910
+ Use cases for selective disclosure:
1911
+ - Prove name to a bank without revealing nationality
1912
+ - Prove nationality for a community policy without revealing name
1913
+ - Prove document type for a regulatory check without revealing anything else
1914
+
1915
+ ### 20.6 Entity Type as Immutable Differentiator
1916
+
1917
+ The `entity-type` tag is set at credential issuance and cannot be changed without a new credential:
1918
+
1919
+ | Entity type | Display | Can hold nullifier? | Can hold merkle-root? |
1920
+ |-------------|---------|--------------------|-----------------------|
1921
+ | natural_person | Person | Yes | Yes |
1922
+ | persona | Alias | No | No |
1923
+
1924
+ Clients MUST display the entity type. A Persona MUST NOT be displayed as a verified person. The entity type is the primary signal for "is this a real identity or an alias?"
1925
+
1926
+ ### 20.7 Document-Based Nullifiers
1927
+
1928
+ Nullifiers prevent duplicate identity creation. The nullifier is computed using length-prefixed encoding to prevent field-boundary collisions:
1929
+
1930
+ ```
1931
+ nullifier = SHA-256(
1932
+ uint16be(len(document_type)) || document_type ||
1933
+ uint16be(len(country_code)) || country_code ||
1934
+ uint16be(len(document_number)) || document_number ||
1935
+ uint16be(len(domain_tag)) || domain_tag
1936
+ )
1937
+
1938
+ where domain_tag = "signet-nullifier-v2"
1939
+ ```
1940
+
1941
+ Each field is prefixed with its UTF-8 byte length as a 2-byte big-endian unsigned integer. This prevents ambiguity where field values containing delimiters could produce colliding nullifiers (e.g., docType="A||B" + country="C" must not collide with docType="A" + country="B||C").
1942
+
1943
+ Properties:
1944
+ - **Deterministic:** Same document always produces the same nullifier
1945
+ - **One-way:** Cannot recover document details from the nullifier
1946
+ - **Collision-resistant:** Different documents produce different nullifiers; length-prefixed encoding prevents field-boundary ambiguity
1947
+ - **Cross-verifier consistent:** Any verifier with the same document computes the same nullifier
1948
+
1949
+ When a verifier encounters a nullifier that already exists on a relay, this indicates either:
1950
+ 1. The same person is getting re-verified (legitimate — supersede the old credential)
1951
+ 2. Two different people presented the same document (fraud — flag for investigation)
1952
+
1953
+ ### 20.8 Multi-Document Nullifier Families
1954
+
1955
+ When a subject presents multiple identity documents during a verification ceremony (e.g., passport AND driving licence AND national ID), the verifier SHOULD compute nullifiers for ALL documents, not just the primary. These form a **nullifier family** — a set of nullifiers that all belong to the same person.
1956
+
1957
+ ```
1958
+ nullifier_passport = SHA-256(LP("passport") || LP("GB") || LP("123456789") || LP("signet-nullifier-v2"))
1959
+ nullifier_licence = SHA-256(LP("driving_licence") || LP("GB") || LP("SMITH901150J99XX") || LP("signet-nullifier-v2"))
1960
+ nullifier_national_id = SHA-256(LP("national_id") || LP("GB") || LP("AB123456C") || LP("signet-nullifier-v2"))
1961
+
1962
+ where LP(s) = uint16be(len(s)) || s
1963
+ ```
1964
+
1965
+ The credential event includes:
1966
+ - `["nullifier", "<primary_nullifier>"]` — the primary nullifier (backwards compatible)
1967
+ - `["nullifier-family", "<nullifier>", "<document_type>"]` — one tag per document in the family
1968
+
1969
+ **Collision detection:** When checking for duplicates, clients and relays MUST check ALL nullifiers in the incoming family against ALL nullifiers (both `nullifier` and `nullifier-family` tags) in existing credentials. A collision with ANY nullifier in ANY family indicates the same person has been verified before.
1970
+
1971
+ This significantly strengthens duplicate prevention: a person cannot circumvent the system by presenting a different document to a different verifier, because both documents' nullifiers are recorded and cross-checked.
1972
+
1973
+ ### 20.9 Nullifier Weaknesses and Mitigations
1974
+
1975
+ | Weakness | Mitigation |
1976
+ |----------|------------|
1977
+ | Document shared between family members | Nullifier collision detected; professional investigates |
1978
+ | Document number guessable (sequential) | Hash includes document type + country; brute-force requires knowing all three components |
1979
+ | Multiple documents (passport + national ID) | Multi-document nullifier families (§20.8) — each document produces a nullifier, all are cross-checked |
1980
+ | Country changes document format | Domain tag version ("signet-nullifier-v2") allows migration to new formula |
1981
+ | Verifier collusion (issue without real document) | Anti-corruption framework (§7) applies; nullifier without document is detectable via anomaly patterns |
1982
+ | eIDAS wallet credentials | When available, the eIDAS unique person identifier can serve as an additional nullifier source for EU citizens (§20.10) |
1983
+
1984
+ ### 20.10 eIDAS 2.0 Bridge (Future)
1985
+
1986
+ EU eIDAS 2.0 mandates unique person identifiers for ~450M EU citizens by December 2026. When a subject presents an eIDAS wallet credential during a Signet verification ceremony, the verifier MAY use the eIDAS unique person identifier as an additional nullifier source:
1987
+
1988
+ ```
1989
+ nullifier_eidas = SHA-256(LP("eidas") || LP(eidas_unique_id) || LP("signet-nullifier-v2"))
1990
+
1991
+ where LP(s) = uint16be(len(s)) || s
1992
+ ```
1993
+
1994
+ Note: The eIDAS nullifier uses only two data fields (type + identifier) since there is no country code or document number; the length-prefixed encoding ensures this cannot collide with document-based nullifiers which always have three data fields.
1995
+
1996
+ This provides a de facto perfect nullifier for EU citizens, as the eIDAS identifier is government-issued, unique, and machine-verifiable. The eIDAS nullifier is included in the nullifier family alongside document-based nullifiers.
1997
+
1998
+ ### 20.11 Cross-Verification
1999
+
2000
+ When a subject presents the same document to a different verifier, the same nullifier is produced (because the nullifier is derived from the document details). The protocol distinguishes cross-verification from fraud by checking the subject's pubkey:
2001
+
2002
+ | Scenario | Nullifier | Subject pubkey | Interpretation |
2003
+ |---|---|---|---|
2004
+ | First verification | New | User's | New identity — record it |
2005
+ | Cross-verification (same doc, new verifier) | Same | Same | Independent confirmation — higher IQ contribution |
2006
+ | Document renewal (new number) | New | Same | New document — supersedes old credential |
2007
+ | Document renewal (same number) | Same | Same | Re-verification — supersedes old credential |
2008
+ | Fraud (someone else uses the document) | Same | Different | Duplicate detected — flag for investigation |
2009
+
2010
+ Cross-verification is the most valuable IQ signal because it represents independent professional confirmation of the same identity.
2011
+
2012
+ ---
2013
+
2014
+ ## 21. Credential Lifecycle
2015
+
2016
+ ### 21.1 Credential Chains
2017
+
2018
+ When a credential needs updating (name change, document renewal, tier upgrade), a new credential is issued with a `["supersedes", "<old_event_id>"]` tag. The old credential receives a `["superseded-by", "<new_event_id>"]` tag.
2019
+
2020
+ ```
2021
+ Credential v1 (original)
2022
+ ├── superseded-by: <v2_id>
2023
+ └── [still on relay, but clients show as superseded]
2024
+
2025
+ Credential v2 (current)
2026
+ ├── supersedes: <v1_id>
2027
+ └── [active, displayed by clients]
2028
+ ```
2029
+
2030
+ Rules:
2031
+ - Only a professional verifier can issue a superseding credential
2032
+ - The superseding credential MUST reference the old credential's event ID
2033
+ - Clients MUST follow the chain and display only the current (non-superseded) credential
2034
+ - The chain is append-only — superseded credentials cannot be un-superseded
2035
+
2036
+ ### 21.2 Name Changes
2037
+
2038
+ When a subject's legal name changes (marriage, divorce, deed poll, court order):
2039
+
2040
+ 1. Subject presents new legal documents to a professional verifier
2041
+ 2. Verifier builds new Merkle tree with updated name
2042
+ 3. Verifier issues new Natural Person credential with `["supersedes", "<old_id>"]`
2043
+ 4. Persona credential is UNAFFECTED (it carries no name)
2044
+
2045
+ ### 21.3 Titles and Qualifications
2046
+
2047
+ Professional titles (PhD, Dr., KC/QC, Prof.) are NOT name changes. They are separate credentials issued by awarding bodies or verified by professionals, linked to the same pubkey. The Natural Person credential reflects the legal name only.
2048
+
2049
+ ### 21.4 Children
2050
+
2051
+ #### 21.4.1 Child Credential Requirements
2052
+
2053
+ Foundational rule: child credentials MUST be sub-accounts of a verified parent or guardian.
2054
+
2055
+ The ceremony requires:
2056
+ - Parent/guardian with Tier 3+ Signet credential (mandatory)
2057
+ - Child's birth certificate or passport (DOB mandatory)
2058
+ - Professional verifies parental authority (birth certificate name match, court order if applicable)
2059
+ - Professional generates Pedersen range proof age-range proof from DOB
2060
+ - Issues Natural Person + Persona credentials, both with age-range proof and `["guardian", "<parent_pubkey>"]` tag
2061
+ - Child's real name NEVER published — only in private Merkle leaves
2062
+
2063
+ #### 21.4.2 Guardian Link
2064
+
2065
+ The `["guardian", "<parent_pubkey>"]` tag is:
2066
+ - Set by the professional verifier at issuance
2067
+ - Immutable — cannot be changed without a new credential issued by a professional
2068
+ - Multiple guardians supported (joint custody): multiple `["guardian", ...]` tags
2069
+ - Present on BOTH Natural Person and Persona credentials
2070
+
2071
+ #### 21.4.3 Child to Adult Transition
2072
+
2073
+ The transition from dependant to independent identity involves two separate decisions that may happen together or independently.
2074
+
2075
+ **Decision 1 — Remove guardian authority (credential supersession):**
2076
+
2077
+ 1. Subject visits a professional verifier with current identity documents
2078
+ 2. Verifier issues new Tier 3 credential with `["age-range", "18+"]` and `["supersedes", "<child_credential_id>"]`
2079
+ 3. New credential has NO guardian tag
2080
+ 4. Persona credential also superseded with updated age-range and no guardian tag
2081
+ 5. Guardian's delegation events revoked
2082
+
2083
+ **Decision 2 — Sever key derivation (optional key rotation):**
2084
+
2085
+ When the dependant's keys were derived from the guardian's mnemonic (e.g. via nsec-tree sub-identity derivation), the guardian can re-derive those keys indefinitely. Key rotation severs this ability:
2086
+
2087
+ 1. Subject generates a fresh, independently rooted mnemonic on their own device
2088
+ 2. New mnemonic derives new keypairs (natural-person + persona)
2089
+ 3. Old identity publishes a migration event (kind 31000, `type: migration`) linking old pubkeys to new pubkeys, signed by the old keys
2090
+ 4. New credentials issued against new pubkeys with `["supersedes", "<old_credential_id>"]`
2091
+ 5. Guardian's key server (e.g. Heartwood Pi) deletes the derived master secret
2092
+ 6. Old keys become dead — credentials superseded, delegation revoked
2093
+
2094
+ **Key rotation is optional.** The subject may choose to retain the guardian's derivation capability as a recovery mechanism. Clients MUST clearly communicate the implications:
2095
+
2096
+ > "Your guardian can still derive your private keys from their mnemonic. They could sign events as you. Choose this only if you trust them with recovery access."
2097
+
2098
+ | Guardian removed? | Keys rotated? | Result |
2099
+ |:-:|:-:|---------|
2100
+ | Yes | Yes | Fully sovereign identity — complete independence |
2101
+ | Yes | No | Independent but recoverable — guardian retains recovery capability as a safety net |
2102
+ | No | Yes | Guardian retains legal authority but cannot derive keys — used when court restricts direct key access |
2103
+ | No | No | Continuing dependant relationship (e.g. adult with permanent cognitive impairment) |
2104
+
2105
+ **Migration event format:**
2106
+
2107
+ ```json
2108
+ {
2109
+ "kind": 31000,
2110
+ "pubkey": "<old-pubkey>",
2111
+ "tags": [
2112
+ ["d", "migration:<old-pubkey>"],
2113
+ ["type", "migration"],
2114
+ ["p", "<new-pubkey>"],
2115
+ ["L", "nip-va"],
2116
+ ["l", "migration", "nip-va"]
2117
+ ],
2118
+ "content": ""
2119
+ }
2120
+ ```
2121
+
2122
+ The migration event MUST be signed by the old key. Clients encountering a migration event SHOULD:
2123
+ - Follow the `p` tag to the new pubkey
2124
+ - Display credentials on the new pubkey as continuing the old identity's trust history
2125
+ - Mark the old pubkey as migrated (not revoked — migration is a positive transition)
2126
+
2127
+ #### 21.4.3a Transfer of Guardianship
2128
+
2129
+ Guardianship may transfer due to foster care, adoption, bereavement, or court order. The protocol supports three transfer patterns:
2130
+
2131
+ **Temporary delegation (guardian retains parental responsibility):**
2132
+ - Credential layer unchanged — guardian tag stays as original guardian
2133
+ - Guardian delegates specific scopes to the temporary carer via kind 31000 `type: delegation`
2134
+ - Key derivation unchanged — original guardian retains derived keys
2135
+ - Example: temporary foster placement, grandparent caring during hospital stay
2136
+
2137
+ **Permanent transfer (parental responsibility transferred by court order):**
2138
+ - Professional issues new credential with new guardian tag (court order required as documentary evidence)
2139
+ - Old guardian's delegation revoked
2140
+ - Key rotation MUST occur — a person whose parental responsibility has been legally removed MUST NOT retain cryptographic access to the dependant's identity
2141
+ - New keys are either independently rooted (professional generates fresh mnemonic for the dependant) or derived from the new guardian's mnemonic
2142
+ - Nullifier chain links old and new identities via `["nullifier-chain", "<old_nullifier>"]`
2143
+ - Old credentials superseded; old keys become dead
2144
+
2145
+ **Bereavement:**
2146
+ - Court-appointed guardian added via superseding credential (existing §21.6 provisions)
2147
+ - If deceased guardian's key server is inaccessible, key rotation occurs by necessity
2148
+ - Nullifier chain preserves identity continuity
2149
+
2150
+ **Duplicate identity resolution:**
2151
+
2152
+ When key rotation creates a new identity, two pubkeys may temporarily claim the same person on relays. The nullifier system resolves this:
2153
+
2154
+ 1. Professional computes nullifier from the dependant's identity documents (same documents → same nullifier)
2155
+ 2. Nullifier matches the old identity
2156
+ 3. Old credential receives a revocation event from the professional
2157
+ 4. `["nullifier-chain", "<old_nullifier>"]` on the new credential links old and new
2158
+ 5. Clients follow the chain: old identity revoked → new identity active → same person confirmed
2159
+
2160
+ The old guardian cannot prevent this — revocation and new issuance are performed by a professional with legal authority (court order).
2161
+
2162
+ #### 21.4.3b Graduated Autonomy
2163
+
2164
+ Delegation scopes control what a dependant can sign without guardian approval. The guardian adjusts scopes as the dependant matures:
2165
+
2166
+ | Stage | Signing behaviour | Guardian visibility |
2167
+ |-------|-------------------|---------------------|
2168
+ | Full control | Guardian signs everything | N/A |
2169
+ | Request/approve | Dependant requests, guardian approves via NIP-46 | Real-time approval prompts |
2170
+ | Autonomous with alerts | Dependant signs autonomously | Real-time notifications |
2171
+ | Autonomous with logging | Dependant signs autonomously | Audit log only |
2172
+ | Full autonomy | No restrictions | No visibility (unless opted in) |
2173
+
2174
+ Scope transitions are enacted by the guardian updating the delegation event. The dependant's device requires no reconfiguration — the key server (Heartwood Pi or guardian's device) enforces the current scope on each signing request.
2175
+
2176
+ When a signing request falls outside the dependant's permitted scope, the key server SHOULD forward the request to the guardian's device for approval rather than rejecting outright. This allows the dependant to request exceptions without requiring a permanent scope change.
2177
+
2178
+ #### 21.4.4 Age-Appropriate Tiers
2179
+
2180
+ | Age range | Tier | Guardian required? | Typical capabilities |
2181
+ |-----------|------|--------------------|---------------------|
2182
+ | 0-7 | 4 | Yes (mandatory) | Guardian-managed account, no direct messaging |
2183
+ | 8-12 | 4 | Yes (mandatory) | Limited messaging with guardian approval |
2184
+ | 13-17 | 4 | Yes (mandatory) | More autonomy, guardian notification |
2185
+ | 18+ | 3 | No | Full adult account |
2186
+
2187
+ #### 21.4.5 Family Structures
2188
+
2189
+ Three distinct layers handle the complexity of real families:
2190
+
2191
+ **Layer 1 — Credential level (immutable, set by professional):**
2192
+ Guardian tags reflect legal parental responsibility. Only changeable via court order + new credential from a professional.
2193
+
2194
+ **Layer 2 — Delegation level (flexible, set by guardian):**
2195
+ Guardians delegate specific permissions to step-parents, grandparents, teachers, or other trusted adults via kind 31000 delegation attestations (with `type: delegation`). Delegations are:
2196
+ - Time-limited (expiry tag)
2197
+ - Scope-limited: `full`, `activity-approval`, `content-management`, `contact-approval`
2198
+ - Revocable by the guardian at any time
2199
+
2200
+ **Layer 3 — Client level (app-specific, enforced locally):**
2201
+ Applications enforce permissions based on Layer 1 and Layer 2 data: screen time limits, content filtering, activity approval workflows, contact restrictions.
2202
+
2203
+ ### 21.5 Document Renewal
2204
+
2205
+ When a document expires and is renewed (new passport number):
2206
+ 1. New nullifier computed from new document details
2207
+ 2. `["nullifier-chain", "<old_nullifier>"]` tag links old and new
2208
+ 3. New credential supersedes old
2209
+ 4. Continuity of identity maintained despite new document
2210
+
2211
+ ### 21.6 Death, Key Compromise, Incapacitation
2212
+
2213
+ **Death:** A professional issues a kind 31000 revocation attestation (with `type: revocation`) with reason "death." All credentials for the pubkey are considered revoked.
2214
+
2215
+ **Key compromise:** Subject visits a professional with identity documents. Professional revokes all old credentials and issues new ones on a new keypair. Existing vouches are lost (deliberate security measure — prevents an attacker who compromised the key from retaining social trust).
2216
+
2217
+ **Incapacitation:** Court-appointed guardian added via guardian tag on a superseding credential, issued by a professional with the court order.
2218
+
2219
+ ### 21.7 Nostr Early Adopter Migration
2220
+
2221
+ Existing Nostr users can integrate with Signet without losing their established identity:
2222
+
2223
+ **Path 1 — Sign existing keypair:**
2224
+ The user's existing npub becomes their Natural Person identity. They visit a professional for verification. All followers, NIP-05, zaps, and reputation are preserved.
2225
+
2226
+ **Path 2 — Existing npub becomes Persona:**
2227
+ The user creates a new keypair for their Natural Person identity and uses their existing npub as their Persona. An identity bridge attestation (kind 31000 with `type: identity-bridge`) links them with ring-signature privacy.
2228
+
2229
+ Both paths use existing mechanisms (NIP-05, identity bridges, credential chains). No automatic trust transfer between keypairs (prevents impersonation).
2230
+
2231
+ ---
2232
+
2233
+ ## 22. Child Online Safety
2234
+
2235
+ ### 22.1 Grooming Prevention
2236
+
2237
+ The primary defence against grooming is the combination of age-range proofs and in-person professional verification:
2238
+
2239
+ 1. **Unverified accounts cannot enter child spaces.** Communities require Tier 4 + age-range proof. An unverified account is rejected.
2240
+ 2. **Peer vouching cannot produce age-range proofs.** Only professionals who see the person and their documents can issue age-range proofs. A Tier 2 vouch carries no age verification.
2241
+ 3. **Professionals see the actual person.** AI can generate convincing documents, but a 40-year-old cannot present as a 14-year-old in person. Professionals verify documents daily as part of their existing practice.
2242
+ 4. **Guardian notifications.** When a child's account receives contact from an unknown adult, the guardian is notified. Contact requires guardian approval in strict mode.
2243
+ 5. **"Signet me" challenges.** Time-based word verification proves the current device holder matches the credential. Detects proxy use and reveals age gaps.
2244
+
2245
+ ### 22.2 Age Bypass Prevention
2246
+
2247
+ Preventing children from accessing adult-only spaces:
2248
+
2249
+ 1. **Adult spaces require Tier 3+ with "18+" age-range proof.** Self-declaration ("I am 18") is not sufficient.
2250
+ 2. **Nullifiers prevent second keypairs.** A child cannot create an additional keypair without age-range proof — the deterministic nullifier from their document will match their existing child credential.
2251
+ 3. **Persona credentials carry age-range.** The Persona issued during the two-credential ceremony MUST carry the same age-range proof as the Natural Person credential. A child's Persona is still identifiable as a child's Persona.
2252
+ 4. **Identity bridges inherit age-range.** Any identity bridge created from a child credential carries the source credential's age-range constraint.
2253
+
2254
+ ### 22.3 Client Display Requirements
2255
+
2256
+ Clients implementing Signet MUST display:
2257
+
2258
+ | Element | Display |
2259
+ |---------|---------|
2260
+ | Unverified account | "Unverified" label, no trust indicators |
2261
+ | Tier 4 child (0-12) | "Verified Child" + age range badge |
2262
+ | Tier 4 teen (13-17) | "Verified Teen" + age range badge |
2263
+ | Tier 3 adult (18+) | "Verified Adult" badge |
2264
+ | Guardian link | "Guardian: [name/pubkey]" on child profiles |
2265
+ | Age-gap contact | Warning to child + guardian notification |
2266
+ | Missing age proof | "Age not verified" warning |
2267
+
2268
+ ### 22.4 Guardian Controls
2269
+
2270
+ Guardian accounts (pubkeys listed in a child's guardian tags) have access to:
2271
+
2272
+ - **DM policy:** Block all / approve-only / notify / allow
2273
+ - **Content filtering:** Strict / moderate / off
2274
+ - **Contact restrictions:** Whitelist / blacklist / open with notifications
2275
+ - **Meeting detection:** "Signet me" required for first real-world contact
2276
+ - **Delegation:** Grant specific permissions to trusted adults (step-parent, grandparent, teacher)
2277
+
2278
+ These controls are enforced at the client level (Layer 3 of the family structure model, §21.4.5).
2279
+
2280
+ ### 22.5 Community Policy Templates
2281
+
2282
+ Communities can adopt pre-defined safety policies:
2283
+
2284
+ | Template | Min tier | Age range | Guardian required? | DM policy |
2285
+ |----------|----------|-----------|-------------------|-----------|
2286
+ | Child-safe (under-13) | 4 | 0-12 | Yes | Guardian-approved only |
2287
+ | Teen (13-17) | 4 | 13-17 | Yes (notify) | Open with logging |
2288
+ | Adult-only (18+) | 3 | 18+ | No | Open |
2289
+ | Mixed-age | 3 (adults) / 4 (children) | All | Per age group | Age-appropriate |
2290
+
2291
+ ---
2292
+
2293
+ ## 23. Inclusivity
2294
+
2295
+ ### 23.1 Tier System as Safety Net
2296
+
2297
+ The four-tier system ensures that lack of documents does not mean exclusion:
2298
+
2299
+ - **Tier 1 (self-declared):** Anyone can create an account. No documents required. Zero barrier to entry.
2300
+ - **Tier 2 (peer-vouched):** Real-world connections can vouch. No professional or document needed.
2301
+ - **Tier 3 (professional, adult):** Requires documents and professional verification.
2302
+ - **Tier 4 (professional, adult+child):** Requires documents, professional, and guardian.
2303
+
2304
+ Every person starts at Tier 1. The system provides *degrees of confidence*, not binary access.
2305
+
2306
+ ### 23.2 Expanded Document Types
2307
+
2308
+ Professional verifiers can accept a range of identity documents beyond passports and national IDs:
2309
+
2310
+ - UNHCR refugee travel documents
2311
+ - Stateless person travel documents (1954 Convention)
2312
+ - Temporary residence permits
2313
+ - Birth certificates (for children)
2314
+ - Court-issued identity documents
2315
+ - Religious community attestations (with professional co-signing)
2316
+ - Employer attestations (for jurisdiction-specific contexts)
2317
+
2318
+ The verifier's professional judgement determines which documents are sufficient. The credential records the document type used, allowing communities to set their own acceptance thresholds.
2319
+
2320
+ ### 23.3 The "Down and Out" Path
2321
+
2322
+ For people with no documents at all (homeless, displaced, stateless):
2323
+
2324
+ 1. **Tier 1** — immediate access. Create a keypair, start participating.
2325
+ 2. **Tier 2** — community vouching. Local people who know the person can vouch.
2326
+ 3. **Support pathway** — NGOs, shelters, legal aid organisations can help obtain documents over time
2327
+ 4. **Tier 3** — when documents are eventually obtained, professional verification upgrades the credential
2328
+
2329
+ The system never requires documents as a prerequisite for basic participation. Documents unlock higher tiers, which unlock access to communities with stricter policies — but Tier 1 and Tier 2 are always available.
2330
+
2331
+ ### 23.4 Degrees of Confidence, Not Binary Access
2332
+
2333
+ Communities choose their own verification thresholds. A community for casual conversation might accept Tier 1. A community for financial advice might require Tier 3. A community for children requires Tier 4.
2334
+
2335
+ This is not gatekeeping — it is informed choice. Each community publishes its policy (kind 30078). Users can see what is required before joining. No central authority decides who can participate where.
2336
+
2337
+ The goal is that every person, regardless of documentation status, has a path to meaningful participation — while communities retain the right to set appropriate safety standards for their members.
2338
+
2339
+ ---
2340
+
2341
+ ## 24. Jurisdiction Confidence
2342
+
2343
+ ### 24.1 Overview
2344
+
2345
+ Not all jurisdictions provide equal assurance for professional verification. A credential issued by a verifier in a jurisdiction with strong professional regulation, public registries, and digital credential infrastructure carries more weight than one from a jurisdiction with weaker oversight.
2346
+
2347
+ ### 24.2 Confidence Scoring
2348
+
2349
+ The jurisdiction confidence score (0-100) is computed from:
2350
+
2351
+ | Factor | Max Points | Description |
2352
+ |--------|-----------|-------------|
2353
+ | Corruption Perception Index | 20 | Transparency International CPI (updated annually, publicly available). Score = CPI / 5, capped at 20. A jurisdiction with CPI 90 (Denmark) scores 18. A jurisdiction with CPI 20 scores 4. |
2354
+ | Professional body coverage | 15 | Number of regulated professions (1pt per body, capped at 15) |
2355
+ | Public register availability | 15 | Proportion of bodies with queryable public registers |
2356
+ | Digital credential issuance | 15 | Proportion of bodies issuing machine-verifiable credentials |
2357
+ | Data protection maturity | 15 | Explicit consent, erasure rights, portability, breach notification, cross-border restrictions |
2358
+ | Mutual recognition | 10 | Number of mutual recognition partners (1pt per partner, capped at 10) |
2359
+ | E-signature recognition | 5 | Whether electronic signatures are legally recognised |
2360
+ | Legal system compatibility | 5 | Common-law and civil-law score highest (well-established professional regulation) |
2361
+
2362
+ The CPI factor is the single most important signal. In jurisdictions where bribery is common, the confidence that a professional genuinely verified documents (rather than rubber-stamping for a fee) is lower. This is not discrimination — it is statistical confidence based on publicly available data.
2363
+
2364
+ ### 24.3 Client Behaviour
2365
+
2366
+ Clients MAY use jurisdiction confidence scores to:
2367
+ - Weight Signet Score contributions from different jurisdictions (a Tier 3 credential from a high-confidence jurisdiction contributes more to the Signet Score)
2368
+ - Display jurisdiction confidence alongside credentials
2369
+ - Set minimum jurisdiction confidence in community policies
2370
+
2371
+ Clients MUST NOT use jurisdiction confidence to deny Tier 1 or Tier 2 credentials, which are jurisdiction-independent.
2372
+
2373
+ ### 24.4 Three Failure Modes
2374
+
2375
+ | Mode | Example | Solution |
2376
+ |------|---------|----------|
2377
+ | **Captured/corrupt bodies** | State-controlled professional bodies | Cross-jurisdiction verification: subject verified by professional in a free-body jurisdiction |
2378
+ | **Nonexistent bodies** | No formal professional regulation | Embassy model: international NGOs and law firms with globally-licensed professionals serve as remote trust anchors |
2379
+ | **Non-digital bodies** | Paper-based registries, no APIs | Manual registry cross-checks (weighted lower); eIDAS 2.0 mandates machine-readable interfaces by December 2026 |
2380
+
2381
+ For jurisdictions where Tier 3/4 is not achievable, Tier 1 + Tier 2 (self-declared + peer vouches) are always available. "Some trust" is infinitely better than "no trust."
2382
+
2383
+ ### 24.5 Bribery as Self-Documenting Evidence
2384
+
2385
+ In jurisdictions with high corruption, bribery in document issuance is currently invisible — cash changes hands, fake documents appear, nobody knows. Signet inverts this: every credential is public, permanently traceable to a specific verifier, and subject to anomaly detection.
2386
+
2387
+ A corrupt official who rubber-stamps verifications creates a permanent, public audit trail:
2388
+ - **Volume anomalies** — issuing 200 verifications/week when the norm is 5 (§7 Layer 3)
2389
+ - **Geographic impossibilities** — verifying people in locations they couldn't plausibly reach
2390
+ - **Nullifier collisions** — multiple people presenting the same document
2391
+ - **Cross-verification failures** — credentials that don't survive independent confirmation by a second verifier
2392
+
2393
+ The corruption that was invisible becomes the evidence that catches itself. The more a corrupt official does it, the more obvious the pattern. This has the potential to reduce bribery in document issuance — not by preventing it, but by making it permanently traceable.
2394
+
2395
+ Cross-jurisdiction verification (§24.4) provides the escape valve: a person in a corrupt jurisdiction can get verified by a professional in a less corrupt one. The credential from the independent jurisdiction carries higher confidence, and the discrepancy (if any) between the two credentials surfaces the problem.
2396
+
2397
+ #### The game theory inversion
2398
+
2399
+ Currently, bribery is a Nash equilibrium in many developing countries — everyone does it because the cost of not doing it (waiting months, being denied) exceeds the cost of doing it (a small fee, no consequences). Signet breaks the equilibrium from both sides:
2400
+
2401
+ - **The corrupt official** carries every bribed verification as a permanent liability. One anomaly detection flag and their entire history unravels — taking down every credential they ever signed. Their career, their professional registration, and their reputation are on the line forever.
2402
+ - **The person paying the bribe** has their entire identity infrastructure linked to that official. If the official falls, their credential's IQ contribution drops to near zero. Everything built on top — service access, family trust chains, children's verifications — crumbles. The bribe isn't a one-time transaction; it's a permanent bond to a ticking time bomb.
2403
+
2404
+ The honest route becomes the rational economic choice, even in a corrupt environment. A slow, honest credential lasts forever. A fast, corrupt credential is a house of cards. Both sides of the bribe are incentivised to go straight — not through enforcement, but through structural incentives. The system doesn't need to catch everyone — it just needs to shift the equilibrium.
2405
+
2406
+ #### Scale of the problem
2407
+
2408
+ The UN estimates $1 trillion is paid in bribes annually and $2.6 trillion stolen through corruption — roughly 5% of global GDP (~$5.75 trillion in 2025). Even reducing document-related bribery by a fraction of a percent moves billions. Anti-corruption as a structural byproduct of transparent identity verification, at zero additional cost.
2409
+
2410
+ Sources: [UN Secretary-General, Security Council (2018)](https://press.un.org/en/2018/sc13493.doc.htm), [World Economic Forum (2018)](https://www.weforum.org/stories/2018/12/the-global-economy-loses-3-6-trillion-to-corruption-each-year-says-u-n/), [World Bank](https://blogs.worldbank.org/en/governance/what-are-costs-corruption).
2411
+
2412
+ ### 24.6 Document Type Registry
2413
+
2414
+ The Merkle tree leaf keys and the document type strings used in nullifier computation are defined by the **Signet Document Registry**, which is maintained separately from this specification.
2415
+
2416
+ The registry lists, per country:
2417
+ - Available document types (passport, national ID, driving licence, etc.)
2418
+ - Required and optional fields for each document type
2419
+ - Which fields contribute to the nullifier computation
2420
+ - Whether the document number changes on renewal
2421
+ - Country-specific attributes (e.g., `gb:nationalInsurance`, `in:aadhaar`, `us:ssn`)
2422
+
2423
+ The registry is an open-source community resource hosted alongside the protocol. Adding a new country or document type is a registry update — it does not require a protocol revision. The protocol is document-agnostic by design: it defines the Merkle tree format and nullifier computation, not the contents.
2424
+
2425
+ ---
2426
+
2427
+ ## 25. Implementation Levels
2428
+
2429
+ ### 25.1 Overview
2430
+
2431
+ Protocol complexity should not prevent partial adoption. Signet defines three progressive implementation levels so that client developers can integrate incrementally.
2432
+
2433
+ ### 25.2 Level 1 — Read Trust Badges
2434
+
2435
+ **Effort:** A weekend. **Event kinds:** 31000 (`type: credential`), 31000 (`type: vouch`).
2436
+
2437
+ Read credentials and vouches for a pubkey, compute a basic trust tier and score, display a badge. No new cryptography beyond Schnorr signature verification (which Nostr clients already implement). This is the NIP-05 equivalent — minimal effort, immediate value.
2438
+
2439
+ The reference implementation provides `src/badge.ts` with `computeBadge()`, `buildBadgeFilters()`, and related helpers.
2440
+
2441
+ ### 25.3 Level 2 — Issue Vouches
2442
+
2443
+ **Effort:** A few days. **Event kinds:** 31000 (credential, vouch), 30078 (policy).
2444
+
2445
+ Level 1 + users can vouch for each other (create kind 31000 vouch attestations) and communities can set policies (kind 30078). This is the viral layer — peer vouching creates Tier 2 network effects without requiring professional verifiers.
2446
+
2447
+ ### 25.4 Level 3 — Full Protocol
2448
+
2449
+ **Effort:** Weeks to months. **Event kinds:** 31000 (all attestation types), 30078 (policy), 30482-30484 (voting).
2450
+
2451
+ All event kinds, full cryptographic stack: Merkle trees for selective disclosure, Pedersen range proofs for age range proofs, ring signatures for issuer privacy, two-credential ceremony, nullifier computation, guardian delegation, anomaly detection, and the voting extension.
2452
+
2453
+ ### 25.5 Strategic Guidance
2454
+
2455
+ The recommended adoption path is:
2456
+ 1. Get Level 1 into 10+ Nostr clients (badges create visibility and demand)
2457
+ 2. Enable Level 2 for viral peer vouching
2458
+ 3. Level 3 for clients that want full verification capability
2459
+
2460
+ ## 26. Security Considerations — Privacy Design Trade-offs
2461
+
2462
+ This section documents known privacy trade-offs in the Signet protocol design, the mitigations available to users and implementers, and the accepted trade-offs where transparency or continuity was deliberately chosen over maximum privacy.
2463
+
2464
+ ### 26.1 Credential Chain Privacy
2465
+
2466
+ Credential chains (`supersedes`/`superseded-by` tags) create a publicly observable timeline of credential lifecycle events. An observer can follow the full history of a Natural Person's credential renewals, name changes, and tier upgrades through these links.
2467
+
2468
+ **Mitigation options for privacy-sensitive users:**
2469
+ - Issue new credentials without `supersedes` tags, sacrificing continuity proof for privacy
2470
+ - Use a fresh keypair when replacing credentials (requires re-establishing trust)
2471
+ - Clients SHOULD warn users that supersedes chains are publicly visible
2472
+
2473
+ **Accepted trade-off:** Credential chains provide important auditability and credential lifecycle management. For most users, the transparency is a feature (proving continuous identity). Users who need stronger privacy should avoid credential chains.
2474
+
2475
+ ### 26.2 Guardian Tag Privacy
2476
+
2477
+ Guardian delegation tags (`["guardian", "<parent_pubkey>"]`) on child Persona credentials publicly link the child's anonymous account to their parent's verified Natural Person identity. This reveals:
2478
+ - That the account belongs to a child
2479
+ - Which specific adult is their guardian
2480
+ - The child's age range
2481
+
2482
+ **Mitigation (future):** Guardian tags on Persona credentials SHOULD reference the parent's Persona pubkey rather than their Natural Person pubkey. This preserves the guardian relationship while maintaining the parent's anonymity. Implementations MUST validate that the referenced guardian holds a valid credential regardless of which pubkey is used.
2483
+
2484
+ **Current status:** Implementations currently use the Natural Person pubkey for simplicity. A migration path will be defined in a future spec revision.
2485
+
2486
+ ### 26.3 Ring Intersection Attacks on Identity Bridges
2487
+
2488
+ Identity bridge attestations (kind 31000 with `type: identity-bridge`) embed the full ring of public keys used for the ring signature. If a Persona issues multiple identity bridges over time with different randomly selected decoy members, an observer can intersect the ring sets to identify the common member — the actual signer.
2489
+
2490
+ With a ring of size `n` and `k` independent bridge events, the expected intersection size is approximately `1 + (n-1) * (1/pool_size)^(k-1)`, which rapidly approaches 1 (the signer) as `k` increases.
2491
+
2492
+ **Mitigations:**
2493
+ - Identity bridges SHOULD be issued at most once per Persona. Re-issuance MUST reuse the same ring members
2494
+ - Larger rings (50+ members) require more samples for intersection attacks to succeed
2495
+ - Clients MUST NOT automatically refresh identity bridges — manual re-issuance only, with a warning about ring intersection risks
2496
+ - Future: consider using zero-knowledge proofs of set membership instead of explicit rings
2497
+
2498
+ ---
2499
+
2500
+ ## 27. Cold-Call Verification
2501
+
2502
+ Cold-call verification solves a common trust problem: a customer receives a call claiming to be from their bank, law firm, or other institution. How can the customer verify the caller is genuine, without installing a new app, without sharing personal data, and without depending on a central authority?
2503
+
2504
+ Signet provides a mechanism for institutions to publish their verification pubkeys via `.well-known/signet.json`, and for both parties to independently derive the same spoken words from an ephemeral ECDH shared secret.
2505
+
2506
+ ### 27.1 Institution Key Publication
2507
+
2508
+ Institutions publish a JSON document at `https://<domain>/.well-known/signet.json`:
2509
+
2510
+ ```json
2511
+ {
2512
+ "version": 1,
2513
+ "name": "Acme Legal LLP",
2514
+ "pubkeys": [
2515
+ {
2516
+ "id": "key-2026-01",
2517
+ "pubkey": "<64-char hex secp256k1 x-only pubkey>",
2518
+ "label": "Primary Verification Key",
2519
+ "created": "2026-01-01T00:00:00Z"
2520
+ }
2521
+ ],
2522
+ "relay": "wss://relay.example.com",
2523
+ "policy": {
2524
+ "rotation": "annual",
2525
+ "contact": "security@acmelegal.com"
2526
+ }
2527
+ }
2528
+ ```
2529
+
2530
+ **Validation rules for clients fetching this document:**
2531
+
2532
+ - MUST use HTTPS — HTTP is rejected.
2533
+ - Response body MUST NOT exceed 10,240 bytes (10 KB) for version 1 documents, or 102,400 bytes (100 KB) for version 2 documents (see §17.7.1 for the extended schema).
2534
+ - `version` MUST be `1` or `2`. Version 2 documents may include `entity`, `registry`, and `staff` fields as defined in §17.7.1.
2535
+ - `name` MUST be a non-empty string.
2536
+ - `pubkeys` MUST be a non-empty array with at most 20 entries.
2537
+ - Each `pubkey` value MUST be a 64-character lowercase hexadecimal string (x-only secp256k1).
2538
+ - Clients MAY cache the response for up to 24 hours.
2539
+
2540
+ ### 27.2 Session Code Format
2541
+
2542
+ To let the customer and institution find each other (e.g. when the customer initiates the check in an app and reads a code over the phone), a human-friendly session code is derived from the ephemeral pubkey:
2543
+
2544
+ ```
2545
+ NATOWORD-NNNN
2546
+ ```
2547
+
2548
+ Examples: `BRAVO-7742`, `NOVEMBER-0053`, `XRAY-1991`
2549
+
2550
+ Derivation:
2551
+
2552
+ 1. Compute `hash = SHA-256(ephemeralPubkey_bytes)`.
2553
+ 2. `natoIndex = hash[0] mod 26` → select from the NATO phonetic alphabet.
2554
+ 3. `digits = ((hash[1] << 24) | (hash[2] << 16) | (hash[3] << 8) | hash[4]) mod 10000` → zero-padded to 4 digits.
2555
+ 4. Code = `NATO[natoIndex] + "-" + digits.padStart(4, "0")`.
2556
+
2557
+ The session code is a human-readable fingerprint of the ephemeral pubkey, not a secret. It allows the institution to look up the associated ephemeral pubkey from a relay (Phase 2 feature) without the customer needing to read out 64 hex characters.
2558
+
2559
+ **NATO phonetic alphabet (Signet uses the ICAO standard):**
2560
+
2561
+ `ALFA BRAVO CHARLIE DELTA ECHO FOXTROT GOLF HOTEL INDIA JULIET KILO LIMA MIKE NOVEMBER OSCAR PAPA QUEBEC ROMEO SIERRA TANGO UNIFORM VICTOR WHISKEY XRAY YANKEE ZULU`
2562
+
2563
+ ### 27.3 Ephemeral ECDH Flow
2564
+
2565
+ The verification flow uses a one-time ECDH exchange to derive a shared secret that neither party possessed before the call:
2566
+
2567
+ **Customer side (initiate):**
2568
+
2569
+ 1. Fetch `https://<institution-domain>/.well-known/signet.json` and select a pubkey.
2570
+ 2. Generate an ephemeral secp256k1 keypair `(ephPriv, ephPub)`.
2571
+ 3. Compute `sharedPoint = secp256k1.ECDH(ephPriv, institutionPubkey)`.
2572
+ 4. Derive `sharedSecret = SHA-256(x-coordinate of sharedPoint)` (32 bytes).
2573
+ 5. Derive words: `words = SPOKEN-DERIVE(sharedSecret, "signet:cold-call", currentEpoch, wordCount=3)`.
2574
+ 6. Generate `sessionCode = NATO-WORD + "-" + 4-digits` from ephemeral pubkey.
2575
+ 7. Display `words` on screen — the customer expects to hear these words from the caller.
2576
+ 8. Share `ephemeralPubkey` (or `sessionCode`) with the institution (read it out, or relay lookup).
2577
+ 9. Zero the ephemeral private key immediately after use.
2578
+
2579
+ **Institution side (complete):**
2580
+
2581
+ 1. Receive the customer's `ephemeralPubkey` (via relay lookup by session code, or spoken by customer).
2582
+ 2. Compute `sharedPoint = secp256k1.ECDH(institutionPrivkey, ephemeralPubkey)`.
2583
+ 3. Derive `sharedSecret = SHA-256(x-coordinate of sharedPoint)`.
2584
+ 4. Derive `words = SPOKEN-DERIVE(sharedSecret, "signet:cold-call", currentEpoch, wordCount=3)`.
2585
+ 5. Read the words out to the customer.
2586
+
2587
+ If the words match, the caller holds the private key corresponding to a pubkey published in the institution's `.well-known/signet.json` at the time the customer fetched it.
2588
+
2589
+ ### 27.4 Word Derivation Specification
2590
+
2591
+ Cold-call words use the same SPOKEN-DERIVE function as "Signet me" (§15), with a different context string for domain separation:
2592
+
2593
+ - **Algorithm:** `HMAC-SHA256(sharedSecret, utf8("signet:cold-call") || counter_be32)`
2594
+ - **Context:** `"signet:cold-call"` (distinct from `"signet:verify"` used by "Signet me")
2595
+ - **Counter:** `Math.floor(unixSeconds / 30)` — 30-second epoch, same as "Signet me"
2596
+ - **Tolerance:** ±1 epoch (accounts for up to 30 seconds of clock skew between parties)
2597
+ - **Default word count:** 3
2598
+ - **Wordlist:** spoken-clarity wordlist (same as "Signet me")
2599
+
2600
+ The context separation ensures that cold-call words and peer-verification words are always different, even if the same shared secret were somehow reused.
2601
+
2602
+ ### 27.5 Security Properties
2603
+
2604
+ **What cold-call verification provides:**
2605
+
2606
+ - **Institution authenticity:** The caller knows the institution's private key — they are who they claim to be (or the key has been compromised).
2607
+ - **Freshness:** The ephemeral keypair is generated per-call. Replaying an old session code produces different words in the next epoch.
2608
+ - **No data disclosure:** The customer's personal data is never transmitted. The ECDH produces a shared secret without either party revealing their private key.
2609
+ - **No central authority:** Verification relies only on DNS (to reach the `.well-known` endpoint) and the HTTPS PKI.
2610
+
2611
+ **Limitations:**
2612
+
2613
+ - **DNS/TLS trust:** If the institution's domain is compromised, an attacker could substitute their own pubkeys in `.well-known/signet.json`. Clients SHOULD cache the pubkeys and warn if they change unexpectedly.
2614
+ - **Key compromise:** If the institution's private key is leaked, an attacker can impersonate the institution. Institutions SHOULD rotate keys annually and support multiple simultaneous pubkeys for transition periods.
2615
+ - **Epoch synchronisation:** Both parties must be within ±30 seconds. Network time attacks could desynchronise them, but ±1 epoch tolerance mitigates minor skew.
2616
+ - **No relay integration yet (Phase 1):** In the current implementation, the customer must share the `ephemeralPubkey` or `sessionCode` verbally. Phase 2 will add relay-based session code resolution so the institution can look up the ephemeral pubkey automatically.
2617
+
2618
+ ### 27.6 Phase 2: Relay-Based Session Code Resolution
2619
+
2620
+ *Not yet implemented. Described here for future implementers.*
2621
+
2622
+ The institution publishes a relay URL in `.well-known/signet.json` (`relay` field). The customer's app publishes the ephemeral pubkey to this relay, tagged with the session code. The institution's system subscribes and automatically retrieves the ephemeral pubkey without requiring the customer to read it out.
2623
+
2624
+ This eliminates the need for the customer to verbally communicate anything except confirming that the words match.
2625
+
2626
+ ---
2627
+
2628
+ *This specification is a living document. It will evolve through community feedback and implementation experience.*