All skills
Skillintermediate

Constant-Time Analyzer (ct-analyzer)

A portable tool for detecting timing side-channel vulnerabilities in compiled cryptographic code. Analyzes assembly output from multiple compilers and architectures to detect instructions that could leak secret data through execution timing.

Claude Code Knowledge Pack7/10/2026

Overview

Constant-Time Analyzer (ct-analyzer)

A portable tool for detecting timing side-channel vulnerabilities in compiled cryptographic code. Analyzes assembly output from multiple compilers and architectures to detect instructions that could leak secret data through execution timing.

Background

Timing side-channel attacks exploit variations in execution time to extract secret information from cryptographic implementations. Common sources include:

  • Hardware division (DIV, IDIV): Execution time varies based on operand values
  • Floating-point operations (FDIV, FSQRT): Variable latency based on inputs
  • Conditional branches: Different execution paths have different timing

The infamous KyberSlash attack demonstrated how division instructions in post-quantum cryptographic implementations could be exploited to recover secret keys.

Features

  • Multi-language support: C, C++, Go, Rust, PHP, JavaScript, TypeScript, Python, Ruby
  • Multi-architecture support: x86_64, ARM64, ARM, RISC-V, PowerPC, s390x, i386
  • Multi-compiler support: GCC, Clang, Go compiler, Rustc
  • Scripting language support: PHP (VLD/opcache), JavaScript/TypeScript (V8 bytecode), Python (dis), Ruby (YARV)
  • Optimization-level testing: Test across O0-O3, Os, Oz
  • Multiple output formats: Text, JSON, GitHub Actions annotations
  • Cross-compilation: Analyze code for different target architectures

Quick Start

# Install
uv pip install -e .

# Analyze a C file
ct-analyzer crypto.c

Usage

Basic Analysis

ct-analyzer <source_file>

Options

OptionDescription
--arch, -aTarget architecture (x86_64, arm64, arm, riscv64, ppc64le, s390x, i386)
--compiler, -cCompiler to use (gcc, clang, go, rustc)
--opt-level, -OOptimization level (O0, O1, O2, O3, Os, Oz) - default: O2
--warnings, -wInclude conditional branch warnings
--func, -fRegex pattern to filter functions
--jsonOutput JSON format
--githubOutput GitHub Actions annotations
--list-archList supported architectures

Examples

# Test with different optimization levels
ct-analyzer --opt-level O0 crypto.c
ct-analyzer --opt-level O3 crypto.c

# Cross-compile for ARM64
ct-analyzer --arch arm64 crypto.c

# Include conditional branch warnings
ct-analyzer --warnings crypto.c

# Analyze specific functions
ct-analyzer --func 'decompose|sign' crypto.c

# JSON output for CI
ct-analyzer --json crypto.c

# Analyze Go code
ct-analyzer crypto.go

# Analyze Rust code
ct-analyzer crypto.rs

# Analyze PHP code (requires PHP with VLD extension or opcache)
ct-analyzer crypto.php

# Analyze TypeScript (transpiles to JS first)
ct-analyzer crypto.ts

# Analyze JavaScript (uses V8 bytecode analysis)
ct-analyzer crypto.js

# Analyze Python (uses dis module for bytecode disassembly)
ct-analyzer crypto.py

# Analyze Ruby (uses YARV instruction dump)
ct-analyzer crypto.rb

Detected Vulnerabilities

Error-Level (Must Fix)

Categoryx86_64ARM64RISC-V
Integer DivisionDIV, IDIV, DIVQ, IDIVQUDIV, SDIVDIV, DIVU, REM, REMU
FP DivisionDIVSS, DIVSD, DIVPS, DIVPDFDIVFDIV.S, FDIV.D
Square RootSQRTSS, SQRTSD, SQRTPS, SQRTPDFSQRTFSQRT.S, FSQRT.D

Warning-Level (Review Needed)

Conditional branches that may leak timing if condition depends on secret data:

  • x86: JE, JNE, JZ, JNZ, JA, JB, JG, JL, etc.
  • ARM: BEQ, BNE, CBZ, CBNZ, TBZ, TBNZ
  • RISC-V: BEQ, BNE, BLT, BGE

