# CAAS: The Audit System That Caught a Private Key Leak During a Platform Port

Leader posted 4 min read

I'll start with the bug that makes the case.

I was porting UltrafastSecp256k1 — my secp256k1 cryptographic library — to RISC-V. New architecture, new compiler behavior. The code compiled fine. Tests passed.

But the CT (constant-time) verification pipeline flagged something.

GCC on RISC-V was optimizing my constant-time field arithmetic into branches that depended on secret data. The RISC-V backend had different optimization behavior than x86-64. The result: timing side-channel. The kind that leaks private keys over many observations.

A traditional security audit, done on x86-64, would never have seen this. The audit report would say "constant-time: verified." The library would ship to RISC-V users with a subtle vulnerability.

My CAAS pipeline caught it in the same commit as the port. Fixed. Bug capsule created. Permanent regression test. Can never silently return.


What is CAAS?

Continuous Adversarial Audit System — a methodology for security-critical libraries where every security claim is backed by an executable test that runs on every commit.

The key word is continuous. Not "we audited it in March." On. Every. Commit.

For UltrafastSecp256k1, CAAS consists of:

Three independent CT verification pipelines:

  • ct-verif.yml — LLVM IR symbolic analysis. Analyzes at compile time whether any secret-bearing operation produces a branch or memory address visible in the IR.
  • valgrind-ct.yml — Runtime Valgrind taint propagation. Marks secret bytes as undefined at entry, runs the signing path, catches any branch or memory access derived from secret data.
  • ct-prover.yml — dudect statistical timing. Runs the operation thousands of times with different secret data and tests whether timing distributions are statistically distinguishable.

171 exploit PoC tests covering known CVE and academic attack classes. Each test is a standalone C++ file that actively tries to break the library. All run on every commit. None can be removed.

A bug capsule system:

{
  "id": "BUG-2026-0001",
  "category": "CT",  
  "severity": "critical",
  "title": "CT branch leak in ecdsa_sign_recoverable",
  "fix_commit": "0a93ff4b",
  "exploit_poc": true,
  "expected": { "result": "no_timing_leak" }
}

Run bug_capsule_gen.py and it generates a regression test, an exploit PoC, and CMake integration — automatically. The bug class is permanently sealed in CI.

A domain-specific static analyzer (dev_bug_scanner.py) with 28 rules that generic tools miss:

  • CT_VIOLATIONfast::scalar_mul() called in signing path (generic tools see valid C++; this is a side-channel)
  • SECRET_UNERASEDScalar variable without secure_erase on signing path exit
  • TAGGED_HASH_BYPASSsha256() where BIP-340 tagged_hash() is required
  • RANDOM_IN_SIGNING — non-deterministic RNG in RFC 6979 deterministic signing

~1,000,000+ assertions per build across 55 audit modules covering field arithmetic invariants, scalar operations, point group law, CT properties, and protocol-level correctness.


Full Reproducibility

Everything runs in Docker. Not "runs if you install the right toolchain." Runs with one command:

# Local CI with GitHub parity
docker compose -f docker-compose.ci.yml run --rm pre-push    # 5 min
docker compose -f docker-compose.ci.yml run --rm gh-parity   # full

# Auditor challenge environment
docker build -f Dockerfile.auditor -t ufsecp-auditor .
docker run --rm ufsecp-auditor

# Bit-for-bit reproducible build
docker build -f Dockerfile.reproducible -t uf-repro-check .
docker run --rm uf-repro-check  # compares two independent builds byte-for-byte

The auditor image includes libsecp256k1, @noble/secp256k1, coincurve, and python-ecdsa for differential testing — all hash-pinned. No setup required.


The CI Regression Baseline

The code quality pipeline uses a baseline model:

{
  "dev_bug_scanner": { "HIGH": 0, "MEDIUM": 138, "LOW": 234 },
  "hot_path_alloc_scanner": { "HIGH": 104, "MEDIUM": 44 }
}

CI doesn't require zero findings. It requires findings don't increase. This is mature engineering — existing technical debt acknowledged, new debt blocked. The 104 HIGH hot_path allocations are intentional for performance reasons. If a new commit adds one more HIGH finding, CI fails.


What Happens When You Fork This

You inherit the accumulated security knowledge of every platform port, every bug found, every academic paper evaluated:

  • RISC-V CT leak → caught → capsule → permanent
  • Metal field_reduce_512 truncation (affecting ~0.05% of inputs) → caught → capsule → permanent
  • OpenCL carry propagation bug → caught → capsule → permanent
  • CT branch leak in ECDSA signing low-s normalization → caught → capsule → permanent

A startup forking this doesn't spend six months building security infrastructure. They start from a system that has already caught the bugs above, with permanent regression tests for each.


Real-World Validation

Craig Raw integrated the library into Frigate for BIP-352 Silent Payments scanning. Real Bitcoin mainnet. Real transactions.

The GPU BIP-352 pipeline achieves 11 million operations per second on an RTX 5060 Ti. Frigate's real-world scan of two years of Bitcoin mainnet history (133M tweaks) completes in 3.2 seconds on 2× RTX 5090s.


What CAAS Doesn't Replace

To be direct:

  • No third-party audit yet. Documented openly. CAAS is designed to make one cheaper and faster when it happens.
  • GPU CT verification is code-discipline (branchless source) but not formally pipeline-verified — vendor JIT compilers transform kernels at runtime.
  • Novel, unknown attack classes have no prior test by definition.

Getting Started

git clone https://github.com/shrec/UltrafastSecp256k1.git
cd UltrafastSecp256k1

# Run the full audit suite locally
docker compose -f docker-compose.ci.yml run --rm pre-push

# Or directly
cmake -S . -B build -DSECP256K1_BUILD_AUDIT=ON && cmake --build build -j
ctest --test-dir build -L exploit -V  # run all exploit PoC tests

CAAS specification: docs/AUDIT_STANDARD.md

The audit infrastructure ships with the library. MIT licensed.

1 Comment

1 vote
1

More Posts

Tuesday Coding Tip 06 - Explicit template instantiation

Jakub Neruda - Apr 7

Tuesday Coding Tip 02 - Template with type-specific API

Jakub Neruda - Mar 10

Breaking the AI Data Bottleneck: How Hammerspace's AI Data Platform Eliminates Migration Nightmares

Tom Smithverified - Mar 16

React Native Quote Audit - USA

kajolshah - Mar 2

How I Built a React Portfolio in 7 Days That Landed ₹1.2L in Freelance Work

Dharanidharan - Feb 9
chevron_left

Related Jobs

View all jobs →

Commenters (This Week)

4 comments
3 comments
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!