diff --git a/.gitignore b/.gitignore index c2e3c55..8612a27 100644 --- a/.gitignore +++ b/.gitignore @@ -76,7 +76,6 @@ cmd/benchmark/data !*.css !*.ts !*.html -!contrib/stella/Dockerfile !*.lock !*.nix !license @@ -88,10 +87,8 @@ cmd/benchmark/data !.gitignore !version !out.jsonl -!contrib/stella/Dockerfile !strfry.conf !config.toml -!contrib/stella/.dockerignore !*.jsx !*.tsx !bun.lock diff --git a/docs/names.md b/docs/names.md new file mode 100644 index 0000000..dde6c33 --- /dev/null +++ b/docs/names.md @@ -0,0 +1,807 @@ +NIP-XX +====== + +Decentralized Name Registry with Trust-Weighted Consensus +---------------------------------------------------------- + +`draft` `optional` + +## Abstract + +This NIP defines a decentralized name registry protocol for human-readable resource naming with trustless title transfer. The protocol uses trust-weighted attestations from relay operators to achieve Byzantine fault tolerance without requiring centralized coordination or proof-of-work. Consensus is reached through social mechanisms of association and affinity, enabling the network to scale to thousands of participating relays while maintaining ~51% Byzantine fault tolerance against censorship. + +## Motivation + +Many peer-to-peer applications require human-readable naming systems for locating network resources (analogous to DNS). Traditional approaches either rely on centralized authorities or blockchain-based systems with slow finality times and high resource requirements. + +This proposal leverages Nostr's existing social graph and relay infrastructure to create a naming system that is: + +- **Trustless**: No single authority controls name registration +- **Byzantine fault tolerant**: Resistant to malicious relays (up to ~51% by trust weight) +- **Scalable**: Supports thousands of participating relays +- **Censorship resistant**: Diverse trust graphs make network-wide censorship difficult +- **Permissionless**: Anyone can operate a relay and participate in consensus + +The protocol achieves finality in 1-2 minutes, which is acceptable for DNS-like use cases while avoiding the complexity and resource requirements of traditional blockchain consensus. + +## Specification + +### Event Kinds + +This NIP defines the following event kinds: + +- `30100`: Registration Proposal - Claim or transfer of a name (parameterized replaceable) +- `20100`: Attestation - Relay operator's vote on a registration proposal (ephemeral) +- `30101`: Trust Graph - Relay's trust relationships with other relays (parameterized replaceable) +- `30102`: Name State - Current ownership state (parameterized replaceable) + +### Registration Proposal (Kind 30100) + +A parameterized replaceable event where users propose to register or transfer a name: + +```json +{ + "kind": 30100, + "pubkey": "", + "created_at": , + "tags": [ + ["d", ""], // name being claimed (e.g., "foo.n") + ["action", "register"], // "register" or "transfer" + ["prev_owner", ""], // previous owner pubkey (for transfers only) + ["prev_sig", ""] // signature from prev_owner authorizing transfer + ], + "content": "", + "sig": "" +} +``` + +**Field Specifications:** + +- `d` tag: The name being registered. MUST be unique within the namespace. +- `action` tag: Either `register` (initial claim) or `transfer` (ownership change) +- `prev_owner` tag: Required for `transfer` actions. The pubkey of the current owner. +- `prev_sig` tag: Required for `transfer` actions. Signature proving authorization from previous owner. + +**Transfer Authorization:** + +For transfers, the `prev_sig` MUST be a signature over the following message: +``` +transfer::: +``` + +This prevents unauthorized transfers and ensures the current owner explicitly approves the transfer. + +### Attestation (Kind 20100) + +An ephemeral event where relay operators attest to their acceptance or rejection of a registration proposal: + +```json +{ + "kind": 20100, + "pubkey": "", + "created_at": , + "tags": [ + ["e", ""], // the registration proposal being attested + ["decision", "approve"], // "approve", "reject", or "abstain" + ["weight", "100"], // optional stake/confidence weight + ["reason", "first_valid"], // optional audit trail + ["relay", "wss://relay.example.com"] // the relay this operator controls + ], + "content": "", + "sig": "" +} +``` + +**Field Specifications:** + +- `e` tag: References the registration proposal event ID +- `decision` tag: One of: + - `approve`: Relay accepts this registration as valid + - `reject`: Relay rejects this registration (e.g., conflict detected) + - `abstain`: Relay acknowledges but doesn't vote +- `weight` tag: Optional numeric weight (default: 100). Higher weights indicate stronger confidence or stake. +- `reason` tag: Optional human-readable justification for audit trails +- `relay` tag: WebSocket URL of the relay this operator controls + +**Attestation Window:** + +Relays SHOULD publish attestations within 60-120 seconds of receiving a registration proposal. This allows sufficient time for gossip propagation while maintaining reasonable finality times. + +### Trust Graph (Kind 30101) + +A parameterized replaceable event where relay operators declare their trust relationships: + +```json +{ + "kind": 30101, + "pubkey": "", + "created_at": , + "tags": [ + ["d", "trust-graph"], // identifier for replacement + ["p", "", "wss://relay1.com", "0.9"], + ["p", "", "wss://relay2.com", "0.7"], + ["p", "", "wss://relay3.com", "0.5"] + ], + "content": "", + "sig": "" +} +``` + +**Field Specifications:** + +- `p` tag: Defines trust in another relay operator + - First parameter: Trusted relay operator's pubkey + - Second parameter: Relay WebSocket URL + - Third parameter: Trust score (0.0 to 1.0, where 1.0 = complete trust) + +**Trust Score Guidelines:** + +- `1.0`: Complete trust (e.g., operator's own other relays) +- `0.7-0.9`: High trust (well-known, reputable operators) +- `0.4-0.6`: Moderate trust (established but less familiar) +- `0.1-0.3`: Low trust (new or unknown operators) +- `0.0`: No trust (excluded from consensus) + +**Trust Graph Updates:** + +Relay operators SHOULD update their trust graphs gradually. Rapid changes to trust relationships MAY be penalized in weighted consensus calculations to prevent manipulation. + +### Name State (Kind 30102) + +A parameterized replaceable event representing the current ownership state of a name: + +```json +{ + "kind": 30102, + "pubkey": "", + "created_at": , + "tags": [ + ["d", ""], // the name + ["owner", ""], + ["registered_at", ""], + ["proposal", ""], + ["attestations", ""], + ["confidence", "0.87"] // consensus confidence score + ], + "content": "", + "sig": "" +} +``` + +This event is published by relays after consensus is reached, allowing clients to quickly query current ownership state without recomputing consensus. + +### Consensus Algorithm + +Each relay independently computes consensus using the following algorithm: + +#### 1. Attestation Window + +When a relay receives a registration proposal for name `N`: + +1. Start a timer for `T` seconds (recommended: 60-120s) +2. Collect all attestations for this proposal +3. Collect competing proposals for the same name `N` + +#### 2. Trust-Weighted Scoring + +For each competing proposal `P`, compute a weighted score: + +``` +score(P) = Σ (attestation_weight × trust_decay) +``` + +Where: +- `attestation_weight`: The weight from the attestation's `weight` tag (default: 100) +- `trust_decay`: Distance-based trust decay from this relay's trust graph: + - **Direct trust** (0-hop): `trust_score × 1.0` + - **1-hop trust**: `trust_score × 0.8` + - **2-hop trust**: `trust_score × 0.6` + - **3-hop trust**: `trust_score × 0.4` + - **4+ hops**: `0.0` (not counted) + +#### 3. Trust Distance Calculation + +Trust distance is computed using the relay's trust graph (kind 30101 events): + +1. Build a directed graph from all relay trust declarations +2. Use Dijkstra's algorithm or breadth-first search to find shortest trust path +3. Multiply trust scores along the path for effective trust weight + +**Example:** +``` +Relay A → Relay B (0.9) → Relay C (0.8) +Effective trust from A to C: 0.9 × 0.8 × 0.8 (1-hop decay) = 0.576 +``` + +#### 4. Consensus Decision + +After the attestation window expires: + +1. **Compute total trust weight**: Sum of all attestation scores across all proposals +2. **Compute proposal score**: Each proposal's weighted attestation sum +3. **Accept proposal `P` if:** + - `score(P) / total_trust_weight > threshold` (recommended: 0.51) + - No competing proposal has higher score + - Valid transfer authorization (if action is "transfer") + +4. **Defer decision if:** + - No proposal reaches threshold + - Multiple proposals exceed threshold with similar scores (within 5%) + - Insufficient attestations received (coverage < 30% of trust graph) + +5. **Publish name state** (kind 30102) once consensus is reached + +### Sparse Attestation Optimization + +To reduce network load, relays MAY use sparse attestation where they only attest when: + +1. **Local interest**: One of the relay's connected clients queries this name +2. **Duty rotation**: `hash(proposal_event_id || relay_pubkey) % K == 0` (for sampling rate 1/K) +3. **Conflict detected**: Multiple competing proposals received for the same name +4. **Direct request**: Client explicitly requests attestation + +**Recommended sampling rates:** +- Networks with <100 relays: K=1 (100% attestation) +- Networks with 100-1000 relays: K=10 (10% attestation) +- Networks with >1000 relays: K=20 (5% attestation) + +This optimization reduces attestation volume by 80-95% while maintaining consensus reliability through randomized duty rotation. + +### Handling Conflicts + +#### Simultaneous Registration + +When multiple proposals for the same name arrive at similar timestamps: + +1. **Primary resolution**: Weighted consensus (highest score wins) +2. **Tiebreaker**: If scores are within 5%, use lexicographic ordering of proposal event IDs +3. **Client notification**: Relays SHOULD publish notices about conflicts for transparency + +#### Competing Transfers + +When multiple transfer proposals claim to originate from the same owner: + +1. Verify `prev_sig` authenticity for each proposal +2. Accept the earliest valid transfer (by `created_at`) +3. If timestamps are identical (within 1 second), use event ID tiebreaker + +#### Trust Graph Divergence + +Different relays may reach different consensus due to divergent trust graphs. This is acceptable and provides censorship resistance: + +- Clients SHOULD query multiple relays (recommended: 3-5) +- Use majority consensus among queried relays +- Display uncertainty warnings if relays disagree (similar to SSL certificate warnings) + +### Finality Timeline + +Expected timeline for name registration: + +``` +T=0s: Registration proposal published +T=0-30s: Proposal propagates via Nostr gossip +T=30-90s: Relays publish attestations +T=90s: Most relays compute weighted consensus +T=120s: High confidence threshold (2-minute finality) +``` + +**Early finality**: If >70% of expected attestations arrive within 30s and reach consensus threshold, relays MAY finalize earlier. + +## Implementation Guidelines + +### Client Implementation + +Clients querying name ownership should: + +1. Subscribe to kind 30102 events for the name from multiple relays +2. Use majority consensus among responses +3. Warn users if relays disagree on ownership +4. Cache results with TTL of 5-10 minutes +5. Re-query on cache expiry or when name is used in critical operations + +### Relay Implementation + +Relays participating in consensus should: + +1. Subscribe to kind 30100, 20100, and 30101 events from trusted relays +2. Maintain local trust graph (derived from kind 30101 events) +3. Implement the consensus algorithm described above +4. Publish attestations (kind 20100) for proposals of interest +5. Publish name state (kind 30102) after reaching consensus +6. Prune expired ephemeral attestations (>7 days old) + +**Storage requirements:** +- Trust graph: ~100 KB per 1000 relays +- Active proposals: ~1 MB per 1000 pending registrations +- Attestations (7-day window): ~100 MB per 1000 relays at 1000 registrations/day +- Name state: ~1 KB per name + +### Bootstrap Relay Discovery + +New relays should bootstrap their trust graph by: + +1. Connecting to well-known seed relays (similar to NIP-65 relay lists) +2. Importing trust graphs from 3-5 reputable relays +3. Using weighted average of imported trust scores as initial state +4. Gradually adjusting trust based on observed relay behavior over 30 days + +## Security Considerations + +### Attack Vectors and Mitigations + +#### 1. Sybil Attack + +**Attack**: Attacker creates thousands of relay identities to dominate attestations. + +**Mitigation**: +- Trust-weighted consensus prevents new relays from having immediate influence +- Established relays must trust new relays before they gain weight +- Age-weighted trust (new relays have reduced influence for 30 days) + +#### 2. Trust Graph Manipulation + +**Attack**: Attacker gradually builds trust relationships then exploits them. + +**Mitigation**: +- Audit trails (kind 30101 events are public and verifiable) +- Sudden trust changes are penalized in consensus calculations +- Diverse trust graphs mean attacker must control different sets of relays for different victims + +#### 3. Censorship + +**Attack**: Powerful relays refuse to attest certain names (e.g., dissidents, competitors). + +**Mitigation**: +- Subjective consensus means each relay has its own trust graph +- Censoring a name requires controlling >51% of *each relay's* trust graph +- More difficult than controlling 51% of network-wide consensus +- Users can choose relays aligned with their values + +#### 4. Name Squatting + +**Attack**: Registering valuable names without use. + +**Mitigation** (optional extensions): +- Name expiration: Require periodic renewal (NIP extension) +- Economic cost: Require payment or proof-of-burn for registration +- Proof-of-use: Require demonstrable resource at name (similar to DNS verification) + +#### 5. Transfer Fraud + +**Attack**: Forged transfer without owner's consent. + +**Mitigation**: +- Transfer requires cryptographic signature from previous owner (`prev_sig`) +- Signature includes timestamp to prevent replay attacks +- Invalid signatures cause immediate rejection by honest relays + +### Privacy Considerations + +- Registration proposals are public (necessary for consensus) +- Ownership history is permanently visible on relays +- Trust relationships are public (required for verifiable consensus) +- Clients leaking name queries to relays (similar to DNS privacy issues) + - Mitigation: Use private relays or Tor for sensitive queries + +## Discussion + +### Trust Graph Bootstrapping + +The effectiveness of trust-weighted consensus depends on establishing a healthy trust graph. This presents a chicken-and-egg problem: new relays need trust to participate, but must participate to earn trust. + +**Proposed bootstrapping strategies:** + +#### 1. Seed Relay Trust Inheritance + +New relays can inherit trust graphs from established "seed" relays: + +```json +{ + "kind": 30101, + "tags": [ + ["inherit", "", "0.8"], + ["inherit", "", "0.6"] + ] +} +``` + +The new relay computes its initial trust graph as a weighted average of the seed relays' graphs. Over time (30-90 days), the relay adjusts trust based on observed behavior. + +**Trade-offs:** +- ✅ Enables immediate participation +- ✅ Leverages existing reputation +- ❌ Creates trust concentrations around seed relays +- ❌ Seed relay compromise affects many descendants + +#### 2. Web of Trust Endorsements + +Established relay operators can endorse new relays through signed endorsements: + +```json +{ + "kind": 1100, + "pubkey": "", + "tags": [ + ["p", ""], + ["endorsement", "verified"], + ["duration", "30d"], + ["initial_trust", "0.3"] + ] +} +``` + +Other relays consuming this endorsement automatically grant the new relay temporary trust (e.g., 0.3 for 30 days), after which it decays to 0 unless organically reinforced. + +**Trade-offs:** +- ✅ Decentralized trust building +- ✅ Time-limited risk exposure +- ✅ Organic network growth +- ❌ Slower bootstrap for new relays +- ❌ Endorsement spam risk + +#### 3. Proof-of-Stake Bootstrap + +New relays can stake economic value (e.g., lock tokens in a Bitcoin Lightning channel) to gain initial trust: + +```json +{ + "kind": 30103, + "pubkey": "", + "tags": [ + ["stake", "", "1000000"], // 1M sats + ["stake_duration", "180d"], + ["stake_proof", ""] + ] +} +``` + +Relays treat staked relays as having trust proportional to stake amount. Dishonest behavior results in slashing (stake destruction). + +**Trade-offs:** +- ✅ Sybil resistant (economic cost) +- ✅ Clear incentive alignment +- ✅ Immediate trust proportional to stake +- ❌ Requires economic layer integration +- ❌ Excludes low-resource operators +- ❌ Introduces plutocracy risk + +#### 4. Proof-of-Work Bootstrap + +New relays solve computational puzzles to earn temporary trust: + +```json +{ + "kind": 30104, + "pubkey": "", + "tags": [ + ["pow", "", "24"], // 24-bit difficulty + ["pow_created", ""] + ] +} +``` + +Higher difficulty equals higher initial trust. PoW expires after 90 days unless organic trust replaces it. + +**Trade-offs:** +- ✅ Sybil resistant (computational cost) +- ✅ No economic barrier +- ✅ Proven model (Hashcash, Bitcoin) +- ❌ Energy intensive +- ❌ Favors well-resourced operators +- ❌ Difficulty calibration challenges + +**Recommendation**: Implement **hybrid approach**: +- Start with seed relay inheritance (#1) for immediate participation +- Layer WoT endorsements (#2) for organic trust growth +- Optional PoW (#4) for permissionless entry without social connections +- Reserve PoS (#3) for future upgrade if economic attacks become problematic + +### Economic Incentives + +Why would relay operators honestly attest to name registrations? Without proper incentives, rational operators might: +- Refuse to attest (freeloading) +- Attest dishonestly (e.g., favoring paying customers) +- Collude to manipulate consensus + +**Proposed incentive mechanisms:** + +#### 1. Registration Fees + +Name registration proposals include optional tips to relays that attest: + +```json +{ + "kind": 30100, + "tags": [ + ["d", "foo.n"], + ["fee", "", "10000"], // 10k sats + ["fee_distribution", "attestors"] // or "weighted" or "threshold" + ] +} +``` + +**Distribution strategies:** +- **Attestors**: Split among all relays that attested (encourages broad participation) +- **Weighted**: Proportional to trust weight (rewards influential relays) +- **Threshold**: All-or-nothing (only if consensus reached) + +**Trade-offs:** +- ✅ Direct incentive for honest attestation +- ✅ Market-driven fee discovery +- ✅ Revenue for relay operators +- ❌ Plutocracy risk (wealthy users get priority) +- ❌ Creates spam incentive (register garbage for fees) + +#### 2. Reputation Markets + +Relay operators earn reputation scores based on attestation quality: + +```json +{ + "kind": 30105, + "tags": [ + ["p", ""], + ["metric", "accuracy", "0.97"], // % of attestations matching consensus + ["metric", "uptime", "0.99"], // % of proposals attested + ["metric", "latency", "15"], // avg attestation time (seconds) + ["period", "", ""] + ] +} +``` + +High-reputation relays gain: +- Greater trust from other relays +- Priority in client queries +- Higher economic value (e.g., relay subscription fees) + +**Trade-offs:** +- ✅ Long-term incentive alignment +- ✅ Punishes dishonest behavior +- ✅ No direct economic barrier +- ❌ Reputation calculation is complex +- ❌ Slow feedback loop (months to build reputation) + +#### 3. Mutual Benefit Networks + +Relays form explicit cooperation agreements: + +```json +{ + "kind": 30106, + "tags": [ + ["p", "", "wss://relay1.com"], + ["p", "", "wss://relay2.com"], + ["agreement", "reciprocal_attestation"], + ["sla", "95_percent_uptime"] + ] +} +``` + +Relays attest to partners' proposals in exchange for reciprocal service. Violating agreements results in removal from the network. + +**Trade-offs:** +- ✅ No economic transactions needed +- ✅ Builds social cohesion +- ✅ Flexible SLA definitions +- ❌ Creates relay cartels +- ❌ Excludes new entrants +- ❌ May lead to consensus fragmentation + +#### 4. Altruism + Low Operational Cost + +If attestation cost is sufficiently low, relay operators may participate altruistically: + +- Storage: ~100 MB for 7-day attestation window +- Bandwidth: ~1 KB per attestation +- Computation: Simple signature verification and weighted sum + +At 1000 registrations/day with 10% sparse attestation: +- **Cost per relay**: <$1/month in infrastructure +- **Comparable to**: Running a Bitcoin full node or Nostr relay + +Many operators already run relays without direct compensation, motivated by: +- Ideological alignment (decentralization, censorship resistance) +- Supporting applications they use +- Technical interest and experimentation + +**Trade-offs:** +- ✅ No economic complexity +- ✅ Aligns with Nostr's ethos +- ✅ Proven model (Nostr relay operators, Bitcoin nodes) +- ❌ May not scale to high-value registrations +- ❌ Vulnerable to tragedy of the commons + +**Recommendation**: Start with **altruism (#4)** supplemented by **reputation (#2)**: +- Most relay operators will participate without direct payment (proven by existing Nostr network) +- Implement transparent reputation metrics to reward high-quality attestors +- Enable optional tipping (#1) for users who want priority or to support relays +- Reserve mutual benefit networks (#3) for enterprise deployments + +### Client Conflict Resolution + +Clients querying name ownership may receive conflicting responses from different relays due to: +1. Trust graph divergence (different relays trust different attestors) +2. Network partitions (some relays missed attestations) +3. Byzantine relays (malicious responses) + +**Conflict resolution strategies:** + +#### 1. Majority Consensus + +Client queries N relays (recommended N=5) and accepts the majority response: + +```python +def resolve_name(name, relays): + responses = [] + for relay in relays: + owner = query_relay(relay, name) + responses.append(owner) + + # Count occurrences + counts = {} + for owner in responses: + counts[owner] = counts.get(owner, 0) + 1 + + # Return majority (>50%) + for owner, count in counts.items(): + if count > len(relays) / 2: + return owner + + return None # No majority +``` + +**Trade-offs:** +- ✅ Simple and intuitive +- ✅ Byzantine fault tolerant (up to N/2 malicious relays) +- ✅ Works with any relay set +- ❌ Requires querying multiple relays (latency) +- ❌ No nuance for different relay qualities + +#### 2. Trust-Weighted Voting + +Client maintains its own trust graph and weights relay responses: + +```python +def resolve_name_weighted(name, relays, trust_scores): + responses = {} + for relay in relays: + owner = query_relay(relay, name) + weight = trust_scores.get(relay, 0.5) # default 0.5 + responses[owner] = responses.get(owner, 0) + weight + + # Return highest weighted response + return max(responses, key=responses.get) +``` + +**Trade-offs:** +- ✅ Rewards high-quality relays +- ✅ Resilient to Sybil attacks +- ✅ Customizable trust model +- ❌ Client must maintain trust graph +- ❌ More complex UX + +#### 3. Consensus Confidence Scoring + +Relays include confidence scores in name state events (kind 30102): + +```json +{ + "kind": 30102, + "tags": [ + ["d", "foo.n"], + ["owner", ""], + ["confidence", "0.87"], // 87% of trust weight agreed + ["attestations", "42"] // 42 relays attested + ] +} +``` + +Client queries multiple relays and uses the response with highest confidence: + +```python +def resolve_name_confidence(name, relays): + best_response = None + best_confidence = 0 + + for relay in relays: + state = query_relay(relay, name) # returns kind 30102 + confidence = float(state.tags["confidence"]) + + if confidence > best_confidence: + best_confidence = confidence + best_response = state.tags["owner"] + + # Warn if low confidence + if best_confidence < 0.6: + warn_user("Low consensus confidence") + + return best_response +``` + +**Trade-offs:** +- ✅ Transparent consensus strength +- ✅ User warnings for disputed names +- ✅ Minimal client complexity +- ❌ Trusts relay's confidence calculation +- ❌ Relays could lie about confidence + +#### 4. Recursive Attestation Verification + +Client fetches attestations (kind 20100) from relays and recomputes consensus locally: + +```python +def resolve_name_verify(name, relays): + # 1. Get all proposals for this name + proposals = [] + for relay in relays: + props = query_relay(relay, kind=30100, filter={"d": name}) + proposals.extend(props) + + # 2. Get all attestations for these proposals + attestations = [] + for relay in relays: + atts = query_relay(relay, kind=20100, filter={"e": [p.id for p in proposals]}) + attestations.extend(atts) + + # 3. Get trust graphs + trust_graphs = [] + for relay in relays: + graphs = query_relay(relay, kind=30101) + trust_graphs.extend(graphs) + + # 4. Recompute consensus locally + return compute_consensus(proposals, attestations, trust_graphs) +``` + +**Trade-offs:** +- ✅ Maximum trustlessness +- ✅ Client verifies everything +- ✅ Can audit relay dishonesty +- ❌ Significant bandwidth and computation +- ❌ Complex client implementation +- ❌ May timeout on large registries + +#### 5. Hybrid: Quick Query with Dispute Resolution + +Normal case: Query 3 relays, accept majority (fast path) +Dispute case: If no majority, fetch attestations and recompute (slow path) + +```python +def resolve_name_hybrid(name, relays): + # Fast path: majority consensus + responses = [query_relay(r, name) for r in relays] + majority = get_majority(responses) + + if majority: + return majority + + # Slow path: fetch attestations and verify + return resolve_name_verify(name, relays) +``` + +**Trade-offs:** +- ✅ Fast common case (1 round trip) +- ✅ Trustless dispute resolution +- ✅ Best of both worlds +- ❌ Unpredictable latency (95% fast, 5% slow) + +**Recommendation**: Implement **hybrid approach (#5)**: +- Default to majority consensus for speed +- Fall back to attestation verification on conflicts +- Display confidence scores (#3) to users +- Allow power users to enable trust-weighted voting (#2) +- Provide CLI tool for full recursive verification (#4) for auditing + +This provides good UX for most users while maintaining trustless properties for disputed or high-value names. + +## References + +- [NIP-01: Basic protocol flow](https://github.com/nostr-protocol/nips/blob/master/01.md) +- [NIP-33: Parameterized replaceable events](https://github.com/nostr-protocol/nips/blob/master/33.md) +- [NIP-65: Relay list metadata](https://github.com/nostr-protocol/nips/blob/master/65.md) +- PageRank algorithm: Brin, S. and Page, L. (1998). "The anatomy of a large-scale hypertextual Web search engine" +- Byzantine Generals Problem: Lamport, L., Shostak, R., and Pease, M. (1982) + +## Changelog + +- 2025-01-XX: Initial draft