Files
bft-crdt-experiment/docs/use-case-4-identity-networks.md

19 KiB
Raw Blame History

Use Case 4: Sybil-Resistant Identity Networks

The Identity Problem in Web3

Decentralized systems face a fundamental challenge: how to establish identity and reputation without central authorities while preventing Sybil attacks.

Current Identity System Failures

  1. Centralized Identity Providers

    • Single points of failure (KYC providers, social logins)
    • Privacy violations through data aggregation
    • Censorship and deplatforming risks
    • Geographic and political exclusion
  2. Token-Based Sybil Resistance

    • Plutocratic (wealthy users have more influence)
    • Doesn't represent real human relationships
    • Vulnerable to borrowing/renting attacks
    • Excludes users without capital
  3. Proof of Personhood Ceremonies

    • Require synchronous participation
    • Exclude users in certain timezones
    • Technical barriers for non-technical users
    • Still vulnerable to sophisticated attacks

The BFT-CRDT Identity Solution

A web of trust that grows organically through attestations, resistant to Sybil attacks through social graph analysis:

Traditional Identity:
[Central Authority] → [Identity Verification] → [Single Identity Record]
         ↓                      ↓                        ↓
   [Can be hacked]    [Privacy violation]        [Can be revoked]

BFT-CRDT Identity Network:
[User A] ←→ [User B]
    ↓    ×    ↓
[User C] ←→ [User D]
    ↓
[Attestations merge via CRDT]
    ↓
[Emergent trust graph]

Key Innovation: Trust Without Consensus

  • No global agreement on who is "verified"
  • Each participant maintains their own trust graph
  • Applications interpret the graph based on their needs
  • Sybil resistance emerges from graph topology

Architecture

Core Data Structures

pub struct IdentityCRDT {
    // All attestations in the network
    attestations: Map<AttestationId, Attestation>,
    
    // Revocations (tombstones)
    revocations: Set<AttestationId>,
    
    // Computed trust paths
    trust_cache: TrustCache,
    
    // Anti-Sybil metrics
    sybil_scores: Map<IdentityId, SybilScore>,
}

pub struct Attestation {
    pub id: AttestationId,
    pub issuer: IdentityId,
    pub subject: IdentityId,
    pub claim_type: ClaimType,
    pub claim_value: ClaimValue,
    pub confidence: u8, // 0-100
    pub context: AttestationContext,
    pub timestamp: Timestamp,
    pub expiry: Option<Timestamp>,
    pub signature: Signature,
}

pub enum ClaimType {
    // Social attestations
    KnowsPersonally,
    MetInPerson,
    WorkedWith,
    FamilyMember,
    
    // Skill attestations
    TechnicalSkill(String),
    ProfessionalRole(String),
    EducationCredential(String),
    
    // Behavior attestations
    TrustedTrader,
    ReliableCounterparty,
    GoodCitizen,
    
    // Verification attestations
    VerifiedEmail(Hash),
    VerifiedPhone(Hash),
    VerifiedAddress(Hash),
    BiometricHash(Hash),
}

pub struct AttestationContext {
    // Where/how the attestation was made
    pub location: Option<Location>,
    pub event: Option<String>,
    pub proof_of_interaction: Option<InteractionProof>,
    pub metadata: Map<String, String>,
}

Trust Computation

impl IdentityCRDT {
    // Calculate trust between two identities
    pub fn calculate_trust(
        &self,
        source: IdentityId,
        target: IdentityId,
        claim_type: ClaimType,
        params: TrustParams,
    ) -> TrustScore {
        // Find all paths from source to target
        let paths = self.find_trust_paths(source, target, params.max_depth);
        
        if paths.is_empty() {
            return TrustScore::Unknown;
        }
        
        // Weight paths by:
        // - Length (shorter = better)
        // - Attestation confidence
        // - Recency
        // - Path diversity
        let weighted_scores: Vec<f64> = paths
            .iter()
            .map(|path| self.score_path(path, claim_type, params))
            .collect();
        
        // Aggregate using params.aggregation_method
        let final_score = match params.aggregation_method {
            AggregationMethod::Maximum => weighted_scores.max(),
            AggregationMethod::Average => weighted_scores.average(),
            AggregationMethod::Median => weighted_scores.median(),
            AggregationMethod::WeightedByDiversity => {
                self.diversity_weighted_aggregate(paths, weighted_scores)
            }
        };
        
        TrustScore {
            value: final_score,
            confidence: self.calculate_confidence(paths.len(), weighted_scores.variance()),
            paths_found: paths.len(),
            computation_time: timestamp(),
        }
    }
    
