Release date: 2026-04-04
Previous release: v3.50.0 (2026-03-XX)
Commits since v3.50.0: 50+
ABI-compatible with v3.50.x — drop-in upgrade
Security & Correctness
- ECDSA large-x fix (
cpu/src/ecdsa.cpp) — corrected r_less_than_pmn comparison in both FE52 and 4×64 paths. Wrong PMN constants assumed limb[2]=0; actual p−n has limb[2]=1. Signatures where k·G.x ∈ [n, p−1] (~2⁻¹²⁸ probability per sig) were incorrectly rejected. Equivalent to the Stark Bank CVE-2021-43568..43572 false-negative class. Found and confirmed by Wycheproof tcId 346. ([`ea8cfb3c`])
- ECDSA r-overflow test suite (
audit/test_exploit_ecdsa_r_overflow.cpp) — 19 checks: k·G.x ≥ n accept case (tcId 346), r=p−3 strict-parse rejection, r=n zero-reduction reject, r=0 reject, range sanity and sign/verify consistency. Closes Wycheproof PR #206 / Stark Bank CVE assurance gap.
- Wycheproof ECDSA Bitcoin vectors (
audit/test_wycheproof_ecdsa_bitcoin.cpp) — 53 checks: BIP-62 low-S enforcement, tcId 346/347/348/351, high-S malleability boundary, r=0/s=0 special-value rejection, point-at-infinity rejection during verify.
- CUDA
jacobian_add_mixed_unchecked infinity flag — missing r->infinity = false in the normal code path caused generator table entries table[3..15] to carry uninitialized infinity flags. Scalars with many consecutive high nibbles (e.g. n−1) hit table[15] and produced wrong public keys. All 52/52 CUDA signing tests now pass.
- ASan/UBSan clean: 210/210 C++ tests pass under
-fsanitize=address,undefined -fno-sanitize-recover=all after full rebuild.
Exploit PoC / Audit Coverage (Wave II)
| Suite | Tests | What it proves |
test_exploit_schnorr_nonce_reuse.cpp | SNR-1..16 | Nonce reuse → full privkey recovery via d' = (s1−s2)·(e1−e2)⁻¹ mod n; RFC6979 safety |
test_exploit_bip32_child_key_attack.cpp | CKA-1..18 | xpub + child_sk → parent_sk recovery; chained grandchild→child→master; hardened blockage |
test_exploit_frost_identifiable_abort.cpp | FIA-1..14 | frost_verify_partial() correctly attributes bad partial sigs; multi-cheater, honest subset |
test_exploit_hash_algo_sig_isolation.cpp | HAS-1..11 | Cross-hash confusion rejected; Schnorr↔ECDSA format confusion; domain prefix isolation |
test_exploit_zk_adversarial.cpp | 14 tests | Malformed/forged ZK proofs: garbage bytes, scalar overflow, identity pubkey, 64-byte-flip |
test_exploit_pedersen_adversarial.cpp | 12 tests | Switch commitment security, imbalanced verify_sum, double-spend detection |
test_exploit_ethereum_differential.cpp | 10 tests | go-ethereum / web3.py / ethers.js KAT vectors, ecrecover, EIP-155/EIP-191, keccak256 |
test_fuzz_musig2_frost.cpp | 15 tests | MuSig2 key_agg/nonce_agg/partial_verify; FROST keygen/sign/verify random inputs (5000+ rounds) |
test_wycheproof_ecdsa_bitcoin.cpp | 53 checks | Wycheproof BIP-62 + large-x vectors |
test_exploit_ecdsa_r_overflow.cpp | 19 checks | Wycheproof PR #206 r-overflow class |
| EIP-712 KAT | 12 tests | Typed structured data, 13 assertions |
Python Dynamic Audit Suite (9 CTest targets)
All powered by --lib path/to/libufsecp.so, integrated in CI and unified_audit_runner:
| CTest target | Checks | What it catches |
py_differential_crossimpl | 1000+ | Wrong low-S, pubkey parity bugs, ECDH mismatches (vs coincurve + python-ecdsa) |
py_nonce_bias | 10,000+ ops | Chi-squared + KS + per-bit sweep (Minerva/TPM-FAIL-class biases) |
py_rfc6979_spec | 200+ | Independent RFC 6979 §3.2 HMAC-SHA256 nonce derivation + Appendix A.2.5 KAT |
py_bip32_cka | — | Live BIP-32 parent key recovery demo + hardened immunity |
py_glv_exhaustive | 5000+ scalars | GLV decomposition — adversarial Babai-boundary scalars vs coincurve reference |
py_semantic_props | 1450+ | Algebraic properties (kG+lG==(k+l)G), roundtrip, determinism, Hypothesis |
py_invalid_input_grammar | 37 | Structured rejection — bad prefix, x≥p, sk=0/n, r=0/s=0, invalid BIP-32 paths |
py_stateful_sequences | 401+ | Error-injection recovery, BIP-32 multi-level consistency, 5000-op endurance |
py_dev_bug_scan | 221 files | 15-category static scanner: NULL, CPASTE, SIG, RETVAL, MSET, OB1, ZEROIZE, … |
- ClusterFuzzLite expanded to 5 targets: added
fuzz_ecdsa.cpp (sign→verify invariant, wrong-msg, compact parse) and fuzz_schnorr.cpp (BIP-340 sign→verify, adversarial from_bytes).
| Path | Before | After | Delta |
| CUDA ECDSA Sign (w=8 generator table) | 220.9 ns | 198.3 ns | −10.2% |
| CUDA/OpenCL/Metal MSM (GLV Shamir w=1 scatter) | baseline | +18–24% | +18–24% |
| ARM64 ECDSA Sign (SHA-2 HW accel) | 25.89 µs | 22.22 µs | −14.2% |
| ARM64 Schnorr Sign (precomputed) | 17.73 µs | 16.67 µs | −6.0% |
| Bulletproof MSM verifier | 5,079 µs | 2,634 µs | −48% (1.93×) |
| CPU KPlan zero-alloc (stack wnaf arrays) | heap | stack | alloc eliminated |
| BIP-352 SHA-256 tag midstate | per-call | precomputed | hash call eliminated |
precompute (scalar_mul_generator) | 2 heap allocs | 0 | zero-alloc hot path |
Zero-Knowledge Proof Layer (new)
- Knowledge proofs — non-interactive Schnorr PoK, Fiat-Shamir with tagged SHA-256, no trusted setup.
- DLEQ proofs — discrete log equality, batch-verify capable.
- Bulletproof range proofs — 64-bit range, MSM-optimized verifier (Pippenger + Montgomery batch inversion).
- GPU ZK: CUDA CT kernels (
ct_zk.cuh), OpenCL (secp256k1_zk.cl), Metal (kernels 19–22), all batch-capable.
- 5 new GPU C ABI functions:
ufsecp_gpu_zk_knowledge_verify_batch, ufsecp_gpu_zk_dleq_verify_batch, ufsecp_gpu_bulletproof_verify_batch, ufsecp_gpu_bip324_aead_encrypt_batch, ufsecp_gpu_bip324_aead_decrypt_batch.
- 24 tests in
test_zk.cpp; 8.5 benchmarks in bench_unified.
Full GPU Parity (zero Unsupported stubs)
- Bulletproof on OpenCL + Metal: removed
#if 0 guard in secp256k1_zk.cl; fixed address-space qualifiers; wired bulletproof_verify_batch on both backends. CUDA ↔ OpenCL ↔ Metal parity complete.
- 4 new OpenCL kernels wired:
zk_knowledge_verify_batch, zk_dleq_verify_batch, bip324_aead_encrypt_batch, bip324_aead_decrypt_batch.
- 4 Metal kernels connected: same 4 operations — kernels existed but dispatch was unwired.
- Metal ZK fix:
zk_knowledge_verify_batch was treating pubkey buffer as a scalar; corrected to lift_x to recover full point.
- CUDA 13 compatibility: replaced deprecated
cudaDeviceProp::clockRate / ::memoryClockRate with cudaDeviceGetAttribute. Backward-compatible with CUDA 12. (RTX 5080 / CUDA 13 reported by @craigraw)
- Unified Wallet API (
wallet.hpp/wallet.cpp) — chain-agnostic key management, address generation, message signing, pubkey recovery — Bitcoin, Ethereum, Tron, and all 28 coins from a single wallet:: namespace.
- BIP-39 Mnemonic (
bip39.hpp/bip39.cpp) — entropy→mnemonic (12–24 words), validation, PBKDF2-HMAC-SHA512 seed derivation. 57 tests.
- Bitcoin message signing (
message_signing.hpp) — BIP-137/Electrum compatible: sign, verify, recover, Base64.
- P2SH-P2WPKH (nested SegWit, BIP-49) —
3... addresses.
- P2SH and P2WSH primitives.
- CashAddr (BIP-0185) —
bitcoincash:q... addresses.
- Tron (TRX) coin — coin_type=195,
0x41 prefix + Keccak-256 + Base58Check. Now 28 coins total.
Bindings
- Stable validation closure across 11 language bindings: C#, Java, Swift, Python, Go, Rust, Node.js, PHP, Ruby, Dart, React Native. Fixed wrapper/API drift, zero-length FFI buffer edge cases, Dart
NativeFinalizer, local Dart smoke-runner.
Audit Coverage Summary
| Surface | Count |
C ABI functions (ufsecp_*) | 155 |
GPU C ABI functions (ufsecp_gpu_*) | 23 |
| Unified audit runner modules | 70 |
| Python CTest audit targets | 9 |
| ClusterFuzz targets | 5 |
| Exploit PoC test files | 13 |
| Active GPU Unsupported stubs | 0 |
CI/CD
- All jobs green on: Linux (GCC + Clang), macOS (arm64 + amd64), Windows, Android (ARM64), RISC-V, ARM64 cross, ROCm, CUDA.
- Fixed: macOS
externally-managed-environment, Windows Unicode cp1252, Python-order CMake embed, ASan/MSan/TSan py_* symbol issue, SonarCloud coincurve missing.
- 10 CodeQL code-scanning alerts resolved.
Full diff: v3.50.0...v3.60.0