The system uses a three-layer encrypted balance architecture:
encrypted_user_balances: Map<user_id, encrypted_balance>- User's personal encrypted balanceuser_balance_mappings: Map<encrypted_balance, actual_amount>- Public decryption lookup tableshared_balance_access: Map<auth_id, shared_encrypted_balance>- Authorization-specific balance sharing
// User's personal encryption key (PIN-based)
const user_key = persistentHash([pad(32, "user:balance:"), pin]);
// Balance encryption function
pure circuit encrypt_balance(balance: Uint<64>, encryption_key: Bytes<32>): Bytes<32> {
const encrypted = persistentHash([persistentHash(balance), encryption_key]);
return encrypted;
}
Issue: The user_balance_mappings ledger exposes a brute-forceable privacy layer.
- ✅ All balance amounts in the system (e.g., who has $100, $500, etc.)
- ✅ Balance distribution across users
- ✅ Number of users with each balance amount
- ❌ Direct userId → balance mapping (requires additional computation)
Risk Level: 🔴 HIGH for targeted attacks
Requirements:
- Know target user's
userId(publicly visible in authorization requests) - Computational resources for PIN brute force (4-6 digits = 10K-1M attempts)
- Access to
user_balance_mappingspublic ledger data
Attack Process:
// Target: Find Alice's balance
const targetUserId = "alice";
const observedBalances = [100, 500, 1000, 5000]; // From user_balance_mappings values
for (const pin of generatePinCombinations()) { // 0000-9999
const userKey = persistentHash([pad(32, "user:balance:"), pin]);
for (const balance of observedBalances) {
const encrypted = encrypt_balance(balance, userKey);
if (user_balance_mappings.has(encrypted)) {
// SUCCESS: Found Alice's PIN and balance
break;
}
}
}Risk Level: 🟡 MEDIUM for common PINs
Method:
- Pre-compute
encrypt_balance(balance, key)for common PINs and balance amounts - Match against
user_balance_mappingsentries - Discover balances for users with weak PINs ("1234", "0000", birth years)
Risk Level: 🟢 LOW privacy concern
Method:
- Analyze balance distribution patterns
- Identify economic trends or user behavior patterns
- Does not reveal individual user data
- ✅ Casual blockchain observers - Cannot easily link users to balances
- ✅ General analytics - Balance distribution analysis
- ✅ Strong PIN users - 6+ digit random PINs
- 🔴 Targeted investigations - Specific user balance discovery
- 🔴 Weak PIN users - Common patterns (1234, 0000, 1111)
- 🔴 Sophisticated attackers - With computational resources and user targeting
Implementation:
// Add unique salt per user
const user_salt = persistentHash([user_id, pad(32, "balance_salt")]);
const user_key = persistentHash([pad(32, "user:balance:"), pin, user_salt]);
Benefits:
- ✅ Prevents rainbow tables - Each user needs unique pre-computation
- ✅ Increases brute force cost - Attackers must target users individually
- ✅ Minimal code changes - Simple modification to existing system
- ✅ Backward compatible - Can migrate existing balances
Limitations:
- 🟡 Still vulnerable to targeted attacks - PIN brute force remains possible
- 🟡 Requires migration - Existing encrypted balances need re-encryption
Implementation:
// Remove user_balance_mappings entirely
// Store decrypted balances only in private state
witness user_balance(user_id: Bytes<32>): Uint<64>;
Benefits:
- ✅ Complete balance privacy - No public balance information
- ✅ No brute force vector - Cannot match encrypted keys to amounts
- ✅ Simple security model - Balances are private, period
Limitations:
- 🔴 Major architecture change - Requires significant contract modifications
- 🔴 Shared balance complexity - Authorization system needs redesign
- 🔴 Performance concerns - All balance operations require witness calls
Implementation:
- Use additive homomorphic encryption (e.g., Paillier cryptosystem)
- Allow balance operations without decryption
- Enable balance sharing without revealing exact amounts
Benefits:
- ✅ Strong cryptographic security - Computationally infeasible attacks
- ✅ Flexible operations - Can perform balance checks without decryption
- ✅ Future-proof - Resistant to computational advances
Limitations:
- 🔴 High complexity - Significant implementation overhead
- 🔴 Performance cost - Homomorphic operations are expensive
- 🔴 Library dependencies - May require external cryptographic libraries
Implementation:
- Use ZK-SNARKs for balance threshold proofs
- Users can prove "balance ≥ threshold" without revealing exact amount
- Eliminate need for encrypted balance sharing
Benefits:
- ✅ Perfect privacy - No balance information leakage
- ✅ Flexible verification - Supports complex balance conditions
- ✅ Cryptographically secure - Based on zero-knowledge proofs
Limitations:
- 🔴 Very high complexity - Requires ZK circuit development
- 🔴 Trusted setup - May require ceremony for some ZK systems
- 🔴 Performance overhead - Proof generation and verification costs
Target: Next release Solution: Implement user-specific salt (Solution 1) Effort: Low (1-2 days) Impact: Significantly reduces rainbow table and mass brute force attacks
Target: Future major version Solution: Evaluate Solution 2 (eliminate public mapping) Effort: High (1-2 weeks) Impact: Complete balance privacy, requires system redesign
Target: Future research Solutions: Homomorphic encryption or ZK proofs Effort: Very High (weeks/months) Impact: State-of-the-art privacy guarantees
- ✅ Adequate for disclosure use case - Disclosure is intentional and authorized
- ✅ Consistent security model - Same encryption patterns as authorization system
- ✅ Limited scope exposure - Only authorized parties gain access
- Implement Solution 1 (salt) before adding disclosure feature
- Apply same security model to disclosure permissions
- Document privacy trade-offs for users
- PIN brute force attack simulation
- Rainbow table effectiveness testing
- Balance correlation analysis
- Authorization system security audit
- Encryption key generation consistency
- PIN validation and storage
- Ledger data exposure patterns
- Private state management security
Document Version: 1.0
Last Updated: 2025-01-16
Next Review: Before implementing selective balance disclosure feature