    fn score_path(
        &self,
        path: &TrustPath,
        claim_type: ClaimType,
        params: &TrustParams,
    ) -> f64 {
        let mut score = 1.0;
        
        for edge in &path.edges {
            let attestation = &self.attestations[&edge.attestation_id];
            
            // Confidence factor
            score *= (attestation.confidence as f64) / 100.0;
            
            // Recency factor
            let age = timestamp() - attestation.timestamp;
            score *= params.recency_decay.decay_factor(age);
            
            // Claim type relevance
            score *= params.claim_relevance(attestation.claim_type, claim_type);
            
            // Penalize long paths
            score *= params.path_length_penalty.pow(path.edges.len());
        }
        
        score
    }
}

Sybil Resistance Mechanisms

pub struct SybilDetector {
    // Network topology analysis
    pub min_clustering_coefficient: f64,
    pub max_betweenness_centrality: f64,
    pub min_attestation_diversity: f64,
    
    // Temporal analysis
    pub min_account_age: Duration,
    pub max_attestation_rate: f64,
    
    // Behavioral analysis
    pub interaction_requirements: InteractionRequirements,
}

impl SybilDetector {
    pub fn analyze_identity(&self, id: IdentityId, graph: &IdentityCRDT) -> SybilScore {
        let mut score = SybilScore::default();
        
        // 1. Graph topology checks
        score.clustering = self.check_clustering(id, graph);
        score.centrality = self.check_centrality(id, graph);
        
        // 2. Attestation pattern checks
        score.attestation_diversity = self.check_attestation_diversity(id, graph);
        score.temporal_distribution = self.check_temporal_patterns(id, graph);
        
        // 3. Interaction proof checks
        score.interaction_quality = self.check_interactions(id, graph);
        
        // 4. Economic cost analysis
        score.attack_cost = self.estimate_attack_cost(id, graph);
        
        score
    }
    
    fn check_clustering(&self, id: IdentityId, graph: &IdentityCRDT) -> f64 {
        // Real social networks have high clustering
        // Sybil networks tend to be tree-like
        let neighbors = graph.get_neighbors(id);
        let interconnections = graph.count_edges_between(neighbors);
        let possible_connections = neighbors.len() * (neighbors.len() - 1) / 2;
        
        interconnections as f64 / possible_connections as f64
    }
}

Use Cases

1. Decentralized KYC/AML

pub struct DecentralizedKYC {
    required_attestations: Vec<RequiredAttestation>,
    trust_threshold: f64,
    approved_issuers: Option<Set<IdentityId>>,
}

pub struct RequiredAttestation {
    claim_types: Vec<ClaimType>,
    min_confidence: u8,
    max_age: Duration,
    min_paths: usize,
}

impl DecentralizedKYC {
    pub fn verify_identity(
        &self,
        identity: IdentityId,
        graph: &IdentityCRDT,
        verifier: IdentityId,
    ) -> KYCResult {
        let mut results = Vec::new();
        
        for requirement in &self.required_attestations {
            let attestations = graph.find_attestations(
                identity,
                &requirement.claim_types,
                verifier,
            );
            
            let valid_attestations = attestations
                .filter(|a| a.confidence >= requirement.min_confidence)
                .filter(|a| a.age() <= requirement.max_age)
                .filter(|a| self.is_approved_issuer(a.issuer))
                .collect::<Vec<_>>();
            
            results.push(RequirementResult {
                requirement: requirement.clone(),
                found: valid_attestations.len(),
                required: requirement.min_paths,
                passed: valid_attestations.len() >= requirement.min_paths,
            });
        }
        
        KYCResult {
            identity,
            passed: results.iter().all(|r| r.passed),
            details: results,
            timestamp: timestamp(),
        }
    }
}

2. Reputation-Based Governance

pub struct ReputationGovernance {
    // Different reputation types have different weights
    reputation_weights: Map<ClaimType, f64>,
    
    // Minimum reputation for participation
    participation_threshold: f64,
    
    // How reputation translates to voting power
    power_curve: PowerCurve,
}

