pull down to refresh

Audit Runner: unified_audit_runner
Verdict: AUDIT-READY -- 55/55 modules passed
Total Checks: ~1,000,000+ (audit) + 1.3M+ (nightly differential)
Runtime: ~36.5 seconds (X64, Clang 21.1.0, Release)


SummarySummary

MetricValue
Audit Sections8
Audit Modules55 (54 + parse strictness)
Audit assertions~1,000,000+ (parser fuzz 530K, CT deep 120K, field Fp 264K, ZK ~1.5K, ...)
Nightly differential~1,300,000+ additional random checks (daily)
CI Workflows23 GitHub Actions workflows
CI Build Matrix17 configurations, 7 architectures, 5 OSes
SanitizersASan+UBSan, TSan, Valgrind memcheck
Fuzzing3 libFuzzer harnesses + 530K deterministic
Static AnalysisCodeQL, SonarCloud, clang-tidy, -Werror
Language Bindings12 (Python, C#, Rust, Node, PHP, Go, Java, Swift, RN, Ruby, Dart, C API)
Supply ChainOpenSSF Scorecard, harden-runner, pinned actions, Dependency Review
Real failures0
Platforms testedX64, ARM64, RISC-V, macOS, Windows, iOS, Android, WASM, ROCm

Section 1/8: Mathematical Invariants (Fp, Zn, Group Laws) -- 15/15 PASSSection 1/8: Mathematical Invariants (Fp, Zn, Group Laws) -- 15/15 PASS

[1/55] SEC2 v2.0 Specification Oracle -- 13 checks[1/55] SEC2 v2.0 Specification Oracle -- 13 checks

Verifies that all library curve constants exactly match the published SEC 2 v2.0 specification:

  • SPEC-1: p ≡ 0 (mod p) — field prime encoding correct
  • SPEC-2: n ≡ 0 (mod n) — group order encoding correct
  • SPEC-3/4: Gx, Gy match SEC2 byte-for-byte (hex cross-check)
  • SPEC-5: G lies on the curve — y² = x³ + 7 (mod p)
  • SPEC-6: (n−1)·G = −G — group order arithmetic
  • SPEC-7: p ≡ 3 (mod 4) — square root formula precondition
  • SPEC-8/9: 2·G ≠ G, 2·G ≠ ∞ — no degenerate generator
  • SPEC-10: G + (−G) = ∞ — inverse closure
  • SPEC-11: curve parameter b = 7
  • SPEC-12/13: cross-representation consistency

[2/55] Post-Operation Invariant Monitor -- ~5,000 checks[2/55] Post-Operation Invariant Monitor -- ~5,000 checks

Continuous on-curve and normalization monitoring across all operation types:

  • INV-1: Post-point-add on-curve (500 random pairs, fast + CT)
  • INV-2: Post-scalar-mul on-curve (500 random scalars + 200 CT)
  • INV-3: Field element normalization after every operation (1000)
  • INV-4: Scalar range [1, n−1] after derivation (500)
  • INV-5: GLV reconstruction: k₁ + k₂·λ = k (mod n) (200)
  • INV-6: Serialization round-trip identity (200)
  • INV-7: ECDSA signatures verify against their own pubkey (100)
  • INV-8: Schnorr signatures verify against their own pubkey (100)
  • INV-9: Infinity propagation: P + (−P) = ∞, ∞ + P = P (50)
  • INV-10: Negation: P + (−P) = ∞ for 100 random points

[3/55] Field Fp Deep Audit -- 264,622 checks[3/55] Field Fp Deep Audit -- 264,622 checks

11 sub-tests covering the full finite field GF(p) where p = 2^256 - 2^32 - 977:

  • Addition: a + b mod p, commutativity, associativity, identity (0), inverse
  • Subtraction: a - b mod p, consistency with addition
  • Multiplication: a * b mod p, commutativity, associativity, distributivity
  • Squaring: a^2 == a * a, consistency
  • Reduction: values >= p are reduced correctly, canonical form
  • Canonical check: normalized representation verification
  • Limb boundary: cross-limb carry propagation correctness
  • Inversion: a * a^{-1} == 1 mod p (Fermat's little theorem)
  • Square root: sqrt(a^2) == +-a, Euler criterion
  • Batch inverse: Montgomery's trick batch inversion
  • Random stress: randomized field operations

[4/55] Scalar Zn Deep Audit -- 93,215 checks[4/55] Scalar Zn Deep Audit -- 93,215 checks

8 sub-tests covering the scalar field Z_n where n is the secp256k1 group order:

  • Mod n: reduction modulo group order
  • Overflow detection: values >= n handled correctly
  • Edge cases: 0, 1, n-1, n, n+1
  • Arithmetic: add, sub, mul, negate mod n
  • Inversion: a * a^{-1} == 1 mod n
  • GLV decomposition: k = k1 + k2 * lambda mod n (endomorphism split)
  • High-bit patterns: scalars with MSB set
  • Negation: a + (-a) == 0 mod n

[5/55] Point Operations Deep Audit -- 116,124 checks[5/55] Point Operations Deep Audit -- 116,124 checks

11 sub-tests covering elliptic curve group operations:

  • Infinity: O + P == P, P + O == P, O + O == O
  • Jacobian addition: P + Q in Jacobian coordinates
  • Doubling: 2P == P + P
  • Self-addition: P + P via add vs dbl
  • Inverse addition: P + (-P) == O
  • Affine conversion: Jacobian -> Affine -> Jacobian roundtrip
  • Scalar multiplication: k * G for known k values
  • k*G test vectors: verified against published test vectors
  • ECDSA integration: sign/verify with computed points
  • Schnorr integration: BIP-340 sign/verify with computed points
  • 100K stress test: 100,000 random scalar multiplications

[6/55] Field & Scalar Arithmetic -- 4,237 checks[6/55] Field & Scalar Arithmetic -- 4,237 checks

  • Field mul, sqr, add, sub, normalize operations
  • Scalar NAF (Non-Adjacent Form) encoding
  • Scalar wNAF (windowed NAF) encoding
  • Cross-verification between representations

[7/55] Arithmetic Correctness -- 7 suites, 55 checks[7/55] Arithmetic Correctness -- 7 suites, 55 checks

  • k*G computed via 3 independent methods (must agree)
  • P1 + P2 point addition
  • k*Q arbitrary base point
  • Random large scalar multiplication
  • Distributive law: k*(P+Q) == kP + kQ

[8/55] Scalar Multiplication -- 319 checks[8/55] Scalar Multiplication -- 319 checks

  • Known k*G vectors (published test data)
  • fast::scalar_mul vs generic::scalar_mul equivalence
  • Large scalar values (near n)
  • Repeated addition: k*G == G + G + ... + G (k times)
  • Doubling chain: 2^k * G
  • Point addition consistency
  • k*Q arbitrary base point
  • Random kQ == (k1k2)*G
  • Distributive law
  • Edge cases (k=0, k=1, k=n-1)

[9/55] Exhaustive Algebraic Verification -- 5,399 checks[9/55] Exhaustive Algebraic Verification -- 5,399 checks

14 sub-tests with exhaustive enumeration:

  1. Closure: k*G on curve for k=1..256
  2. Additive consistency: k*G + G == (k+1)*G for k=1..256
  3. Homomorphism: aG + bG == (a+b)*G for 1,024 (a,b) pairs
  4. Scalar mul vs iterated add: scalar_mul(k) == G+G+...+G for k=1..256
  5. Scalar associativity: k*(lG) == (kl)*G
  6. Addition axioms: associativity, commutativity, identity, inverse
  7. Doubling: 2*P == P + P
  8. Curve order: n*G == O, (n-1)*G == -G
  9. Scalar arithmetic exhaustive: 1,089 pairs for N=128
  10. CT consistency: ct::scalar_mul vs fast::scalar_mul for k=1..64
  11. Negation properties
  12. In-place ops: next/prev/dbl_inplace vs immutable equivalents
  13. Pippenger MSM: multi-scalar multiplication correctness
  14. Comb generator: comb_mul(k) vs k*G

[10/55] Comprehensive 500+ Suite -- 12,023 checks (10 skipped)[10/55] Comprehensive 500+ Suite -- 12,023 checks (10 skipped)

29 categories covering the entire API surface:

CategoryWhat it tests
FieldArithField add, sub, mul, sqr, neg, half
FieldConversionsbytes <-> limbs <-> hex roundtrips
FieldEdgeCases0, 1, p-1, p, max limb values
FieldInverseFermat, extended Euclidean, batch
FieldBranchlessAll field ops produce identical results regardless of input patterns
FieldOptimalOptimal representation dispatch (normalized vs lazy)
FieldRepresentationsASM/platform-specific field ops match generic
ScalarArith4,225 small-range pairs verified
ScalarConversionsbytes <-> limbs <-> hex
ScalarEdgeCases0, 1, n-1, n, max values
ScalarNAF/wNAFNAF and windowed NAF encoding correctness
PointBasicG, 2G, infinity, on-curve checks
PointScalarMulkG, kP for various k
PointInplaceIn-place add/dbl/negate/next/prev
PointPrecomputedPrecomputed table scalar mul
PointSerializationCompressed/uncompressed SEC1 roundtrip
PointEdgeCasesInfinity, negation, self-add
CTOpsConstant-time primitive operations
CTFieldCT field add/sub/mul/sqr/inv
CTScalarCT scalar add/sub/neg/cmov
CTPointCT point add/dbl/scalar_mul
GLVGLV endomorphism decomposition + recombination
MSMMulti-scalar multiplication (Pippenger/Straus)
CombGenComb-based generator multiplication
BatchInverseMontgomery's trick batch inverse
ECDSASign, verify, compact/DER encoding
SchnorrBIP-340 sign, verify, x-only pubkey
ECDHDiffie-Hellman shared secret
RecoveryECDSA public key recovery from signature
ExtrasSHA-256/512, batch affine add, batch verify, homomorphism, precompute

[11/55] ECC Property-Based Invariants -- 89 checks[11/55] ECC Property-Based Invariants -- 89 checks

Group law axioms verified with random points:

  • Identity: P + O == P (5 tests)
  • Inverse: P + (-P) == O (6 tests)
  • Negate involution: -(-P) == P (6 tests)
  • Commutativity: P + Q == Q + P (8 pairs)
  • Associativity: (P + Q) + R == P + (Q + R) (5 triples)
  • Double consistency: 2*P == P + P (6 points)
  • Scalar ring: (a + b)G == aG + b*G (8 pairs)
  • Scalar associativity: (ab)G == a(bG) (8 pairs)
  • Distributivity: k*(P + Q) == kP + kQ (8 triples)
  • Generator order: nG == O, (n-1)G == -G, 1G == G, 0G == O
  • Subtraction: P - Q == P + (-Q) (5 pairs)
  • Small k*G: k*G == G+G+...+G for k=1..8
  • In-place ops: add_inplace, dbl_inplace, negate_inplace, next_inplace, prev_inplace
  • Dual scalar mul: aG + bP (5 tests)

[12/55] Affine Batch Addition -- 548 checks[12/55] Affine Batch Addition -- 548 checks

  • Empty batch handling
  • Precompute 64 G-multiples table
  • batch_add_affine_x correctness (128 additions)
  • batch_add_affine_xy correctness (64 XY results)
  • Bidirectional batch add (32 pairs)
  • Y-parity extraction (32 values)
  • Arbitrary point multiples table (16 points)
  • Negate table (16 points)
  • Large batch benchmark: 1,024 points -- 237.5 ns/point, 4.21 Mpoints/s

[13/55] Carry Chain Stress -- 247 checks[13/55] Carry Chain Stress -- 247 checks

Limb boundary and carry propagation edge cases:

  1. All-ones limb pattern (2^256 - 1)
  2. Single-limb maximum patterns
  3. Cross-limb boundary carry patterns
  4. Values near the prime p (reduction boundary)
  5. Maximum intermediate values (carry chain stress)
  6. Scalar carry propagation near group order n
  7. Point arithmetic carry propagation

[14/55] FieldElement52 (5x52 Lazy-Reduction) -- 267 checks[14/55] FieldElement52 (5x52 Lazy-Reduction) -- 267 checks

Cross-verification of the 5x52-bit limb representation against the reference 4x64:

  • Conversion roundtrip: 4x64 -> 5x52 -> 4x64
  • Zero / One constants
  • Addition (100 pairs), lazy addition chains
  • Negation
  • Multiplication (100 pairs), squaring
  • Multiplication chains (repeated squaring)
  • Mixed operations (add + mul + square chains)
  • Half operation
  • Normalization edge cases
  • Commutativity and associativity

[15/55] FieldElement26 (10x26 Lazy-Reduction) -- 269 checks[15/55] FieldElement26 (10x26 Lazy-Reduction) -- 269 checks

Same as FieldElement52 tests plus:

  • Multiplication after lazy additions (no intermediate normalize)

Section 2/8: Constant-Time & Side-Channel Analysis -- 5/5 PASSSection 2/8: Constant-Time & Side-Channel Analysis -- 5/5 PASS

[16/55] CT Deep Audit -- 120,651 checks[16/55] CT Deep Audit -- 120,651 checks

13 sub-tests with massive differential testing:

  1. CT mask generation -- 12 checks
  2. CT cmov / cswap -- 30,000 operations (10K iterations)
  3. CT table lookup (256-bit) -- 30,000 lookups
  4. CT field ops vs fast:: differential -- 81,000 comparisons (10K iterations)
  5. CT scalar ops vs fast:: differential -- 111,000 comparisons (10K iterations)
  6. CT scalar cmov/cswap -- 1K iterations
  7. CT field cmov/cswap/select -- 1K iterations
  8. CT is_zero / eq comparisons -- edge case coverage
  9. CT scalar_mul vs fast:: scalar_mul -- 1K random scalars
  10. CT complete addition vs fast add -- 1K random point pairs
  11. CT byte-level utilities -- memcpy_if, memswap_if, memzero
  12. CT generator_mul vs fast -- 500 random scalars
  13. Timing variance sanity check -- rudimentary timing ratio (informational only)

[17/55] Constant-Time Layer Tests -- 60 checks[17/55] Constant-Time Layer Tests -- 60 checks

Focused functional tests for the CT API:

  • Field arithmetic: add, sub, mul, sqr, neg, inv, normalize
  • Field conditional: cmov (mask=0/all-ones), cswap, select, cneg, is_zero, eq
  • Scalar arithmetic: add, sub, neg
  • Scalar conditional: cmov, bit access, window extraction
  • Complete addition: G+2G=3G, G+G=2G, G+O=G, O+G=G, O+O=O, G+(-G)=O
  • CT scalar_mul: 1G, 2G, 7G, 0xDEADBEEFG, 0*G
  • CT generator_mul: generator_mul(42) == fast 42*G
  • On-curve check: G and 12345*G
  • Point equality: G==G, G!=42*G, O==O, G!=O
  • CT + fast mixing: fast(100G) -> ct(7P) == 700*G
  • CT ECDSA: sign r/s matches fast, signature verifies, zero key returns zero sig
  • CT Schnorr: keypair matches fast, sign r/s matches fast, signature verifies, pubkey(1)==G.x

[18/55] FAST == CT Equivalence -- 320 checks[18/55] FAST == CT Equivalence -- 320 checks

Systematic equivalence verification between fast:: and ct:: layers:

  • Boundary + 64 random ct::generator_mul vs fast
  • 64 random ct::scalar_mul(P, k) vs fast
  • Boundary edge scalars (0, 1, n-1)
  • 32 random ECDSA signatures: CT == FAST
  • 32 random Schnorr signatures: CT == FAST
  • Schnorr pubkey CT == FAST (boundary + random)
  • CT group law invariants

[19/55] Side-Channel Dudect Smoke -- 34 checks[19/55] Side-Channel Dudect Smoke -- 34 checks

Statistical timing analysis using Welch's t-test (|t| < 4.5 threshold):

[1] CT Primitives:
| Operation | |t| | Result |
|-----------|-----|--------|
| is_zero_mask | 0.98 | OK |
| bool_to_mask | 0.40 | OK |
| cmov256 | 0.65 | OK |
| cswap256 | 1.00 | OK |
| ct_lookup_256 | 0.99 | OK |
| ct_equal | 0.31 | OK |

[2] CT Field:
| Operation | |t| | Result |
|-----------|-----|--------|
| field_add | 4.79 | OK |
| field_mul | 0.18 | OK |
| field_sqr | 0.41 | OK |
| field_inv | 2.01 | OK |
| field_cmov | 0.14 | OK |
| field_is_zero | 3.99 | OK |

[3] CT Scalar:
| Operation | |t| | Result |
|-----------|-----|--------|
| scalar_add | 1.12 | OK |
| scalar_sub | 6.39 | OK |
| scalar_cmov | 0.48 | OK |
| scalar_is_zero | 0.82 | OK |
| scalar_bit | 1.40 | OK |
| scalar_window | 1.74 | OK |

[4] CT Point:
| Operation | |t| | Result |
|-----------|-----|--------|
| complete_add (P+O vs P+Q) | 0.95 | OK |
| complete_add (P+P vs P+Q) | 1.01 | OK |
| scalar_mul (k=1 vs random) | 0.95 | OK |
| scalar_mul (k=n-1 vs random) | 0.93 | OK |
| generator_mul (low vs high HW) | 0.45 | OK |
| point_tbl_lookup (0 vs 15) | 1.05 | OK |

[5] CT Byte Utilities:
| Operation | |t| | Result |
|-----------|-----|--------|
| ct_memcpy_if | 1.00 | OK |
| ct_memswap_if | 1.28 | OK |
| ct_memzero | 0.61 | OK |
| ct_compare | 0.14 | OK |

[6] Control test: fast::scalar_mul |t| = 31.22 (NOT CT -- expected, confirms the test detects leaks)

[7] Valgrind CLASSIFY/DECLASSIFY: All ct:: operations correctly classified as secret-independent.

[8] ASM inspection: Verifies ct:: code uses cmov/cmovne/cmove (branchless) instead of jz/jnz (branches).

[20/55] CT scalar_mul vs Fast Diagnostic -- PASS[20/55] CT scalar_mul vs Fast Diagnostic -- PASS

Diagnostic timing comparison between CT and fast scalar multiplication paths.


Section 3/8: Differential & Cross-Library Testing -- 3/3 PASSSection 3/8: Differential & Cross-Library Testing -- 3/3 PASS

[21/55] Differential Correctness -- 13,007 checks[21/55] Differential Correctness -- 13,007 checks

8 sub-tests with large-scale randomized differential testing:

  1. Public key derivation: 1,000 random private keys -> pubkey, 5,002 checks
  2. ECDSA sign + verify: 1,000 rounds internal consistency
  3. Schnorr (BIP-340) sign + verify: 1,000 rounds internal consistency
  4. Point arithmetic identities: algebraic law verification
  5. Scalar arithmetic: mod n correctness
  6. Field arithmetic: mod p correctness
  7. ECDSA signature serialization roundtrip: compact <-> DER
  8. BIP-340 known test vectors: official Bitcoin test vectors

[22/55] Fiat-Crypto Reference Vectors -- 647 checks[22/55] Fiat-Crypto Reference Vectors -- 647 checks

Golden vectors from Fiat-Crypto / Sage computer algebra:

  1. Field multiplication golden vectors
  2. Field squaring golden vectors
  3. Field inversion golden vectors
  4. Field add/sub boundary vectors
  5. Scalar arithmetic golden vectors (group order n)
  6. Point arithmetic golden vectors
  7. Algebraic identity verification (100 rounds)
  8. Serialization round-trip consistency

[23/55] Cross-Platform KAT -- 24 checks[23/55] Cross-Platform KAT -- 24 checks

Known Answer Tests that must produce identical results on all platforms:

  1. Field arithmetic KAT
  2. Scalar arithmetic KAT
  3. Point operation KAT
  4. ECDSA KAT (RFC 6979 deterministic)
  5. Schnorr KAT (BIP-340 deterministic)
  6. Serialization consistency KAT

Section 4/8: Standard Test Vectors (BIP-340, RFC-6979, BIP-32) -- 5/5 PASSSection 4/8: Standard Test Vectors (BIP-340, RFC-6979, BIP-32) -- 5/5 PASS

[24/55] BIP-340 Official Vectors -- 27 checks[24/55] BIP-340 Official Vectors -- 27 checks

Full coverage of the official Bitcoin BIP-340 Schnorr signature test vectors:

  • V0-V3 (sign + verify): pubkey matches, signature matches, verification passes, our signature verifies (4 vectors x 4 checks = 16)
  • V4 (verify-only): valid signature
  • V5: public key not on curve -> reject
  • V6: R has odd Y -> reject
  • V7: negated message -> reject
  • V8: negated s -> reject
  • V9: R at infinity -> reject
  • V10: R at infinity (x=1) -> reject
  • V11: R.x not on curve -> reject
  • V12: R.x == p -> reject
  • V13: s == n -> reject
  • V14: pk >= p -> reject

[25/55] BIP-32 Official Vectors TV1-TV5 -- 90 checks[25/55] BIP-32 Official Vectors TV1-TV5 -- 90 checks

Complete BIP-32 HD key derivation test vector coverage:

  • TV1: Master key + 5 derivation levels (m, m/0', m/0'/1, m/0'/1/2', m/0'/1/2'/2, m/0'/1/2'/2/1000000000) -- chain_code, priv_key, pub_key at each level
  • TV2: Master + 5 levels with hardened indices (2147483647')
  • TV3: Leading zeros retention
  • TV4: Leading zeros with hardened children
  • TV5: Serialization format (78 bytes, version bytes xprv/xpub, depth, parent fingerprint, child number, chain code, key prefix)
  • Public derivation consistency: Private and public derivation yield same pubkey and chain codes

[26/55] RFC 6979 Deterministic ECDSA -- 35 checks[26/55] RFC 6979 Deterministic ECDSA -- 35 checks

  • 6 nonce generation vectors: Various private keys and messages
  • 7 ECDSA signature vectors (r + s): Including d=1, d=n-1, d=69ec, small d, tiny d
  • 5 verify roundtrips: verify(sign(msg, priv), pub) == true
  • 5 wrong message rejections: verify with wrong message == false
  • Determinism: Same (key, msg) -> identical signature
  • Low-S: All signatures satisfy BIP-62 low-S requirement

[27/55] FROST Reference KAT Vectors -- 9 sub-tests[27/55] FROST Reference KAT Vectors -- 9 sub-tests

  1. Lagrange coefficient mathematical properties
  2. FROST DKG determinism with fixed seeds
  3. FROST DKG Feldman VSS commitment verification
  4. FROST 2-of-3 full signing -> BIP-340 verification
  5. FROST 3-of-5 full signing -> BIP-340 verification
  6. Lagrange coefficients consistency across 10 subsets
  7. Pinned KAT: DKG group key determinism
  8. Pinned KAT: Full signing round-trip determinism
  9. FROST DKG secret reconstruction via Lagrange interpolation

[51/55] KAT: All Operations -- ~42 checks[51/55] KAT: All Operations -- ~42 checks

Known-answer tests for operations not fully covered by BIP-340 / RFC-6979 / BIP-32 vectors:

  • KAT-1..4: ECDH commutativity — ecdh(k₁, k₂·G) == ecdh(k₂, k₁·G) for pairs (1,2), (1,7), (2,7); ecdh vs ecdh_xonly differ
  • KAT-5..8: WIF encode/decode — privkey=1 → KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73NUBBy9s (mainnet compressed), testnet, uncompressed variants
  • KAT-9..12: P2PKH — privkey=1 → 1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH; two distinct keys produce distinct addresses
  • KAT-13..16: P2WPKH — privkey=1 → bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4; starts with "bc1q"
  • KAT-17..20: P2TR format checks — starts with "bc1p" (mainnet) / "tb1p" (testnet); two keys differ
  • KAT-21..25: Taproot output key + taproot_verify round-trip + merkle_root changes output key
  • KAT-26..30: DER encoding round-trip + format check (starts 0x30)
  • KAT-31..34: SHA-256 NIST vectors ("abc", ""), Hash160(""), Hash160(G_compressed) = 751e76e8...
  • KAT-35..38: ECDH commutativity for keys 3,5 and 11,13
  • KAT-39..42: Pubkey arithmetic — (G+2G)−2G=G, G+G=2G, tweak_add(G,1)=2G, tweak_mul(G,7)=7G

Section 5/8: Fuzzing & Adversarial Attack Resilience -- 4/4 PASSSection 5/8: Fuzzing & Adversarial Attack Resilience -- 4/4 PASS

[28/55] Adversarial Fuzz -- 15,461 checks[28/55] Adversarial Fuzz -- 15,461 checks

10 sub-tests targeting malformed/adversarial inputs:

  1. Malformed public key rejection (3 checks)
  2. Invalid ECDSA signatures (4 checks)
  3. Invalid Schnorr signatures (4 checks)
  4. Oversized scalars (4 checks)
  5. Boundary field elements (4 checks)
  6. ECDSA recovery edge cases (1,000 rounds, 4,750 checks)
  7. Random operation sequence (10,000 random ops, 1,692 checks)
  8. DER encoding round-trip (1,000 rounds, 3,000 checks)
  9. Schnorr signature byte round-trip (1,000 rounds, 2,000 checks)
  10. Signature normalization / low-S (1,000 rounds, 4,000 checks)

[29/55] Parser Fuzz -- 530,018 checks[29/55] Parser Fuzz -- 530,018 checks

High-volume random input fuzzing with crash detection:

  1. DER parsing: random bytes -- 100,000 random inputs, 0 accepted, 0 crashes
  2. DER parsing: adversarial inputs -- targeted malformation
  3. DER round-trip -- 50,000 compact -> DER -> compact roundtrips
  4. Schnorr verify: random inputs -- 100,000 random inputs, 0 accepted, 0 crashes
  5. Schnorr round-trip -- 10,000 sign -> verify roundtrips
  6. Random privkey -> pubkey -- 10,000 random keys
  7. Pubkey round-trip -- 10,000 create -> parse roundtrips
  8. Pubkey parse: adversarial inputs -- targeted malformation
  9. ECDSA verify: random garbage -- 50,000 random inputs, 0 accepted, 0 crashes

[30/55] Address/BIP32/FFI Boundary Fuzz -- 13 sub-tests[30/55] Address/BIP32/FFI Boundary Fuzz -- 13 sub-tests

  1. P2PKH address fuzz (Base58Check)
  2. P2WPKH address fuzz (Bech32)
  3. P2TR address fuzz (Bech32m)
  4. WIF encode/decode fuzz
  5. BIP32 master key from seed fuzz
  6. BIP32 path parser fuzz
  7. BIP32 derive (single-step) fuzz
  8. FFI context lifecycle stress
  9. FFI ECDSA sign/verify boundary fuzz
  10. FFI Schnorr sign/verify boundary fuzz
  11. FFI ECDH + tweaking boundary fuzz
  12. FFI Taproot output key boundary fuzz
  13. FFI error inspection

[31/55] Fault Injection Simulation -- 610 checks[31/55] Fault Injection Simulation -- 610 checks

Verifying that single-bit faults are always detected:

  1. Scalar fault injection: bit-flip in k -> wrong k*G (500/500 detected)
  2. Point coordinate fault injection (500/500)
  3. ECDSA signature fault injection: r-fault 200/200, msg-fault 200/200, s-fault 200/200
  4. Schnorr signature fault injection (200/200)
  5. CT operations fault resilience: 1,000/1,000 single-bit differences detected
  6. Cascading fault simulation: multi-step scalar_mul (100/100)
  7. Point addition fault injection (300/300)
  8. GLV decomposition fault resilience (200/200)

Section 6/8: Protocol Security (ECDSA, Schnorr, MuSig2, FROST) -- 9/9 PASSSection 6/8: Protocol Security (ECDSA, Schnorr, MuSig2, FROST) -- 9/9 PASS

[32/55] ECDSA + Schnorr -- 22 checks[32/55] ECDSA + Schnorr -- 22 checks

  • SHA-256 NIST vectors ("abc", empty string)
  • Scalar::inverse correctness (7 * 7^{-1} == 1, random, inverse(0)==0)
  • Scalar::negate (a + (-a) == 0, negate(0)==0)
  • ECDSA: sign/verify, low-S (BIP-62), wrong message/key rejection, compact encoding, DER encoding
  • ECDSA determinism (RFC 6979)
  • Tagged hash (BIP-340): determinism, different tags -> different hashes
  • Schnorr BIP-340: sign/verify, wrong message rejection, roundtrip

[33/55] BIP-32 HD Derivation -- 28 checks[33/55] BIP-32 HD Derivation -- 28 checks

  • HMAC-SHA512 (RFC 4231 TC2)
  • Master key generation (depth=0, chain code, private key match TV1)
  • Child derivation (m/0' depth=1, chain code matches)
  • Path derivation (m/0'/1, m/0'/1/2', empty path fails, invalid prefix fails)
  • Serialization (78 bytes, xprv version, depth, fingerprint)
  • Seed validation (< 16 bytes rejected, 16 and 64 accepted)

[34/55] MuSig2 -- 19 checks[34/55] MuSig2 -- 19 checks

  • Key aggregation: valid point, deterministic, differs from individual keys
  • Nonce generation: non-zero secrets, valid R1/R2, different extra -> different nonce
  • 2-of-2 signing: partial sig 1/2 verify, final MuSig2 sig verifies as standard Schnorr
  • 3-of-3 signing: agg key valid, partial sig 0/1/2 verify, MuSig2 sig verifies as Schnorr
  • Single-signer edge case: agg key valid, partial verify OK, valid Schnorr sig

[35/55] ECDH + Recovery + Taproot -- 76 checks[35/55] ECDH + Recovery + Taproot -- 76 checks

  • ECDH: Basic key exchange, x-only variant, raw x-coordinate, zero private key edge, infinity public key edge
  • Recovery: Basic sign + recover, multiple different private keys, compact 65-byte serialization, wrong recovery ID, invalid signature (zero r/s)
  • Taproot: TapTweak hash, output key derivation, private key tweaking, commitment verification, leaf and branch hashes, Merkle tree construction, Merkle proof verification, full flow (key-path + script-path)
  • CT Utils: Constant-time equality, zero check, compare, secure memory zeroing, conditional copy and swap
  • Wycheproof: ECDSA edge cases, Schnorr edge cases, recovery edge cases

[36/55] v4 Features (Pedersen/FROST/Adaptor/Address/SP) -- 90 checks[36/55] v4 Features (Pedersen/FROST/Adaptor/Address/SP) -- 90 checks

  • Pedersen Commitments: generator H, commit/verify roundtrip, wrong value/blinding fails, homomorphic addition, balance proof, switch commitment, serialization (compressed prefix, 33 bytes), zero-value commitment
  • FROST: Lagrange coefficients (l1=2, l2=-1, interpolation), key generation (poly degree, share count, 3 participants, group keys match), 2-of-3 signing
  • Schnorr Adaptor: R_hat valid, pre-signature valid, adapted sig valid Schnorr, extract secret matches
  • ECDSA Adaptor: R_hat valid, r nonzero, adaptor verify, adapted ECDSA nonzero, extract secret matches
  • Identity adaptor: edge case
  • Base58Check: encode, leading ones, decode, size, roundtrip
  • Bech32/Bech32m: encode, prefix bc1/bc1p, decode, witness version 0/1, program 20/32 bytes
  • HASH160: deterministic, different inputs
  • P2PKH: starts with 1, valid length, testnet prefix
  • P2WPKH: bc1q prefix, testnet tb1q, decode, version 0, 20-byte program
  • P2TR: bc1p prefix, decode, version 1, 32-byte program
  • WIF: compressed (K/L prefix), uncompressed (5 prefix), testnet, roundtrip
  • Address consistency: deterministic, different keys -> different addresses
  • Silent Payments: scan/spend key valid, address encoded with prefix, output key derivation, tweak nonzero, detection (1 and 3 outputs), derived key matches

[37/55] Coins Layer -- 32 checks[37/55] Coins Layer -- 32 checks

  • CurveContext: secp256k1_default(), with_generator(custom), derive_public_key, effective_generator
  • CoinParams: 27 coins defined, Bitcoin/Ethereum values, find_by_ticker + find_by_coin_type
  • Keccak-256: empty string, "abc", incremental == one-shot
  • Ethereum: address format (0x + 40 hex), EIP-55 checksum verify, case sensitivity
  • Coin addresses: Bitcoin P2PKH(1), P2WPKH(bc1q), Litecoin(ltc1q), Dogecoin(D), Ethereum(EIP-55), Dash(X), Dogecoin P2WPKH(empty -- no SegWit)
  • WIF per-coin: Bitcoin(K/L), Litecoin(T)
  • BIP-44 HD: Bitcoin taproot(m/86'/0'/0'/0/0), Ethereum(m/44'/60'/0'/0/0), best_purpose selection, seed -> key, seed -> BTC address, seed -> ETH address
  • Custom generator: coin_derive with custom G, deterministic derivation
  • Full pipeline: same key -> different addresses per coin

[38/55] MuSig2 + FROST Protocol Suite -- 975 checks[38/55] MuSig2 + FROST Protocol Suite -- 975 checks

15 sub-tests with protocol-level verification:

  1. MuSig2 key aggregation determinism (273 checks)
  2. MuSig2 key aggregation ordering matters
  3. MuSig2 key aggregation duplicate keys
  4. MuSig2 full round-trip: 2 signers
  5. MuSig2 full round-trip: 3 signers
  6. MuSig2 full round-trip: 5 signers
  7. MuSig2 wrong partial sig fails verify
  8. MuSig2 bit-flip invalidates final signature
  9. FROST DKG 2-of-3
  10. FROST DKG 3-of-5
  11. FROST signing 2-of-3
  12. FROST signing 3-of-5
  13. FROST different 2-of-3 subsets all valid
  14. FROST bit-flip invalidates signature
  15. FROST wrong partial sig fails verify

[39/55] MuSig2 + FROST Adversarial -- 316 checks[39/55] MuSig2 + FROST Adversarial -- 316 checks

9 sub-tests targeting protocol-level attacks:

  1. Rogue-key resistance: Attacker cannot bias aggregated key
  2. Key coefficient depends on full group: Changing group changes coefficients
  3. Different messages -> different signatures (100 rounds)
  4. Nonce binding: Fresh nonces -> different R values (60 rounds)
  5. Fault injection: Wrong key in partial sign detected
  6. Malicious participant -- bad DKG share: Detected and rejected
  7. Malicious participant -- bad partial sig: Detected and rejected
  8. Message binding: Different messages -> different signatures (40 rounds)
  9. Signer set binding: Same key, different subsets -> different results

[40/55] Integration -- 13,811 checks[40/55] Integration -- 13,811 checks

10 sub-tests for cross-protocol integration:

  1. ECDH key exchange symmetry (1,000 rounds, 4,001 checks)
  2. Schnorr batch verification
  3. ECDSA batch verification
  4. ECDSA sign -> recover -> verify (1,000 rounds)
  5. Schnorr individual vs batch (500 rounds)
  6. Fast vs CT integration cross-check (500 rounds)
  7. Combined ECDH + ECDSA protocol flow (100 rounds)
  8. Multi-key consistency (point addition, 200 rounds)
  9. Schnorr/ECDSA key consistency (200 rounds)
  10. Stress: mixed protocol ops (5,000 rounds, 100% success)

[41/55] ZK Proofs Audit -- ~1,500 checks[41/55] ZK Proofs Audit -- ~1,500 checks

7 sub-sections covering the full ZK proof layer (secp256k1::zk):

  • ZK-1 Knowledge Proof (standard G): round-trip prove/verify (100 iterations), wrong-pubkey rejection (100), tampered-rx rejection (50), tampered-s rejection (50), wrong-message rejection (100)
  • ZK-2 Knowledge Proof (arbitrary base): round-trip prove/verify (50 iterations), arbitrary-base proof rejected by standard verifier, wrong-base rejection (50)
  • ZK-3 DLEQ Proof: round-trip prove/verify (100 iterations), swapped P/Q rejection (100), wrong-Q rejection (100), tampered-challenge rejection (50)
  • ZK-4 Range Proof (Bulletproof 64-bit): boundary values 0, 1, 2³¹, 2³²−1, 2³², 2⁶³−1, 2⁶³, 2⁶⁴−1; random values (20); tampered-commitment rejection (15)
  • ZK-5 Serialization: KnowledgeProof serialize/deserialize (30); DLEQProof serialize/deserialize (30); corrupted-byte rejection
  • ZK-6 Pedersen Homomorphism: C(v1,r1)+C(v2,r2) == C(v1+v2, r1+r2) (30 iterations); wrong-blinding gives different point
  • ZK-7 Batch Range Verify: all-valid batch passes; single-invalid-proof causes full batch failure
Source: audit/audit_zk.cpp | Added: v3.22.0

Section 7/8: ABI & Memory Safety -- 9/9 PASSSection 7/8: ABI & Memory Safety -- 9/9 PASS

[42/55] Cross-ABI / FFI Round-Trip Tests -- 28 sub-tests[42/55] Cross-ABI / FFI Round-Trip Tests -- 28 sub-tests

Complete round-trip coverage through the ufsecp_* C API boundary (28 sections):

Context lifecycle, key generation (compressed/uncompressed/x-only), ECDSA sign→verify→DER encode/decode, recoverable signatures, Schnorr/BIP-340, ECDH variants, BIP-32 derivation, address generation (P2PKH/P2WPKH/P2TR), WIF encode/decode, hashing (SHA-256, Hash160, tagged hash), Taproot, key tweaks, cross-context verification, pubkey arithmetic, batch verify, ZK proofs, multi-scalar, multi-coin wallet, Bitcoin message signing, MuSig2, adaptor signatures.

All tests go through the C ABI (ufsecp_*) verifying the FFI layer correctly marshals data without corruption.

[43/55] Security Hardening -- 17,309 checks[43/55] Security Hardening -- 17,309 checks

10 sub-tests covering defensive security:

  1. Zero / identity key handling (5 checks)
  2. Secret zeroization (ct_memzero verification)
  3. Bit-flip resilience on signatures (1,000 rounds)
  4. Message bit-flip detection (1,000 rounds)
  5. Nonce determinism (RFC 6979 compliance)
  6. Serialization round-trip integrity
  7. Compact recovery serialization (1,000 rounds)
  8. Double operations idempotency
  9. Cross-algorithm consistency (ECDSA/Schnorr same key)
  10. High-S detection (3,000 rounds)

[44/55] Debug Invariant Assertions -- 372 checks[44/55] Debug Invariant Assertions -- 372 checks

6 sub-tests verifying internal consistency invariants:

  1. Field element normalization invariant
  2. Point on-curve invariant
  3. Scalar validity invariant
  4. Debug assertion macro integration
  5. Full computation chain with invariant checks
  6. Debug counter accumulation (11 invariant checks tracked)

[45/55] ABI Version Gate -- 12 checks[45/55] ABI Version Gate -- 12 checks

Compile-time ABI compatibility verification ensuring header and library versions match.

[46/55] C ABI Negative Contract Tests -- ~150 checks[46/55] C ABI Negative Contract Tests -- ~150 checks

Systematic negative testing of all 50+ ufsecp_* C API functions for correct error
propagation. Every function must return the documented error code (never crash, never
silently succeed) when called with:

  • NULL required pointersUFSECP_ERR_NULL_ARG
  • Zero private key (= 0 mod n)UFSECP_ERR_BAD_KEY
  • Key equal to group order (= 0 mod n)UFSECP_ERR_BAD_KEY
  • All-zero / off-curve public keyUFSECP_ERR_BAD_PUBKEY or error
  • All-zero signature (R = 0)UFSECP_ERR_BAD_SIG or UFSECP_ERR_VERIFY_FAIL
  • Wrong public key in verifyUFSECP_ERR_VERIFY_FAIL
  • Truncated / garbage DERUFSECP_ERR_BAD_INPUT
  • Output buffer too smallUFSECP_ERR_BUF_TOO_SMALL
  • BIP-32 seed length < 16 bytesUFSECP_ERR_BAD_INPUT

Covers 12 function groups: context, seckey, pubkey, ECDSA, Schnorr, ECDH,
hashing, addresses, WIF, BIP-32, Taproot, pubkey arithmetic.

[52/55] Secure Memory Erasure Verification -- 25 checks[52/55] Secure Memory Erasure Verification -- 25 checks

Verifies secp256k1::detail::secure_erase() actually zeroes memory and that the zeroing
survives compiler dead-store elimination optimisations (volatile-pointer readback test):

  • SE-1..8: Heap buffers of sizes 1, 2, 4, 8, 16, 32, 64, 128 bytes zeroed correctly
  • SE-9..12: Stack buffers (32-byte, 64-byte), std::array<uint8_t,32>, scalar-sized struct
  • SE-13..14: Zero-length erase is safe; 256-byte heap buffer zeroed
  • SE-15..20: Signing path nonce determinism — same (key, msg) → identical ECDSA sig twice (proves nonce state is erased and re-derived, not leaked or reused)
  • SE-21..24: 0xA5 and 0xFF sentinel patterns survive until erase call, then zero
  • SE-25: Schnorr BIP-340 nonce determinism (aux=0)

[53/55] CT Namespace Discipline (Source-Level Scan) -- ~20 checks[53/55] CT Namespace Discipline (Source-Level Scan) -- ~20 checks

Source-level static analysis verifying every code path handling secret data uses secp256k1::ct:: (constant-time) operations and not secp256k1::fast:: (variable-time):

  • Opens cpu/src/ct_sign.cpp, ecdh.cpp, bip32.cpp, taproot.cpp, musig2.cpp at runtime
  • Strips C++ comments before scanning to eliminate false positives in comment text
  • Required patterns: ct::generator_mul, ct::scalar_inverse, secure_erase, ct::scalar_mul, secp256k1/ct/
  • Prohibited patterns: fast::generator_mul, fast::scalar_mul, fast::point_mul
  • Structural checks: ct_sign.cpp must not #include "secp256k1/fast.hpp"; must include detail/secure_erase.hpp; ecdh.cpp must include ct/point.hpp and call secure_erase
  • Advisory skip (not hard fail) when source tree is absent (binary-only deployment)

[54/55] RFC 6979 Nonce Uniqueness Monitor -- 30 checks[54/55] RFC 6979 Nonce Uniqueness Monitor -- 30 checks

Comprehensive verification of nonce determinism, uniqueness, and isolation:

  • NU-1..6: ECDSA RFC 6979 determinism — same (key=1, msg[i]) → identical sig across 3 calls
  • NU-7..12: ECDSA r-value uniqueness — 6 distinct messages with same key → 6 distinct r values
  • NU-13..17: ECDSA key isolation — 5 different keys, same message → 5 distinct r values
  • NU-18..21: Schnorr BIP-340 determinism — aux_rand=0, 4 messages, each stable across 3 calls
  • NU-22..25: Schnorr R.x uniqueness — 4 distinct messages → 4 distinct R.x commitments
  • NU-26..28: Hedged Schnorr — 3 different aux_rand bytes → 3 different R values (BIP-340 randomness)
  • NU-29: ECDSA r ≠ Schnorr R.x for same (key, msg) — different nonce derivation paths
  • NU-30: 5-key × 5-msg matrix — 25 ECDSA signatures → 25 pairwise distinct r values

[55/55] Public Parse Path Strictness Audit -- ~60 checks[55/55] Public Parse Path Strictness Audit -- ~60 checks

Systematically verifies that every public parse/decode function rejects ALL malformed inputs with
the correct documented error code — never silently accepting corrupt data. This directly addresses
the "Parsing and Validation Unification" engineering requirement.

  • PS-1..16: ufsecp_pubkey_parse (compressed) — all-zero, all-0xFF, x=0, prefix 0x01/0x05, truncated (32-byte, 1-byte, 0-byte), NULL, parity-flip
  • PS-17..22: ufsecp_seckey_verify — scalar=0, scalar=n, scalar=n+1, scalar=0xFF×32; scalar=1 and scalar=n−1 accepted
  • PS-23..30: ufsecp_ecdsa_sig_from_der — all-zero, wrong tag (0x00, 0x31), truncated, inflated length, zero-length, NULL; valid DER round-trips
  • PS-31..36: ufsecp_wif_decode — NULL, empty string, single char, corrupted checksum, garbage WIF-length; valid WIF decodes to correct key
  • PS-37..40: ufsecp_bip32_master — NULL seed, 15-byte seed (<16 BIP-32 minimum), zero-length; 32-byte seed accepted
  • PS-41..48: ufsecp_pubkey_parse (uncompressed, 65-byte) — all-zero, x=0/y=0, x=G.x/y=0 (off-curve), prefix 0x05/0x06 (hybrid), truncated; valid uncompressed round-trips
  • PS-49..53: ufsecp_pubkey_xonly — NULL, x=0, x=p (field prime), x=2 (not on curve); valid compressed → x-only extraction correct

Section 8/8: Performance Validation & Regression -- 4/4 PASSSection 8/8: Performance Validation & Regression -- 4/4 PASS

[47/55] Accelerated Hashing -- 877 checks[47/55] Accelerated Hashing -- 877 checks

Hardware-accelerated hash function validation:

  • Feature detection: SHA-NI, AVX2, AVX-512
  • SHA-256: NIST known vectors, sha256_33, sha256_32 correctness
  • RIPEMD-160: Known vectors, ripemd160_32 correctness
  • Hash160: Pipeline correctness (SHA-256 + RIPEMD-160)
  • Double-SHA256: Correctness
  • Batch operations: Batch hash correctness
  • SHA-NI vs scalar cross-check: Hardware vs software must match
  • Benchmark: SHA-NI 49.1 ns vs scalar 364.6 ns (7.4x speedup), batch Hash160 1.92 Mkeys/s

[48/55] SIMD Batch Operations -- 8 checks[48/55] SIMD Batch Operations -- 8 checks

  • Runtime detection (AVX-512 / AVX2)
  • Batch field add, sub, mul, square
  • Batch field inverse (Montgomery's trick)
  • Single element batch inverse
  • Batch inverse with explicit scratch buffer

[49/55] Multi-Scalar & Batch Verify -- 16 checks[49/55] Multi-Scalar & Batch Verify -- 16 checks

  • Shamir's trick: shamir(7,G,13,5G)==72G, zero scalar edges
  • Multi-scalar mul: 1 point, 3 points (2G+6G+15G=23G), 0 points=infinity, G+(-G)=infinity
  • Schnorr batch: 5 valid pass, individual agrees, corrupted sig#2 detected, identify finds #2, empty=true, single entry
  • ECDSA batch: 4 valid pass, corrupted sig#1 detected, identify finds #1

[50/55] Performance Smoke -- PASS[50/55] Performance Smoke -- PASS

Sign/verify roundtrip timing sanity check.


Additional CTest Targets (Outside Unified Audit)Additional CTest Targets (Outside Unified Audit)

These tests run as separate CTest executables and are included in the 24/24 CTest pass:

TargetWhat it tests
secp256k1_doubling_equivalencedbl(P) == add(P, P) for many points
secp256k1_add_jacobian_vs_affineJacobian addition matches affine addition
secp256k1_generator_vs_generic_smallgenerator_mul(k) matches generic scalar_mul(G, k) for small k

Unified Audit Platform ResultsUnified Audit Platform Results

PlatformCompilerTestsResult
X64 (Windows)Clang 21.1.024/24 CTest, 55/55 auditALL PASS
ARM64 (QEMU)Cross-compiled24/24 CTestALL PASS
RISC-V (QEMU)Cross-compiled24/24 CTestALL PASS
RISC-V (Mars HW, JH7110 U74)Clang 21.1.855/55 unified auditALL PASS

See Full Platform Matrix below for all 16 CI configurations.


How to RunHow to Run

# Configure
cmake -S Secp256K1fast -B build_rel -G Ninja -DCMAKE_BUILD_TYPE=Release

# Build
cmake --build build_rel -j

# Run all CTest targets
ctest --test-dir build_rel --output-on-failure

# Run unified audit only
./build_rel/audit/unified_audit_runner

CI/CD Pipeline -- Full InfrastructureCI/CD Pipeline -- Full Infrastructure

14 GitHub Actions Workflows14 GitHub Actions Workflows

#WorkflowTriggerWhat it does
1CIpush/PR dev,mainCore build+test matrix (see below)
2Security Auditpush main, weeklyASan+UBSan, Valgrind, dudect smoke, -Werror build
3Nightlydaily 03:00 UTCExtended differential (1.3M+ checks), dudect full (30 min)
4Bindingspush dev/main (bindings/)12 language bindings compile-check
5Benchmark Dashboardpush dev/mainPerformance tracking (Linux + Windows), regression alerts
6CodeQLpush dev/main, weeklyGitHub SAST (security-and-quality queries)
7SonarCloudpush dev/mainStatic analysis + coverage upload
8Clang-Tidypush dev/main (cpu/)Static analysis (clang-tidy-17)
9OpenSSF Scorecardpush main, weeklySupply-chain security score
10Dependency ReviewPRsKnown-vulnerable dependency scanning
11Linux Packagesrelease tags.deb (amd64+arm64) + .rpm (x86_64) packaging
12Releaserelease tagsMulti-platform binaries + all binding packages
13Docspush main (cpu/include/)Doxygen API docs to GitHub Pages
14Discord CommitspushCommit notifications

CI Build Matrix (ci.yml)CI Build Matrix (ci.yml)

PlatformCompilerConfigsTests
Linux x64gcc-13Debug, ReleaseCTest (all except ct_sidechannel)
Linux x64clang-17Debug, ReleaseCTest (all except ct_sidechannel)
Linux ARM64aarch64-linux-gnu-g++-13Release (cross)Binary verification
Windows x64MSVC 2022ReleaseCTest
macOS ARM64Apple ClangReleaseCTest + Metal GPU benchmarks
iOSXcodeOS, SIMULATORStatic library build
iOS XCFrameworkXcodeUniversalXCFramework artifact
ROCm/HIPhipcc (gfx906-gfx1100)ReleaseCPU tests (compile-check GPU)
WASMEmscripten 3.1.51ReleaseNode.js benchmark
AndroidNDK r27carm64-v8a, armeabi-v7a, x86_64Binary verification + JNI
Sanitizersclang-17ASan+UBSanCTest under sanitizers
Sanitizersclang-17TSanCTest under thread sanitizer
Coverageclang-17Debug + profilingLLVM source-based coverage -> Codecov

Total CI matrix: 17 configurations across 7 operating systems / architectures.


Sanitizer Testing (CRITICAL)Sanitizer Testing (CRITICAL)

ASan + UBSan (ci.yml + security-audit.yml)ASan + UBSan (ci.yml + security-audit.yml)

  • Compiler: clang-17 with -fsanitize=address,undefined -fno-sanitize-recover=all
  • Options: ASAN_OPTIONS=detect_leaks=1:halt_on_error=1, UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1
  • Scope: All CTest targets (excluding ct_sidechannel timing test)
  • Runs on: Every push to dev/main + every PR

TSan -- Thread Sanitizer (ci.yml)TSan -- Thread Sanitizer (ci.yml)

  • Compiler: clang-17 with -fsanitize=thread
  • Scope: All CTest targets
  • Purpose: Detect data races in potential multi-threaded usage

Valgrind Memcheck (security-audit.yml)Valgrind Memcheck (security-audit.yml)

  • Tool: Valgrind with --leak-check=full --error-exitcode=1
  • Leak detection: definite, indirect, possible (all three)
  • Suppressions: Custom valgrind.supp file
  • Post-check: Grep for ERROR SUMMARY: [1-9] and definitely lost: [1-9]
  • Runs on: Every push to main + weekly

-Werror Build (security-audit.yml)-Werror Build (security-audit.yml)

  • Compiler: gcc-13 with -Werror -Wall -Wextra -Wpedantic -Wconversion -Wshadow
  • Purpose: Zero compiler warnings enforced

Coverage-Guided Fuzzing (libFuzzer)Coverage-Guided Fuzzing (libFuzzer)

3 libFuzzer harnesses in cpu/fuzz/:

HarnessTargetInput SizeInvariants Checked
fuzz_fieldFieldElement arithmetic64 bytes (2 x 32B)add/sub roundtrip, mul-by-1 identity, aa==square, ainv(a)==1
fuzz_scalarScalar arithmetic64 bytes (2 x 32B)add/sub roundtrip, mul-by-1, a-a==0, a+0==a, distributive law
fuzz_pointPoint operations32 bytes (1 scalar)on-curve, compressed/uncompressed roundtrip, P+(-P)==O, dbl==add(P,P)

Build: clang++ -fsanitize=fuzzer,address -O2 -std=c++20
Run: ./fuzz_field -max_len=64 -runs=10000000

All harnesses use __builtin_trap() on invariant violation (instant crash -> corpus saved).

Plus deterministic pseudo-fuzz tests in audit/ (built with -DSECP256K1_BUILD_FUZZ_TESTS=ON):

  • test_fuzz_parsers: DER parser, Schnorr verify, pubkey parse -- 530K+ random inputs
  • test_fuzz_address_bip32_ffi: Address/BIP32/FFI boundary fuzz -- 13 sub-tests

Nightly Extended Testing (nightly.yml)Nightly Extended Testing (nightly.yml)

Runs daily at 03:00 UTC with configurable parameters:

TestDefaultDuration
Extended Differential100x multiplier (~1.3M random checks)up to 60 min
dudect Full Statistical1800s timeout (30 min)up to 45 min

Extended Differential: Same as audit module [22/55] but with 100x more random cases.
dudect Full: No DUDECT_SMOKE define -- runs full statistical analysis with larger sample sizes.


Static AnalysisStatic Analysis

ToolScopeFrequency
CodeQLC/C++ SAST (security-and-quality)Every push + weekly
SonarCloudStatic analysis + coverage metricsEvery push/PR
clang-tidy-17Lint + modernize checksEvery push to dev/main (cpu/)
-Werror buildgcc-13 with Wpedantic, Wconversion, WshadowEvery push to main

Bindings CI (12 Languages)Bindings CI (12 Languages)

C API builds as shared library on Linux/macOS/Windows, then each binding is compile-checked:

BindingToolCheck Type
Pythonpy_compile + pyflakesSyntax + lint
C# (.NET 8)dotnet buildFull compile
Rustcargo check + clippyType-check + lint
Node.jsnode --check + tscSyntax + TypeScript types
PHP 8.3php -lSyntax check
Go 1.22go vet + go buildVet + syntax
Java 21 (JNI)javac + gcc -fsyntax-onlyClass compile + JNI bridge syntax
Swiftswift build + swiftc -typecheckCompile + type check
React Nativenode --check + javacJS syntax + Android Java
Ruby 3.3ruby -c + gem buildSyntax + gemspec
Dartdart pub get + dart analyzeDependencies + analysis

Supply Chain SecuritySupply Chain Security

MechanismTool
Runner hardeningstep-security/harden-runner (egress audit) on ALL CI jobs
Pinned actionsEvery uses: action has SHA-pinned commit hash
Dependency reviewactions/dependency-review-action on all PRs
OpenSSF ScorecardWeekly analysis + SARIF upload to GitHub Security
SBOM generationPart of release pipeline

Performance Benchmarks (benchmark.yml)Performance Benchmarks (benchmark.yml)

PlatformConfigTool
Linux (ubuntu-latest)Release, ASM=ONbench_unified -> JSON -> github-action-benchmark
Windows (windows-latest)Release, MSVCbench_unified -> summary
  • Dashboard: GitHub Pages (gh-pages branch)
  • Alert threshold: 150% (warns if >50% slower than baseline)
  • Tracking: Continuous on every push to dev/main

Release Pipeline (release.yml)Release Pipeline (release.yml)

Multi-platform release on tag push:

ArtifactPlatformFormat
Desktop binariesLinux x64, macOS ARM64, Windows x64.tar.gz / .zip
Static libraryAll 3 platformslibfastsecp256k1.a / .lib
Shared library (C API)All 3 platforms.so / .dylib / .dll
iOS XCFrameworkiOS + Simulator.xcframework
Android AARarm64-v8a, armeabi-v7a, x86_64.aar
WASMBrowser/Node.js.wasm + .js + .mjs
Python wheelLinux/macOS/Windows.whl
.NET NuGetCross-platform.nupkg
Rust crateCross-platformcrates.io publish
npm packageCross-platformnpm publish
Ruby gemCross-platform.gem
Dart packageCross-platformpub.dev publish
Linux packagesamd64, arm64.deb + .rpm

Packaging (packaging.yml)Packaging (packaging.yml)

FormatArchitecturesRepo
.debamd64, arm64GitHub Pages APT repository
.rpmx86_64Attached to GitHub Release

APT install: sudo apt install libufsecp-dev


Audit Gap AnalysisAudit Gap Analysis

What IS CoveredWhat IS Covered

CategoryStatusEvidence
Mathematical correctness (Fp, Zn, Group)COVERED55/55 audit modules, 1M+ checks
Constant-time layer + equivalenceCOVEREDdudect smoke + full, CT deep, ASM inspection, Valgrind CLASSIFY/DECLASSIFY
Standard test vectors (BIP-340/32, RFC 6979, FROST)COVEREDOfficial vectors verified
Randomized differential testingCOVERED13K+ checks (CI) + 1.3M (nightly)
Fiat-Crypto reference vectorsCOVEREDGolden vectors from computer algebra
Cross-platform KATCOVEREDX64, ARM64, RISC-V all identical
Parser/adversarial fuzzing (deterministic)COVERED530K+ random inputs, 0 crashes
Coverage-guided fuzzingCOVERED3 libFuzzer harnesses (field, scalar, point) + ASan
Fault injection simulationCOVERED610+ single-bit fault checks
Protocol security (ECDSA, Schnorr, MuSig2, FROST)COVEREDFull protocol suites + adversarial
ASan + UBSanCOVEREDCI on every push (clang-17)
TSanCOVEREDCI on every push (clang-17)
Valgrind memcheckCOVEREDsecurity-audit.yml weekly + on push
Static analysis (CodeQL, SonarCloud, clang-tidy)COVERED3 tools on every push
Code coverage (Codecov)COVEREDLLVM source-based profiling
Misuse/abuse tests (null ctx, invalid lengths, FFI)COVEREDModule [31/55] + [42/55]
Multi-platform build (17 configurations)COVEREDCI matrix
Supply-chain hardeningCOVEREDPinned actions, harden-runner, Scorecard, Dependency Review
Performance regression trackingCOVEREDBenchmark dashboard with alerts
Language bindings (12 languages)COVEREDBindings CI on every push

What Is NOT Yet Covered (Future Work)What Is NOT Yet Covered (Future Work)

CategoryStatusNotes
Cross-library differential (vs bitcoin-core/libsecp256k1)NOT YETWould be strongest credibility signal for external auditors; nightly has test_cross_libsecp256k1 but not in unified runner
GPU correctness auditDEFERREDSeparate report when GPU side is complete
GPU memory safety (compute-sanitizer)DEFERREDSeparate report
Reproducible build proofNOT YETTwo independent machines -> identical binary hash
SBOM (CycloneDX/SPDX)PARTIALGenerated in release pipeline
Deep dudect (perf counters, cache probes)PARTIALdudect full runs nightly; perf stat / cache analysis not automated

Full Platform MatrixFull Platform Matrix

PlatformArchitectureCompilerBuildTestSanitizersFuzz
Linuxx86_64gcc-13Debug+ReleaseCTest 24/24--
Linuxx86_64clang-17Debug+ReleaseCTest 24/24ASan+UBSan, TSanlibFuzzer
Linuxaarch64aarch64-g++-13Release (cross)Binary verify--
Windowsx86_64MSVC 2022ReleaseCTest 24/24--
macOSARM64Apple ClangReleaseCTest + Metal--
iOSARM64XcodeReleaseStatic lib--
iOS Simulatorx86_64/ARM64XcodeReleaseStatic lib--
Androidarm64-v8aNDK r27cReleaseBinary verify--
Androidarmeabi-v7aNDK r27cReleaseBinary verify--
Androidx86_64NDK r27cReleaseBinary verify--
ROCm/HIPgfx906-gfx1100hipccReleaseCPU tests--
WASMwasm32Emscripten 3.1.51ReleaseNode.js bench--
X64 Localx86_64Clang 21.1.0Release55/55 audit--
ARM64 Localaarch64Cross (QEMU)Release24/24 CTest--
RISC-V Localrv64gcCross (QEMU)Release24/24 CTest--
RISC-V HWJH7110 U74Clang 21.1.8Release55/55 audit--

Total: 16 platform/compiler combinations, 7 architectures, 5 operating systems.


How to RunHow to Run

# Configure
cmake -S Secp256K1fast -B build_rel -G Ninja -DCMAKE_BUILD_TYPE=Release

# Build
cmake --build build_rel -j

# Run all CTest targets
ctest --test-dir build_rel --output-on-failure

# Run unified audit only
./build_rel/audit/unified_audit_runner

# Run libFuzzer harnesses (requires clang)
cd cpu/fuzz
clang++ -fsanitize=fuzzer,address -O2 -std=c++20 \
  -I ../include fuzz_field.cpp ../src/field.cpp -o fuzz_field
./fuzz_field -max_len=64 -runs=10000000

# Run with sanitizers
cmake -S . -B build/asan -DCMAKE_BUILD_TYPE=Debug \
  -DCMAKE_CXX_COMPILER=clang++-17 \
  -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer" \
  -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined" \
  -DSECP256K1_BUILD_TESTS=ON
cmake --build build/asan -j
ctest --test-dir build/asan --output-on-failure

# Run Valgrind
valgrind --leak-check=full --error-exitcode=1 ./build_rel/audit/unified_audit_runner

Generated from unified_audit_runner v3.14.0 output + CI workflow analysis on 2026-02-25.