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:
- Different code paths for different key bits
- Early returns based on comparisons
- Cache timing differences
- Branch prediction attacks
Constant-Time Guarantees
Secret-Independent Execution
- Same number of operations regardless of secret values
- No branching based on secret data
- No array indexing with secret indices
- No early returns in comparisons
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
- Montgomery ladder for scalar multiplication
- No secret-dependent array lookups
- Constant-time field operations
AES
- Constant-time S-box implementation
- No table lookups with secret indices
- Bitsliced implementations where possible
ChaCha20
- Fixed number of rounds
- No secret-dependent operations
- Constant-time quarter-round function
Poly1305
- Constant-time polynomial evaluation
- No early exits in MAC verification
- Constant-time modular arithmetic
Post-Quantum Algorithms
- ML-KEM-768: Constant-time NTT
- Dilithium: Constant-time rejection sampling
- Falcon-512: Constant-time floating-point operations
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
- Model checking for constant-time properties
- Symbolic execution to verify paths
- Automated proofs where applicable
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
- Avoid variable-time instructions
- Be aware of CPU-specific timing variations
- Test on multiple architectures
Language-Specific Issues
Python
- Use
secrets.compare_digest()for comparisons - Avoid short-circuit evaluation
- Be careful with integer operations
JavaScript
- No native constant-time operations
- Use WASM for critical paths
- Avoid timing-dependent optimizations
Best Practices
- Never Branch on Secrets: Use masking instead of if statements
- Avoid Secret Indices: Don’t use secrets as array indices
- Complete All Operations: No early returns based on secrets
- Test Thoroughly: Verify constant-time properties
- 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}"