Skip to content

Security: Femtech-web/Uniquity

Security

docs/SECURITY.md

πŸ” Security Model

This document outlines the security properties, threat model, and mitigations implemented in Uniquity.


Table of Contents

  1. Security Properties
  2. Threat Model
  3. Attack Vectors & Mitigations
  4. Trust Assumptions
  5. FHE Security
  6. Cryptographic Choices
  7. Known Limitations

Security Properties

Uniquity provides the following security guarantees:

1. Biometric Privacy

Property Guarantee
Confidentiality Biometric embeddings are never revealed to any party
No Linkability Cannot link verifications across platforms
No Reversibility Cannot reconstruct face from stored data

2. Submission Privacy

Property Guarantee
End-to-End Encryption Only admin can read submission content
Key Confidentiality AES keys protected by FHE
Unlinkability Cannot link submissions without decryption

3. Sybil Resistance

Property Guarantee Status
Uniqueness One verification per biometric identity πŸ”œ v2
Non-Transferability Credentials bound to wallet address βœ… v1
Temporal Validity Verification persists until revoked βœ… v1
Encrypted Storage Biometrics stored encrypted for future comparison βœ… v1

Note: In v1 (current), users are verified instantly. Uniqueness comparison will be enforced in v2 using off-chain FHE computation. Encrypted embeddings are stored now to enable this future comparison.


Threat Model

Actors

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        THREAT ACTORS                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Malicious User β”‚  β”‚ Network Observerβ”‚  β”‚ Malicious Admin β”‚ β”‚
β”‚  β”‚  ─────────────  β”‚  β”‚  ─────────────  β”‚  β”‚  ─────────────  β”‚ β”‚
β”‚  β”‚  β€’ Sybil attack β”‚  β”‚  β€’ Traffic      β”‚  β”‚  β€’ Data leak    β”‚ β”‚
β”‚  β”‚    (v2 mitigated)β”‚  β”‚    analysis     β”‚  β”‚  β€’ False reject β”‚ β”‚
β”‚  β”‚  β€’ Replay attackβ”‚  β”‚  β€’ Metadata     β”‚  β”‚  β€’ Collusion    β”‚ β”‚
β”‚  β”‚  β€’ Impersonationβ”‚  β”‚                 β”‚  β”‚                 β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚ Comparison Svc  β”‚  β”‚ Compromised Nodeβ”‚  β”‚ State Adversary β”‚ β”‚
β”‚  β”‚  (v2)           β”‚  β”‚  ─────────────  β”‚  β”‚  ─────────────  β”‚ β”‚
β”‚  β”‚  ─────────────  β”‚  β”‚  β€’ Data extract β”‚  β”‚  β€’ Coercion     β”‚ β”‚
β”‚  β”‚  β€’ Wrong result β”‚  β”‚  β€’ Manipulation β”‚  β”‚  β€’ Backdoor     β”‚ β”‚
β”‚  β”‚  β€’ Denial       β”‚  β”‚  β€’ Censorship   β”‚  β”‚  β€’ Surveillance β”‚ β”‚
β”‚  β”‚  β€’ Collusion    β”‚  β”‚                 β”‚  β”‚                 β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Assets Under Protection

  1. Biometric Embeddings - Most sensitive; never to be revealed
  2. Submission Content - Business sensitive; admin-only access
  3. AES Keys - Enables decryption; must be FHE-protected
  4. Verification Status - Public but manipulation-resistant
  5. User Privacy - Pseudonymity and unlinkability

Attack Vectors & Mitigations

1. Sybil Attacks

Vector: Creating multiple accounts with same biometric

Attacker ──▢ Extract face embedding
         ──▢ Modify slightly
         ──▢ Attempt multiple verifications

v1 Status: Not mitigated (instant verification without comparison)

v2 Mitigation:

  • Manhattan distance computed on encrypted values (off-chain)
  • Threshold (400,000) calibrated for reasonable variation
  • Cannot test distance before submission (encrypted)
  • Comparison service computes FHE distance without seeing plaintext
// v2: Distance comparison happens on encrypted values (off-chain)
// Service submits encrypted minDistance result
// User cannot manipulate the comparison

2. Replay Attacks

Vector: Reusing captured biometric data

Attacker ──▢ Capture victim's face image
         ──▢ Submit as own verification

Mitigation:

  • Liveness detection in face-api.js (blink, movement)
  • Input proof tied to specific user address
  • Timestamp validation on-chain
// Input is bound to user address
const input = fhevmInstance.createEncryptedInput(
  contractAddress,
  userAddress // Proof is specific to this address
);

3. Decryption Proof Manipulation (v2)

Vector: Submitting fake cleartext values with forged proof

Attacker ──▢ Observe publicDecrypt result
         ──▢ Modify cleartext (e.g., set distance = MAX_INT)
         ──▢ Submit fake value with original proof

Mitigation:

  • FHE.checkSignatures() cryptographically binds cleartext to ciphertext
  • KMS signatures cannot be forged without Zama's private keys
  • Proof is only valid for exact (handle, cleartext) pair
  • Order of handles matters - proof is order-dependent
