Skip to content
Agentmart
Submit a tool

constant-time-analysis

Detects timing side-channel vulnerabilities in cryptographic code.

Skill by trailofbits

IndexedCC-BY-SA-4.0★ 7,783
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/trailofbits-constant-time-analysis

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Detects timing side-channel vulnerabilities in cryptographic code. Use when implementing or reviewing crypto code, encountering division on secrets, secret-dependent branches, or constant-time programming questions in C, C++, Go, Rust, Swift, Java, Kotlin, C#, PHP, JavaScript, TypeScript, Python, or Ruby.

Use cases: security, finance

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/constant-time-analysis

Tools it pre-approves 4

From allowed-tools in SKILL.md: the agent may use these without asking you each time.

  • Bash
  • Read
  • Grep
  • Glob

What's inside

Skill name
constant-time-analysis
Description
Detects timing side-channel vulnerabilities in cryptographic code. Use when implementing or reviewing crypto code, encountering division on secrets, secret-dependent branches, or constant-time programming questions in C, C++, Go, Rust, Swift, Java, Kotlin, C#, PHP, JavaScript, TypeScript, Python, or Ruby.
License
CC-BY-SA-4.0
Allowed tools
Bash, Read, Grep, Glob
Instructions
180 lines in SKILL.md · view on GitHub

Before installing

  • Pre-approves any shell command

Files (12)

  • README.md
  • SKILL.md
  • openai.yaml · agents/
  • trail-of-bits-mark.svg · assets/
  • compiled.md · references/
  • javascript.md · references/
  • kotlin.md · references/
  • php.md · references/
  • python.md · references/
  • ruby.md · references/
  • swift.md · references/
  • vm-compiled.md · references/

SKILL.md (first lines)

# Constant-Time Analysis

Compile the code, inspect the emitted assembly or bytecode for variable-time instructions, then decide which of the flagged operations actually touch secrets. The compilation step is mechanical; the triage step is the work.

## When to Use

- Implementing or reviewing a signature, encryption, KEM, or key derivation routine
- Code applies `/` or `%` to a value derived from a key, plaintext, nonce, or token
- The user mentions "constant-time", "timing attack", "side-channel", or "KyberSlash"
- Reviewing functions named `sign`, `verify`, `encrypt`, `decrypt`, `derive_key`

## When NOT to Use

- **Measuring** timing variance on a running binary — use the `constant-time-testing` skill from the `testing-handbook-skills` plugin, which covers dudect and statistical approaches and may not be installed. This skill inspects compiler output statically and never executes the code under test.
- Non-cryptographic code, or crypto code where every input is public
- High-level API usage where a vetted library owns the constant-time guarantees
- Cache and other microarchitectural side channels — the assembly view cannot see them

## Language Routing

Read the guide for the target language before interpreting any findings; each one lists that language's dangerous instructions and the idiomatic constant-time replacements.

| Guide | Languages |
| ----- | --------- |
| [references/compiled.md](references/compiled.md) | C, C++, Go, Rust |
| [references/swift.md](references/swift.md) | Swift |
| [references/vm-compiled.md](references/vm-compiled.md) | Java, C# |
| [references/kotlin.md](references/kotlin.md) | Kotlin |
| [references/php.md](references/php.md) | PHP |
| [references/javascript.md](references/javascript.md) | JavaScript, TypeScript |
| [references/python.md](references/python.md) | Python |
| [references/ruby.md](references/ruby.md) | Ruby |

## Running the Analyzer

The analyzer takes one file and detects the language from its extension. **Always pass `--warnings`:**

```bash
uv run {baseDir}/ct_analyzer/analyzer.py --warnings <source_file>
```

Without it the analyzer reports only error-severity findings, which means division, modulo and weak RNG. Four detector families are warning severity and stay silent: secret-dependent branches, early-exit comparison (`memcmp`, `strcmp`, `.equals`, `==`), table lookups indexed by a secret, and variable-time encoding. Early-exit comparison of an authentication tag is the most common timing bug in real code — Lucky Thirteen was exactly that — so a default run is quiet about the finding you are most likely to have.

| Flag | Effect |
| ---- | ------ |
| `--warnings` | Add the four warning-severity families above. Pass it every time |
| `--func <regex>` | Restrict output to function names matching the regex |
| `--json` | Machine-readable output |
| `--github` | GitHub Actions annotations |
| `--arch <target>` | Target architecture (`x86_64`, `arm64`, `riscv64`, ...) — native languages only |
| `--opt-level <level>` | Optimization level (`O0` through `O3`, `Os`, `Oz`) — native languages only |
| `--compiler <name>` | Override compiler choice (`gcc`, `clang`, `go`, `rustc`, `swiftc`) |

Narrow a large file to the routines that handle secrets with a regex, for example `--func 'sign|verify'`.

