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

663 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```typescript
// 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
```typescript
// 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
```typescript
// 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.**