impl ReputationGovernance {
    pub fn calculate_voting_power(
        &self,
        voter: IdentityId,
        graph: &IdentityCRDT,
        context: &GovernanceContext,
    ) -> VotingPower {
        let mut weighted_reputation = 0.0;
        
        // Aggregate different types of reputation
        for (claim_type, weight) in &self.reputation_weights {
            let reputation = graph.calculate_reputation(
                voter,
                claim_type.clone(),
                &context.reputation_params,
            );
            
            weighted_reputation += reputation.value * weight;
        }
        
        // Check participation threshold
        if weighted_reputation < self.participation_threshold {
            return VotingPower::Ineligible;
        }
        
        // Apply power curve (e.g., quadratic)
        let power = self.power_curve.apply(weighted_reputation);
        
        VotingPower::Eligible {
            power,
            reputation_score: weighted_reputation,
            calculation_method: self.power_curve.description(),
        }
    }
}

3. Social Recovery

pub struct SocialRecovery {
    pub identity: IdentityId,
    pub recovery_threshold: usize,
    pub guardians: Vec<Guardian>,
    pub time_delay: Duration,
}

pub struct Guardian {
    pub identity: IdentityId,
    pub relationship: ClaimType,
    pub min_relationship_age: Duration,
    pub weight: u32,
}

impl SocialRecovery {
    pub fn initiate_recovery(
        &self,
        new_key: PublicKey,
        guardian_signatures: Vec<GuardianSignature>,
        graph: &IdentityCRDT,
    ) -> Result<RecoveryRequest> {
        // Verify guardians
        let mut total_weight = 0u32;
        let mut verified_guardians = Vec::new();
        
        for sig in guardian_signatures {
            // Check guardian is valid
            let guardian = self.guardians
                .iter()
                .find(|g| g.identity == sig.guardian)
                .ok_or("Unknown guardian")?;
            
            // Verify relationship still exists
            let relationship = graph.verify_relationship(
                self.identity,
                guardian.identity,
                guardian.relationship.clone(),
            )?;
            
            // Check relationship age
            if relationship.age() < guardian.min_relationship_age {
                return Err("Relationship too new");
            }
            
            // Verify signature
            sig.verify(&new_key)?;
            
            total_weight += guardian.weight;
            verified_guardians.push(sig.guardian);
        }
        
        // Check threshold
        if verified_guardians.len() < self.recovery_threshold {
            return Err("Insufficient guardians");
        }
        
        Ok(RecoveryRequest {
            identity: self.identity,
            new_key,
            guardians: verified_guardians,
            initiated_at: timestamp(),
            executable_at: timestamp() + self.time_delay,
        })
    }
}

4. Skill-Based Matching

pub struct SkillMarketplace {
    pub skill_graph: IdentityCRDT,
    pub matching_params: MatchingParams,
}

impl SkillMarketplace {
    pub fn find_providers(
        &self,
        seeker: IdentityId,
        required_skills: Vec<Skill>,
        preferences: MatchingPreferences,
    ) -> Vec<SkillMatch> {
        let mut candidates = Vec::new();
        
        // Find all identities with required skills
        for skill in &required_skills {
            let providers = self.skill_graph.find_by_claim(
                ClaimType::TechnicalSkill(skill.name.clone()),
                preferences.min_confidence,
            );
            
            for provider in providers {
                // Calculate trust path from seeker
                let trust = self.skill_graph.calculate_trust(
                    seeker,
                    provider.identity,
                    ClaimType::TechnicalSkill(skill.name.clone()),
                    preferences.trust_params.clone(),
                );
                
                // Check if meets minimum trust
                if trust.value >= preferences.min_trust {
                    candidates.push(SkillMatch {
                        provider: provider.identity,
                        skill: skill.clone(),
                        trust_score: trust.value,
                        attestations: provider.attestations,
                        estimated_rate: self.estimate_rate(&provider, skill),
                    });
                }
            }
        }
        
        // Sort by preference
        candidates.sort_by(|a, b| {
            preferences.ranking_function(a, b)
        });
        
        candidates
    }
}

Privacy Features

1. Selective Disclosure

pub struct PrivateAttestation {
    // Public part
    pub id: AttestationId,
    pub issuer: IdentityId,
    pub subject_commitment: Commitment,
    pub claim_type: ClaimType,
    pub timestamp: Timestamp,
    
