All skills
Skillintermediate

Constant-Time Analysis: Python

Analysis guidance for Python scripts. Uses the `dis` module to analyze CPython bytecode for timing-unsafe operations.

Claude Code Knowledge Pack7/10/2026

Overview

Constant-Time Analysis: Python

Analysis guidance for Python scripts. Uses the dis module to analyze CPython bytecode for timing-unsafe operations.

Prerequisites

  • Python 3.10+ (bytecode format varies by version)

Running the Analyzer

# Analyze Python file
uv run {baseDir}/ct_analyzer/analyzer.py crypto.py

# Include warning-level violations
uv run {baseDir}/ct_analyzer/analyzer.py --warnings crypto.py

# Filter to specific functions
uv run {baseDir}/ct_analyzer/analyzer.py --func 'encrypt|sign' crypto.py

# JSON output for CI
uv run {baseDir}/ct_analyzer/analyzer.py --json crypto.py

Dangerous Operations

Bytecodes (Errors)

Python < 3.11:

BytecodeIssue
BINARY_TRUE_DIVIDEVariable-time execution
BINARY_FLOOR_DIVIDEVariable-time execution
BINARY_MODULOVariable-time execution
INPLACE_TRUE_DIVIDEVariable-time execution
INPLACE_FLOOR_DIVIDEVariable-time execution
INPLACE_MODULOVariable-time execution

Python 3.11+:

BINARY_OP OpargOperationIssue
11/Variable-time execution
12//Variable-time execution
6%Variable-time execution
24/=Variable-time execution
25//=Variable-time execution
19%=Variable-time execution

Functions (Errors)

FunctionIssueSafe Alternative
random.random()Predictablesecrets.token_bytes()
random.randint()Predictablesecrets.randbelow()
random.randrange()Predictablesecrets.randbelow()
random.choice()Predictablesecrets.choice()
random.shuffle()PredictableCustom with secrets
random.sample()PredictableCustom with secrets
math.sqrt()Variable latencyAvoid in crypto
math.pow()Variable latencyAvoid in crypto
eval()Unpredictable timingAvoid entirely
exec()Unpredictable timingAvoid entirely

Functions (Warnings)

FunctionIssueSafe Alternative
str.find()Early-terminatingConstant-time search
str.index()Early-terminatingConstant-time search
str.startswith()Early-terminatinghmac.compare_digest()
str.endswith()Early-terminatinghmac.compare_digest()
in (strings)Early-terminatingConstant-time search
json.dumps()Variable-length outputFixed-length padding
json.loads()Variable-timeFixed-length input
base64.b64encode()Variable-length outputFixed-length padding
pickle.dumps()Variable-length outputAvoid for secrets
pickle.loads()Variable-time, security riskAvoid for secrets

Safe Patterns

String Comparison

# VULNERABLE: Early exit on mismatch
if user_token == stored_token:
    ...

# SAFE: Constant-time comparison

if hmac.compare_digest(user_token, stored_token):
    ...

# SAFE: For bytes

if secrets.compare_digest(user_bytes, stored_bytes):
    ...

Random Number Generation

# VULNERABLE: Predictable

token = random.randint(0, 2**128)

# SAFE: Cryptographically secure

token = secrets.token_bytes(16)
token_int = secrets.randbits(128)
random_index = secrets.randbelow(len(items))

Division Operations

# VULNERABLE: Division has variable timing
quotient = secret // divisor

# SAFE: Barrett reduction for constant divisors
# Precompute: mu = (1 << (2 * BITS)) // divisor
def barrett_reduce(value: int, divisor: int, mu: int, bits: int) -> int:
    q = (value * mu) >> (2 * bits)
    r = value - q * divisor
    # Constant-time correction
    mask = -(r >= divisor)
    return r - (divisor & mask)

Python Version Notes

Python 3.11+ Changes

Python 3.11 introduced the BINARY_OP bytecode that replaces individual binary operation bytecodes. The analyzer detects division/modulo by checking the oparg:

BINARY_OP               11 (/)    # True division
BINARY_OP               12 (//)   # Floor division
BINARY_OP                6 (%)    # Modulo

Python 3.10 and Earlier

Uses separate bytecodes:

BINARY_TRUE_DIVIDE
BINARY_FLOOR_DIVIDE
BINARY_MODULO

Cryptography Library Considerations

When using the cryptography library:

# The cryptography library handles constant-time internally
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

# SAFE: Library handles timing protection
aesgcm = AESGCM(key)
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data)

For custom cryptographic code, ensure you:

  1. Use hmac.compare_digest() for comparisons
  2. Use secrets module for randomness
  3. Avoid division/modulo on secret-derived values
  4. Use fixed-length data representations

Limitations

CPython Bytecode Only

The analyzer targets CPython bytecode. Alternative implementations (PyPy, Jython, etc.) have different bytecode formats and timing characteristics.

JIT Compilation

PyPy and Numba can JIT-compile Python to native code with potentially different timing behavior. Consider additional analysis for JIT-compiled code paths.