Skip to content

Security: nel349/midnight-bank

Security

SECURITY.md

Midnight Bank Security Analysis

Balance Privacy Assessment

Current Balance Encryption System

The system uses a three-layer encrypted balance architecture:

  1. encrypted_user_balances: Map<user_id, encrypted_balance> - User's personal encrypted balance
  2. user_balance_mappings: Map<encrypted_balance, actual_amount> - Public decryption lookup table
  3. shared_balance_access: Map<auth_id, shared_encrypted_balance> - Authorization-specific balance sharing

Encryption Implementation

// 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;
}

Privacy Vulnerability Analysis

⚠️ Identified Security Concern: PIN-Based Balance Discovery

Issue: The user_balance_mappings ledger exposes a brute-forceable privacy layer.

What is Exposed:

  • All balance amounts in the system (e.g., who has $100, $500, etc.)
  • Balance distribution across users
  • Number of users with each balance amount

What is NOT Directly Exposed:

  • Direct userId → balance mapping (requires additional computation)

Attack Vectors

1. Targeted PIN Brute Force Attack

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_mappings public 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;
    }
  }
}

2. Rainbow Table Attack

Risk Level: 🟡 MEDIUM for common PINs

Method:

  • Pre-compute encrypt_balance(balance, key) for common PINs and balance amounts
  • Match against user_balance_mappings entries
  • Discover balances for users with weak PINs ("1234", "0000", birth years)

3. Statistical Balance Analysis

Risk Level: 🟢 LOW privacy concern

Method:

  • Analyze balance distribution patterns
  • Identify economic trends or user behavior patterns
  • Does not reveal individual user data

Risk Assessment by Scenario

Low Risk:

  • Casual blockchain observers - Cannot easily link users to balances
  • General analytics - Balance distribution analysis
  • Strong PIN users - 6+ digit random PINs

High Risk:

  • 🔴 Targeted investigations - Specific user balance discovery
  • 🔴 Weak PIN users - Common patterns (1234, 0000, 1111)
  • 🔴 Sophisticated attackers - With computational resources and user targeting

Proposed Security Enhancements

Solution 1: User-Specific Salt (Recommended)

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

Solution 2: Eliminate Public Mapping

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

Solution 3: Homomorphic Encryption

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

Solution 4: Zero-Knowledge Balance Proofs

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

Implementation Recommendations

Phase 1: Immediate Security Improvement

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

Phase 2: Long-term Architecture Review

Target: Future major version Solution: Evaluate Solution 2 (eliminate public mapping) Effort: High (1-2 weeks) Impact: Complete balance privacy, requires system redesign

Phase 3: Advanced Cryptography (Optional)

Target: Future research Solutions: Homomorphic encryption or ZK proofs Effort: Very High (weeks/months) Impact: State-of-the-art privacy guarantees

Impact on Selective Balance Disclosure Feature

Current Security Model Compatibility:

  • 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

Recommended Approach:

  1. Implement Solution 1 (salt) before adding disclosure feature
  2. Apply same security model to disclosure permissions
  3. Document privacy trade-offs for users

Security Testing Recommendations

Penetration Testing:

  • PIN brute force attack simulation
  • Rainbow table effectiveness testing
  • Balance correlation analysis
  • Authorization system security audit

Code Review Focus Areas:

  • 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

There aren’t any published security advisories