    // Private part (revealed selectively)
    pub private_data: EncryptedData,
    pub reveal_key: Option<RevealKey>,
}

impl PrivateAttestation {
    pub fn reveal_to(&self, recipient: IdentityId) -> RevealToken {
        // Generate reveal token for specific recipient
        let token = RevealToken {
            attestation_id: self.id,
            recipient,
            expiry: timestamp() + Duration::hours(24),
            scope: RevealScope::FullClaim,
        };
        
        token.encrypt_for(recipient)
    }
}

2. Zero-Knowledge Proofs

pub struct ZKIdentityClaim {
    // Prove properties without revealing identity
    pub proof: ZKProof,
    pub public_inputs: PublicInputs,
    pub nullifier: Nullifier, // Prevent double-usage
}

impl IdentityCRDT {
    pub fn prove_reputation_threshold(
        &self,
        identity: IdentityId,
        threshold: f64,
        claim_type: ClaimType,
    ) -> ZKIdentityClaim {
        // Generate proof that reputation > threshold
        // without revealing actual reputation or identity
        let witness = self.gather_reputation_witness(identity, claim_type);
        let proof = generate_zk_proof(witness, threshold);
        
        ZKIdentityClaim {
            proof,
            public_inputs: PublicInputs { threshold, claim_type },
            nullifier: derive_nullifier(identity, timestamp()),
        }
    }
}

Implementation Guide

Starting an Identity Network

// 1. Initialize identity
const identity = new Identity({
    publicKey: await generateKeypair(),
    profile: {
        displayName: "Alice",
        avatar: "ipfs://...",
    },
});

// 2. Create initial attestations
await identity.attestTo({
    subject: "bob.eth",
    claimType: "KnowsPersonally",
    confidence: 95,
    context: {
        event: "ETH Denver 2024",
        proof: interactionProof,
    },
});

// 3. Join identity network
const network = new IdentityNetwork({
    bootstrapPeers: ["peer1", "peer2"],
    storage: new IPFSStorage(),
});

await network.publishIdentity(identity);
await network.syncAttestations();

Building Trust Relationships

// Organic trust building
async function buildTrust() {
    // 1. Attend events and meet people
    const eventAttestations = await collectEventAttestations("ETH Denver");
    
    // 2. Work on projects together  
    const projectAttestations = await collaborateOnProject({
        project: "DeFi Protocol",
        teammates: ["carol.eth", "dave.eth"],
        duration: "3 months",
    });
    
    // 3. Trade/interact on-chain
    const onChainAttestations = await generateFromOnChain({
        interactions: getOnChainInteractions(),
        threshold: 5, // minimum interactions
    });
    
    // 4. Publish attestations
    await network.publishBatch([
        ...eventAttestations,
        ...projectAttestations,
        ...onChainAttestations,
    ]);
}

Consuming Identity Data

// For applications
class IdentityConsumer {
    constructor(
        private network: IdentityNetwork,
        private requirements: TrustRequirements,
    ) {}
    
    async verifyUser(userId: string): Promise<VerificationResult> {
        // 1. Calculate trust from your perspective
        const trust = await this.network.calculateTrust(
            this.identity,
            userId,
            this.requirements.claimTypes,
        );
        
        // 2. Check Sybil resistance
        const sybilScore = await this.network.getSybilScore(userId);
        
        // 3. Verify specific claims if needed
        const claims = await this.network.getAttestations(
            userId,
            this.requirements.requiredClaims,
        );
        
        return {
            trusted: trust.value > this.requirements.minTrust,
            sybilRisk: sybilScore.risk,
            verifiedClaims: claims,
        };
    }
}

Conclusion

BFT-CRDT identity networks solve the fundamental paradox of decentralized identity:

  • No Central Authority: Trust emerges from the network
  • Sybil Resistant: Graph analysis detects fake identities
  • Privacy Preserving: Selective disclosure and ZK proofs
  • Contextual: Different apps interpret trust differently
  • Organic Growth: Builds on natural human relationships

This enables:

  • Truly decentralized social networks
  • Reputation-based lending without credit scores
  • Skills marketplaces without centralized platforms
  • Democratic governance beyond token-voting
  • Social recovery that actually works

The key insight: Identity is not a binary state but a graph of relationships that can be interpreted contextually while remaining resistant to attacks.