Constant-Time Operations

All MetaMUI Crypto Primitives implementations use constant-time operations for secret-dependent code paths to prevent timing attacks.

What Are Timing Attacks?

Timing attacks exploit variations in execution time based on secret data:

Constant-Time Guarantees

Secret-Independent Execution

Implementation Techniques

Constant-Time Comparison

def constant_time_compare(a: bytes, b: bytes) -> bool:
    """Compare two byte arrays in constant time."""
    if len(a) != len(b):
        return False
    
    result = 0
    for x, y in zip(a, b):
        result |= x ^ y
    
    return result == 0

Constant-Time Selection

/// Select between two values without branching
fn ct_select(condition: bool, a: u32, b: u32) -> u32 {
    let mask = (condition as u32).wrapping_neg();
    (a & mask) | (b & !mask)
}

Constant-Time Modular Reduction

// Reduce without timing leaks
uint32_t ct_mod(uint64_t x, uint32_t p) {
    uint32_t q = (uint32_t)(x / p);
    uint32_t r = (uint32_t)(x - (uint64_t)q * p);
    
    // Constant-time correction
    uint32_t mask = (uint32_t)((r >= p) - 1);
    return r - (p & ~mask);
}

Algorithm-Specific Implementations

Ed25519

AES

ChaCha20

Poly1305

Post-Quantum Algorithms

Verification Methods

Static Analysis

# Check for timing leaks with tools
cargo install cargo-timing
cargo timing check

Runtime Testing

def test_constant_time_operation():
    """Test that operation time doesn't depend on input."""
    import time
    
    times = []
    for secret in generate_test_secrets():
        start = time.perf_counter_ns()
        operation(secret)
        end = time.perf_counter_ns()
        times.append(end - start)
    
    # Statistical analysis of timing variance
    assert variance(times) < threshold

Formal Verification

Platform Considerations

Compiler Optimizations

// Prevent optimization that might break constant-time
void secure_compare(const uint8_t *a, const uint8_t *b, size_t len) {
    volatile uint8_t result = 0;
    
    for (size_t i = 0; i < len; i++) {
        result |= a[i] ^ b[i];
    }
    
    return result == 0;
}

CPU Features

Language-Specific Issues

Python

JavaScript

Best Practices

  1. Never Branch on Secrets: Use masking instead of if statements
  2. Avoid Secret Indices: Don’t use secrets as array indices
  3. Complete All Operations: No early returns based on secrets
  4. Test Thoroughly: Verify constant-time properties
  5. Document Assumptions: Make timing assumptions explicit

Code Examples

Constant-Time Maximum

def ct_max(a: int, b: int) -> int:
    """Return maximum of a and b in constant time."""
    # Create mask: -1 if a > b, 0 otherwise
    diff = a - b
    mask = -(diff >> 31)  # Arithmetic shift
    
    # Select without branching
    return (a & mask) | (b & ~mask)

Constant-Time Conditional Copy

fn ct_copy(dest: &mut [u8], src: &[u8], condition: bool) {
    let mask = (condition as u8).wrapping_neg();
    
    for (d, s) in dest.iter_mut().zip(src.iter()) {
        *d = (*d & !mask) | (*s & mask);
    }
}

Testing Constant-Time Properties

import statistics
import time

def measure_timing_variance(operation, inputs):
    """Measure timing variance of an operation."""
    timings = []
    
    for inp in inputs:
        # Warm up
        for _ in range(100):
            operation(inp)
        
        # Measure
        times = []
        for _ in range(1000):
            start = time.perf_counter_ns()
            operation(inp)
            end = time.perf_counter_ns()
            times.append(end - start)
        
        timings.append(statistics.median(times))
    
    # Check variance is within acceptable bounds
    cv = statistics.stdev(timings) / statistics.mean(timings)
    assert cv < 0.01, f"High timing variance: {cv}"

See Also