function finalizeVerification(
    uint256 requestId,
    uint64 clearDistance,
    bytes calldata decryptionProof
) external {
    bytes32[] memory handles = new bytes32[](1);
    handles[0] = req.minDistanceHandle;
    bytes memory abiEncodedClear = abi.encode(clearDistance);

    // Reverts if proof doesn't match (clearDistance, handle) pair
    FHE.checkSignatures(handles, abiEncodedClear, decryptionProof);

    // Only reaches here if proof is valid
    // ...
}

4. Front-Running

Vector: Observing pending verification and racing to register

Attacker ──▢ Monitor mempool for proveHumanity()
         ──▢ Extract encrypted values (cannot decrypt)
         ──▢ ??? (no viable attack)

Mitigation:

  • Encrypted values cannot be reused (bound to address)
  • Even with same face, attacker's proof would be different
  • v2: Profile comparison happens against all existing profiles

5. Admin Key Compromise

Vector: Admin private key stolen, all submissions decrypted

Attacker ──▢ Steal admin key
         ──▢ Call getSubmissionKeyHandle()
         ──▢ userDecrypt all keys
         ──▢ Decrypt all submissions

Mitigation:

  • Per-campaign admin isolation
  • Compromise affects only that campaign's submissions
  • Cannot retroactively access other campaigns
  • Recommended: Use multisig for admin

6. Biometric Extraction from Contract

Vector: Extracting biometric data from on-chain storage

Attacker ──▢ Read contract storage
         ──▢ Extract euint64 chunks
         ──▢ ??? Decrypt ???

Mitigation:

  • Values are FHE-encrypted with network key
  • Only Zama KMS can decrypt
  • No party (including contract) can read plaintext
  • Chunks are meaningless without decryption

7. Traffic Analysis

Vector: Correlating on-chain activity with identity

Observer ──▢ Track wallet addresses
         ──▢ Correlate verification timing
         ──▢ Link to real identity

Mitigation:

  • Use fresh wallet for verification
  • Verification doesn't reveal which campaign
  • Submission content is encrypted

8. Comparison Service Manipulation (v2)

Vector: Malicious comparison service returns wrong distance

Attacker ──▢ Run compromised comparison service
         ──▢ Always return MAX_INT (everyone unique)
         ──▢ Or return 0 (everyone duplicate)

Mitigation:

  • Service cannot see decrypted biometrics (FHE)
  • All operations emit events for audit trail
  • Multiple services can verify each other
  • Future: ZK proofs of correct computation
  • Future: Zama coprocessor with cryptographic guarantees

Trust Assumptions

What We Trust

Component Trust Assumption Version
Zama KMS Correctly signs decryption proofs; won't forge signatures v1, v2
Zama Relayer Faithfully relays decryption requests to KMS v1, v2
FHE Security TFHE encryption is computationally secure v1, v2
checkSignatures Correctly verifies KMS signatures on-chain v2
face-api.js Provides accurate, consistent embeddings v1, v2
Browser Client-side code executes correctly v1, v2
IPFS Data availability (not confidentiality) v1, v2
Comparison Service Correctly computes FHE distance (auditable) v2

What We Don't Trust

Component Why
Blockchain Nodes Can't see encrypted data
Contract Owner No admin keys for Core contract
Campaign Admins Can only decrypt their campaign's submissions
Other Users Isolated by FHE permissions
Network All sensitive data encrypted in transit

