DEV Community

Vano Chkheidze
Vano Chkheidze

Posted on

UltrafastSecp256k1 v3.60

v3.60.0 — Audit Campaign Wave II · ZK Layer · Full GPU Parity · Wallet API · Performance

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).

Performance

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)

Wallet API & Address Formats (new)

  • 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

Top comments (0)