**Run natively compiled code (C, C++, Go, Rust, Swift) at more than one `--arch` and `--opt-level`.** Division timing and branch lowering are architecture- and optimization-dependent: x86_64 `IDIV` and arm64 `SDIV` differ, and a `cmov` at `-O2` can become a branch at `-O0`. A single clean run proves one configuration safe, not the code.

**How `--arch` crosses depends on the toolchain.** clang crosses with `--target` and needs no second compiler, but any source that includes libc headers also needs that target's C library headers — `libc6-dev-riscv64-cross` and friends — or it fails with `bits/libc-header-start.h file not found`. Go cross-builds through `GOARCH`, though `go tool objdump` has no riscv64 disassembler. A GNU cross toolchain is a *separate binary*, so gcc needs it named explicitly — `--compiler x86_64-linux-gnu-gcc`, `--compiler riscv64-linux-gnu-gcc` — and nothing is substituted for you, so the report always names the binary that ran. rustc needs the target's standard library (`rustup target add`), and Swift on Linux targets only the host. Compare against the toolchain that builds your product, not whichever cross build a distribution packages.

**Re-run the whole sweep on the fix, across compilers, targets and every level including `Os` and `Oz`.** Any fix that works by handing the compiler a constant divisor to strength-reduce is a fix only where the compiler chooses to cooperate, and that choice varies more than it looks. Replacing `key_coef / (2 * gamma2)` with a `#define`d divisor still emits a real divide here:

| Toolchain | Levels that emit a division |
| --------- | --------------------------- |
| gcc riscv64 | `O0` through `Oz` — every level |
| gcc arm64, gcc x86_64 | `Os`, `Oz` |
| clang arm64 | `O0`, `Oz` |

Strength reduction is an optimizer courtesy, not a language guarantee. Prefer an explicit multiply-shift, and verify it against the original expression over the full input range rather than on sampled values — an off-by-a-power-of-two reciprocal matches for millions of inputs before it diverges.

Java, Kotlin, and C# compile to JVM/CIL bytecode. The analyzer reads that bytecode, so `--arch` and `--opt-level` do not apply and the JIT may still introduce variable-time native code the analyzer cannot see.

### Per-language coverage limits

Coverage is not uniform, and the gaps change what a clean report means:

| Language | What the report does not cover |
| -------- | ------------------------------ |
| Go | Only symbols from the analyzed file. `go build` links the runtime in, and its divisions — all on public data — would otherwise dominate the findings |
| JavaScript, TypeScript | Bytecode findings are restricted to functions the file declares by name, because V8 dumps node's internals the same way it dumps yours. Anonymous callbacks fall to the source scan. For TypeScript, bytecode findings name the function but carry no line, since V8's positions index the transpiled output |
| Python, Ruby, PHP | Bytecode reflects the interpreter that ran, not a JIT'd or alternative runtime |
| Rust | Analyzed as a library unless the file declares `fn main`; private functions with no caller may be optimized away before analysis |
| Swift | Targets the host platform on Linux; iOS and macOS triples need an Apple toolchain |

Since findings and silence both depend on the configuration, say which compiler, architecture, and optimization level produced a result when reporting it.

To sweep a directory, loop in the shell — the analyzer is a deterministic script, one invocation per file:

```bash
for f in src/crypto/*.c; do uv run {baseDir}/ct_analyzer/analyzer.py --warnings --json "$f"; done
```

### Prerequisites

| Language | Requirement |
| -------- | ----------- |
| C, C++, Go, Rust | `gcc`/`clang`, `go`, `rustc` in PATH |
| Swift | Xcode or Swift toolchain (`swiftc`) |
| Java / Kotlin | JDK (`javac`, `javap`); Kotlin also needs `kotlinc` |
| C# | .NET SDK plus `ilspycmd` (`dotnet tool install -g ilspycmd`) |
| PHP | PHP with the VLD extension or OPcache |
| JavaScript / TypeScript | Node.js |
| Python | Python 3.x |
| Ruby | Ruby with `--dump=insns` support |

On a "toolchain not found" error, see [references/vm-compiled.md](references/vm-compiled.md) for JVM and .NET installation, macOS keg-only PATH configuration, and troubleshooting.

## Interpreting Results

**PASSED** — no *error*-severity finding for the configuration you ran. Warnings do not affect it, so `Result: PASSED` alongside `Warnings: 6` is normal and is not a clean result. Read the warning list before concluding anything.

**FAILED** — dangerous instructions found, reported per function:

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

## Triaging Findings

From trailofbits/skills, CC-BY-SA-4.0.

More from trailofbits/skills

Signals

Stars
7,783
Forks
671
Open issues
30
Last commit (this folder)
Sep 16, 2026 (1 month ago)

From GitHub (fetched Oct 24, 2026).

Details

License
CC-BY-SA-4.0
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from trailofbits

Cite this page

constant-time-analysis skill. Agent Mart. https://agentmart.dev/skills/trailofbits-constant-time-analysis (last updated 2026-10-24)