Trust Minimization

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    TRUST HIERARCHY                              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  MAXIMUM TRUST                                                  β”‚
β”‚  ─────────────                                                  β”‚
β”‚  Zama FHE Network (KMS, Relayer, Coprocessor)                   β”‚
β”‚  β€’ KMS signs decryption proofs                                  β”‚
β”‚  β€’ checkSignatures verifies on-chain                            β”‚
β”‚    β”‚                                                            β”‚
β”‚    β–Ό                                                            β”‚
β”‚  HIGH TRUST (v2 only)                                           β”‚
β”‚  ─────────────                                                  β”‚
β”‚  Comparison Service (off-chain FHE computation)                 β”‚
β”‚  β€’ Computes encrypted distance                                  β”‚
β”‚  β€’ Cannot see plaintext (FHE)                                   β”‚
β”‚  β€’ Auditable via event logs                                     β”‚
β”‚    β”‚                                                            β”‚
β”‚    β–Ό                                                            β”‚
β”‚  MODERATE TRUST                                                 β”‚
β”‚  ──────────────                                                 β”‚
β”‚  User's Browser (executes client code)                          β”‚
β”‚  β€’ Calls publicDecrypt off-chain (v2)                           β”‚
β”‚  β€’ Submits proof on-chain (v2)                                  β”‚
β”‚    β”‚                                                            β”‚
β”‚    β–Ό                                                            β”‚
β”‚  MINIMAL TRUST                                                  β”‚
β”‚  ─────────────                                                  β”‚
β”‚  Blockchain (can't see encrypted data)                          β”‚
β”‚  IPFS (encrypted storage)                                       β”‚
β”‚  Campaign Admins (isolated access)                              β”‚
β”‚    β”‚                                                            β”‚
β”‚    β–Ό                                                            β”‚
β”‚  ZERO TRUST                                                     β”‚
β”‚  ──────────                                                     β”‚
β”‚  Other Users                                                    β”‚
β”‚  Network Observers                                              β”‚
β”‚  Contract Storage Readers                                       β”‚
β”‚                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

FHE Security

FHE Parameters

Uniquity uses Zama's fhEVM which implements FHE (Fully Homomorphic Encryption):

Parameter Value
Security Level 128-bit
Key Size Network-managed
Ciphertext Expansion ~8x
Supported Types euint8, euint16, euint32, euint64, euint256

Encrypted Operations Security

All FHE operations maintain semantic security:

// These operations never reveal plaintext
euint64 sum = FHE.add(a, b);      // a, b, sum all encrypted
ebool lt = FHE.lt(a, b);          // Result is encrypted boolean
euint64 result = FHE.select(lt, a, b);  // Encrypted selection

Permission Model

FHE permissions control who can decrypt:

// Grant permissions (critical for security)
FHE.allow(encryptedKey, campaign.admin);  // Admin can decrypt
FHE.allowThis(encryptedKey);              // Contract can operate
FHE.allow(encryptedKey, msg.sender);      // User can edit

// Without permission, decryption fails
// Even contract owner cannot bypass permissions

Cryptographic Choices

Why These Algorithms?

Algorithm Use Case Rationale
FHE Biometric storage & comparison (v2) Enables encrypted computation
AES-256-GCM Submission encryption Fast, authenticated encryption
SHA3-256 CID hashing Collision resistance for validation

Embedding Representation

Converting float32 embeddings to FHE-compatible format:

// Original: 128 Γ— float32 = 4096 bits
// Quantized: 4 Γ— uint64 = 256 bits
// Compression: 16x (with acceptable precision loss)

// Quantization preserves relative distances
// Tests show >95% correlation with original distances

Threshold Selection (v2)

SIMILARITY_THRESHOLD = 400,000

Calibrated to balance:
β”œβ”€β”€ False Positive Rate (same person rejected): < 1%
β”œβ”€β”€ False Negative Rate (different person accepted): < 0.1%
└── Lighting/angle tolerance: Β±15 degrees, Β±20% brightness

Bucket-based comparison reduces:
β”œβ”€β”€ Comparison scope: O(n/8) vs O(n)
└── Still maintains security (compare within bucket)

Known Limitations

v1 Limitations (Current)

  1. No Uniqueness Enforcement

    • Users verified instantly without comparison
    • Same person can verify with multiple wallets
    • Mitigation: Encrypted embeddings stored for v2 comparison
  2. Liveness Detection

    • Browser-based, could be spoofed with effort
    • Mitigation: Threshold distance catches most spoofs (v2)

v2 Limitations (Planned)

  1. KMS Trust

    • Decryption proofs rely on Zama KMS signatures
    • Mitigation: FHE.checkSignatures() cryptographically verifies
  2. Comparison Service Trust

    • Service must be trusted to compute correctly
    • Cannot see encrypted data (FHE protected)
    • Mitigation: Audit logs, multiple services, future ZK proofs
  3. Replay Protection

    • Same proof could theoretically be resubmitted
    • Mitigation: Track finalized requests; reject duplicates
  4. Bucket Collision

    • Users in same bucket compared together
    • Mitigation: 8 buckets distribute load evenly
  5. Comparison Latency

    • Off-chain FHE computation takes time (~10-30 seconds)
    • Mitigation: Async flow with status updates

Future Improvements

  1. Multi-Factor Verification

    • Add voice embedding
    • Combine multiple biometrics
  2. Decentralized Comparison

    • Replace single service with MPC network
    • Or use Zama coprocessor when available
    • No single point of trust
  3. ZK Proofs of Computation

    • Service generates ZK proof of correct FHE execution
    • Fully trustless comparison
  4. Revocation Mechanism

    • Allow users to revoke verification
    • Re-verify with updated biometrics
  5. Cross-Chain Verification

    • Portable credentials across chains
    • Bridge verified status

Security Audit Status

Component Status Notes
UniquityCore.sol πŸ”Ά Internal Review Pending external audit
UniquitySubmit.sol πŸ”Ά Internal Review Pending external audit
Client-side crypto πŸ”Ά Internal Review Uses standard libraries
FHE operations βœ… Zama Audited Part of fhEVM
Comparison Service πŸ”œ v2 Not yet implemented

Responsible Disclosure

If you discover a security vulnerability:

  1. Do NOT disclose publicly
  2. Email: bossfemzy10@gmail.com
  3. Include: Description, steps to reproduce, impact
  4. We will respond within 48 hours

There aren’t any published security advisories