Scripting Language Support

PHP Analysis

PHP analysis uses either the VLD extension (recommended) or opcache debug output:

Detected PHP Vulnerabilities:

CategoryPatternRecommendation
DivisionZEND_DIV, ZEND_MODUse Barrett reduction
Cache timingchr(), ord()Use pack('C', $int) / unpack('C', $char)[1]
Table lookupsbin2hex(), hex2bin(), base64_encode()Use constant-time alternatives
Array accessFETCH_DIM_R (secret index)Use constant-time table lookup
Bit shiftsZEND_SL, ZEND_SR (secret amount)Mask shift amount
Variable encodingpack(), serialize(), json_encode()Use fixed-length output
Weak RNGrand(), mt_rand(), uniqid()Use random_int() / random_bytes()
String comparisonstrcmp(), === on secretsUse hash_equals()

Installation:

# Install VLD extension (recommended)
# Query latest version from PECL
VLD_VERSION=$(curl -s https://pecl.php.net/package/vld | grep -oP 'vld-\\K[0-9.]+(?=\\.tgz)' | head -1)
pecl install channel://pecl.php.net/vld-${VLD_VERSION}

# Or build from source (if PECL fails)
git clone https://github.com/derickr/vld.git && cd vld
phpize && ./configure && make && sudo make install

# Or use opcache (built-in, fallback)
# Enabled by default in PHP 7+

JavaScript/TypeScript Analysis

JavaScript analysis uses V8 bytecode via Node.js --print-bytecode. TypeScript files are automatically transpiled first.

Detected JS Vulnerabilities:

CategoryPatternRecommendation
DivisionDiv, Mod bytecodesUse constant-time multiply-shift
Array accessLdaKeyedProperty (secret index)Use constant-time table lookup
Bit shiftsShiftLeft, ShiftRight (secret amount)Mask shift amount
Variable encodingTextEncoder, JSON.stringify(), btoa()Use fixed-length output
Weak RNGMath.random()Use crypto.getRandomValues() or crypto.randomBytes()
Variable latencyMath.sqrt(), Math.pow()Avoid in crypto paths
String comparison=== on secretsUse crypto.timingSafeEqual() (Node.js)
Early-exit searchindexOf(), includes()Use constant-time comparison

Requirements:

# Node.js required
node --version

# TypeScript compiler (optional, for .ts files)
npm install -g typescript

Python Analysis

Python analysis uses the built-in dis module to analyze CPython bytecode.

Detected Python Vulnerabilities:

CategoryPatternRecommendation
DivisionBINARY_OP 11 (/), BINARY_OP 6 (%)Use Barrett reduction or constant-time alternatives
Array accessBINARY_SUBSCR (secret index)Use constant-time table lookup
Bit shiftsBINARY_LSHIFT, BINARY_RSHIFT (secret amount)Mask shift amount
Variable encodingint.to_bytes(), json.dumps(), base64.b64encode()Use fixed-length output
Weak RNGrandom.random(), random.randint()Use secrets.token_bytes() / secrets.randbelow()
Variable latencymath.sqrt(), math.pow()Avoid in crypto paths
String comparison== on secretsUse hmac.compare_digest()
Early-exit search.find(), .startswith()Use constant-time comparison

Requirements:

# Python 3.x required (built-in dis module)
python3 --version

Ruby Analysis

Ruby analysis uses YARV (Yet Another Ruby VM) bytecode via ruby --dump=insns.

Detected Ruby Vulnerabilities:

CategoryPatternRecommendation
Divisionopt_div, opt_modUse constant-time alternatives
Array accessopt_aref (secret index)Use constant-time table lookup
Bit shiftsopt_lshift, opt_rshift (secret amount)Mask shift amount
Variable encodingpack(), to_json(), Base64.encode64()Use fixed-length output
Weak RNGrand(), Random.newUse SecureRandom.random_bytes()
Variable latencyMath.sqrt()Avoid in crypto paths
String comparison== on secretsUse Rack::Utils.secure_compare() or OpenSSL
Early-exit search.include?(), .start_with?()Use constant-time comparison

Requirements:

# Ruby required (YARV is standard since Ruby 1.9)
ruby --version

Example Output

============================================================
Constant-Time Analysis Report
============================================================
Source: decompose.c
Architecture: arm64
Compiler: clang
Optimization: O2
Functions analyzed: 4
Instructions analyzed: 88

VIOLATIONS FOUND:
----------------------------------------
[ERROR] SDIV
  Function: decompose_vulnerable
  Reason: SDIV has early termination optimization; execution time depends on operand values

[ERROR] SDIV
  Function: use_hint_vulnerable
  Reason: SDIV has early termination optimization; execution time depends on operand values

----------------------------------------
Result: FAILED
Errors: 2, Warnings: 0

Fixing Violations

Replace Division with Barrett Reduction

// VULNERABLE
int32_t q = a / divisor;

// SAFE: Barrett reduction
// Precompute: mu = ceil(2^32 / divisor)
uint32_t q = (uint32_t)(((uint64_t)a * mu) >> 32);

Replace Branches with Constant-Time Selection

// VULNERABLE
if (secret) {
    result = a;
} else {
    result = b;
}

// SAFE: Constant-time selection
uint32_t mask = -(uint32_t)(secret != 0);
result = (a & mask) | (b & ~mask);

Replace Comparisons

// VULNERABLE
if (memcmp(a, b, len) == 0) { ... }

// SAFE: Use crypto/subtle or equivalent
if (subtle.ConstantTimeCompare(a, b) == 1) { ... }

Test Samples

The repository includes test samples demonstrating vulnerable and secure implementations:

  • ct_analyzer/tests/test_samples/decompose_vulnerable.c - Vulnerable C implementation
  • ct_analyzer/tests/test_samples/decompose_constant_time.c - Constant-time C implementation
  • ct_analyzer/tests/test_samples/decompose_vulnerable.go - Vulnerable Go implementation
  • ct_analyzer/tests/test_samples/decompose_vulnerable.rs - Vulnerable Rust implementation
  • ct_analyzer/tests/test_samples/vulnerable.php - Vulnerable PHP implementation
  • ct_analyzer/tests/test_samples/vulnerable.ts - Vulnerable TypeScript implementation
  • ct_analyzer/tests/test_samples/vulnerable.py - Vulnerable Python implementation
  • ct_analyzer/tests/test_samples/vulnerable.rb - Vulnerable Ruby implementation

These implement the Decompose and UseHint algorithms from ML-DSA (FIPS-204) as test cases.

CI Integration

GitHub Actions

name: Constant-Time Check

on: [push, pull_request]

jobs:
  ct-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: |
          uv pip install -e .

      - name: Check constant-time properties
        run: |
          ct-analyzer --github src/crypto/*.c

GitLab CI

ct-check:
  stage: test
  script:
    - uv pip install -e .
    - ct-analyzer --json src/crypto/*.c > ct-report.json
  artifacts:
    reports:
      codequality: ct-report.json

Limitations

  1. Compiler Output Analysis: Analyzes what the compiler produces, not runtime behavior. Cannot detect:

    • Cache timing attacks from memory access patterns
    • Microarchitectural side-channels (Spectre, etc.)
    • Processor-specific optimizations
  2. No Data Flow Analysis: Flags all dangerous instructions regardless of whether they operate on secret data. Manual review is needed to determine if flagged code handles secrets. This means false positives are expected - for example, division used in loop bounds with public constants will be flagged even though it's not a vulnerability.

  3. False Positive Verification: For each flagged violation, verify the operands:

    • If operands are compile-time constants or public parameters → likely false positive
    • If operands are derived from keys, plaintext, or secrets → true positive
    • See the SKILL.md documentation for detailed triage guidance
  4. Compiler Variations: Different compilers/versions may produce different assembly. Test with:

    • Multiple optimization levels
    • Multiple compilers
    • Target production architectures
  5. Scripting Languages: PHP, JavaScript/TypeScript, Python, and Ruby are supported via bytecode analysis.

Running Tests

python3 ct_analyzer/tests/test_analyzer.py

References

Acknowledgments

Based on the test_ct utility created for ML-DSA.