663 lines
19 KiB
Markdown
663 lines
19 KiB
Markdown
# 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.** |