perf: accelerate BLS12-381 deserialization with blst - #124
perf: accelerate BLS12-381 deserialization with blst#124PastaPastaPasta wants to merge 8 commits into
Conversation
autoreconf's AC_CONFIG_HEADERS([depends/relic/include/relic_conf.h]) and CMake's configure_file() both templated the same source file (depends/relic/include/relic_conf.h.in), but with incompatible syntax: CMake's #cmakedefine directives vs. autoconf's #undef placeholders that autoheader auto-generates. Since the checked-in file used CMake syntax, autoconf's config.status doesn't understand \#cmakedefine and copies those lines through unmodified into the generated header, breaking every autotools build on a completely clean checkout (before any of this PR's changes): 'invalid preprocessing directive' for #cmakedefine lines. Rename the checked-in CMake template to relic_conf.h.in.cmake.in and point depends/relic/CMakeLists.txt's configure_file() at it. Drop relic_conf.h.in itself from version control (matches the existing .gitignore entry, which already excluded it -- it just wasn't being honored because the file predates the ignore rule); autoreconf/autoheader regenerate an autoconf-flavored relic_conf.h.in from configure.ac's AC_DEFINE calls on every ./autogen.sh, exactly as intended. This is a prerequisite for validating the following blst-acceleration commits under both build systems from a single clean checkout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Import the blst BLS12-381 library (https://github.com/supranational/blst) at v0.3.16 (e7f90de551e8df682f3cc99067d204d8b90d27ad): C sources, the pre-generated assembly for x86_64/aarch64 (ELF, Mach-O, COFF and MASM flavours), and the two public headers. Bindings for other languages, tests and the experimental CHERI support are not imported. blst is Apache 2.0 licensed and is the de-facto standard high-performance BLS12-381 implementation (used throughout the Ethereum ecosystem, audited in 2021 by NCC Group). It will be used to accelerate point deserialization while relic remains the backend for all other operations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Build the vendored blst as a libtool convenience library (libblst.la) folded into libdashbls.la, and define BLS_USE_BLST for the dashbls sources when it is enabled. blst is enabled automatically only on little-endian x86_64/aarch64 hosts (--enable-blst=auto), where the bundled assembly is supported and where relic's internal field-element layout (6x64-bit little-endian limbs in Montgomery form with R = 2^384) matches blst's exactly. All other platforms (32-bit ARM, riscv64, ppc64, Emscripten, big-endian) keep the pure relic path and do not compile blst at all. On x86_64 the assembly is built with -D__BLST_PORTABLE__, which compiles both the ADX and the generic code paths and selects between them at run time, so release binaries stay portable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add depends/blst/CMakeLists.txt, compiling the vendored library's single C translation unit (src/server.c, which #includes every other .c file) plus the pre-generated assembly (build/assembly.S, which #includes the correct flavour for the target OS/ABI) into a small static library. Wire it into the top-level CMakeLists.txt behind a USE_BLST option that defaults to on for little-endian x86_64/aarch64 hosts and off elsewhere (mirroring the autotools --enable-blst=auto gate), and link it into the dashbls target in src/CMakeLists.txt when enabled, defining BLS_USE_BLST. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Checked deserialization of a BLS12-381 point pays for decompression (a field square root) plus a subgroup membership check. Through relic on the GMP backend this costs ~195us per G1 public key and ~210us per G2 signature on an Apple M1. This cost is attacker-influenceable on any network message path that carries BLS keys or signatures, and is also paid throughout batch validation of large point sets. Route G1Element/G2Element FromBytes and FromBytesUnchecked through a blst fast path: decompression via blst_p1/p2_uncompress and, for the checked new-format path, subgroup checks via blst_p1/p2_affine_in_g1/g2 (the Scott 2021 membership test, https://eprint.iacr.org/2021/1130). IsValid() uses the same acceleration for affine points. Accepted points are copied limb-for-limb into relic's structs; on the platforms where the fast path is compiled both libraries use the identical in-memory field-element representation (enforced with static_asserts and verified by tests), and the constructed point matches ep_norm output exactly (affine, z = 1, coord = BASIC). Acceptance behaviour is preserved bit-for-bit, since deserialization acceptance is consensus-critical for downstream consumers such as Dash Core: - The fast path only decides inputs both implementations provably agree on: well-formed non-infinity compressed encodings that decompress onto the curve (plus subgroup membership when required). Everything else -- infinity encodings, malformed headers, x >= p, all-zero payloads, not-on-curve x values (which the legacy scheme historically accepts without throwing) -- falls back to the unchanged relic code path, keeping historical error types, messages, and legacy-scheme quirks. - A point that decompresses but fails the subgroup check throws the same std::invalid_argument as CheckValid() without re-running the relic path, so the attacker-controlled 'on curve but wrong subgroup' input class gets the fast rejection. - IsValid() excludes the all-zero affine point explicitly: blst treats an all-zero affine struct as infinity while relic treats it as an invalid point (reachable via the legacy scheme's acceptance of failed decompressions). bls::SetDeserializationFastPathEnabled() provides a runtime toggle (default on) for tests, benchmarking and as an escape hatch. Measured on Apple M1 (same process, fast path toggled): G1 FromBytes checked ~195us -> ~55us (~3.5x) G1 FromBytes legacy ~34us -> ~14us (~2.5x) G2 FromBytes checked ~209us -> ~71us (~2.9x) G2 FromBytes legacy ~88us -> ~26us (~3.4x) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Compare the blst fast path against the pure relic path (via the runtime toggle) and require identical outcomes -- throw/no-throw, point equality, serialization round-trip and IsValid() -- across: valid points in both schemes and both serialization formats, points on the curve but outside the r-order subgroup, canonical and non-canonical infinity encodings, all-zero payloads with every interesting header byte, bit-flip mutations of valid encodings, random buffers, and the known-invalid vectors already covered by the CheckValid tests. On builds without blst both runs use the relic path and the comparison is trivial, so the test is portable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add benchDeserialize() to runbench, timing FromBytes (including the subgroup check) for G1 (public keys) and G2 (signatures), in both the current and the legacy scheme, with the blst fast path enabled and with it disabled via SetDeserializationFastPathEnabled -- so the improvement from the previous commits is visible side by side in a single run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
✅ Final review complete — no blockers (commit fc7e967) |
The go-bindings Makefile and rust-bindings/bls-dash-sys/build.rs each build against the CMake-produced dashbls/relic_s/mimalloc static libraries directly, listing every dependency's -l flag by hand rather than going through CMake's target_link_libraries graph (which the python bindings use, and where blst's PUBLIC link property already propagates correctly). Since libdashbls.a now references blst symbols, both binding builds failed to link with undefined references to blst_p1/p2_* (CI: dashpay#124). Add the blst library search path and -lblst/rustc-link-lib next to the existing mimalloc linking, guarded on the library actually existing -- blst is only built on little-endian x86_64/aarch64 hosts, so 32-bit ARM, riscv64, ppc64 and big-endian builds keep linking exactly as before. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
PR #124 adds an opt-in blst fast path for BLS12-381 G1/G2 deserialization, falling back to relic wherever bit-identical behavior can't be proven, and backs it with a large differential test suite (65k+ fuzz cases plus a permanent test suite) — the cryptographic design and testing are solid, and neither security auditor found any exploitable code-path defect. The latest delta (fc7e967, Go/Rust binding link changes) is correct and matches the existing CMake USE_BLST gate. However, cumulative review of the build-system wiring turned up three real, verified gaps: the CMake install rules never install the new blst static archive even though libdashbls now depends on it (breaking installed-library consumers), the CMake USE_BLST auto-detection has no MSVC/Windows exclusion even though this repo builds Windows wheels and the vendored blst assembly can't be assembled by MSVC, and unlike the autotools path, CMake's USE_BLST detection doesn't exclude big-endian (-DBIGED=ON) builds, which would violate the little-endian layout invariant the whole fast path depends on.
Source: Sol reviewer general/security = gpt-5.6-sol (codex; completed_parseable / completed_parseable_exit_5); Sonnet reviewer general/security = claude-sonnet-5 (completed / completed); verifier = claude-sonnet-5 (sonnet5 primary, completed); Sol orchestrator = openai/gpt-5.6-sol, reasoning=high (orchestration-only; not a reviewer/verifier).
🔴 3 blocking
1 additional finding(s) omitted (not in diff).
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `src/CMakeLists.txt`:
- [BLOCKING] src/CMakeLists.txt:37-45: Installed libdashbls.a has unresolved blst symbols — blst is never installed
`dashbls` now links `PUBLIC blst` (line 39), so its object code calls into blst symbols (`blst_p1_*`, `blst_p2_*`), but only `libdashbls.a` itself is installed (line 45) — there is no `install(TARGETS blst ...)` anywhere, including in `depends/blst/CMakeLists.txt`, which defines the `blst` target but never installs it. This breaks the pattern the rest of the build already follows: `relic_s` is installed via `depends/relic/src/CMakeLists.txt:230` (`install(TARGETS ${RELIC_S} ARCHIVE DESTINATION lib)`) and `mimalloc-static` is installed via `depends/mimalloc/CMakeLists.txt:658`. Every other transitive static dependency of `dashbls` ends up in the install tree; blst is the one exception this PR introduces. A `cmake --install` after a `USE_BLST=ON` build produces an install tree where `libdashbls.a` has undefined references to blst symbols with no way to resolve them, since the archive that provides them was never installed. This was independently reproduced by one reviewer (build + install + `nm -u`).
In `CMakeLists.txt`:
- [BLOCKING] CMakeLists.txt:119-136: USE_BLST auto-enables on MSVC/Windows, but blst's CMake build only compiles GNU-flavour assembly
`BLST_SUPPORTED` is derived purely from `CMAKE_SYSTEM_PROCESSOR` matching x86_64/aarch64 and 8-byte pointers (lines 122–127) — nothing excludes MSVC. On a standard 64-bit Visual Studio configuration, `CMAKE_SYSTEM_PROCESSOR` reports `AMD64`, so `USE_BLST` defaults ON. But `depends/blst/CMakeLists.txt` calls `enable_language(ASM)` and compiles `build/assembly.S` directly (a GNU-`as`-flavoured file selected via C-preprocessor `#include`s) and unconditionally applies `-fno-builtin`, a GCC/Clang-only flag never gated behind `NOT MSVC`. MSVC's toolchain (`ml64`/`cl`) cannot assemble this file. The vendored blst tree separately ships MASM (`build/win64/*.asm`) sources for native Windows/MSVC builds, but nothing in this PR's CMake integration wires them in.
This isn't a hypothetical platform: `.github/workflows/build-wheels.yml` has a `windows-latest` matrix entry building Python wheels via cibuildwheel with no compiler override, implying the default MSVC toolchain. I confirmed via `gh api .../check-runs` on the reviewed SHA (fc7e9671) that no Windows check ran at all for this commit — so this regression is unverified by CI, not disproven by it.
- [BLOCKING] CMakeLists.txt:119-132: USE_BLST auto-detection doesn't exclude big-endian (BIGED) builds, unlike autotools
The blst fast path's entire safety argument rests on relic and blst sharing an identical in-memory field-element layout (6×64-bit little-endian limbs, Montgomery form). `configure.ac` explicitly protects this invariant: `blst_supported=no; if test x$use_big_endian != xyes; then case $host_cpu in x86_64|amd64|aarch64|arm64) blst_supported=yes ;; esac; fi` (configure.ac:448–455), gated on the same `--enable-big-endian` flag that controls relic's own `BIGED` define.
The CMake side has no equivalent: `BLST_SUPPORTED` (CMakeLists.txt:119–128) checks only `CMAKE_SYSTEM_PROCESSOR` and pointer size, never referencing the `BIGED` option that `depends/relic/CMakeLists.txt:48` itself defines (`option(BIGED "Build with big-endian support" off)`). A build configured with `-DBIGED=ON` on a big-endian aarch64 host would still get `USE_BLST=ON` by default, since nothing here consults `BIGED`. Because relic's field layout flips under `BIGED`, the limb-for-limb `memcpy` in `G1FromBytesBlst`/`G2FromBytesBlst` (src/elements.cpp) would silently produce corrupted points from valid input — a consensus-safety violation, not a build failure. This requires a non-default `-DBIGED=ON` configuration to trigger, so it's a narrow target, but it's a real asymmetry between the two build systems on a safety-load-bearing invariant, and this repo documents CMake as the primary standalone build system.
| if(EMSCRIPTEN) | ||
| set(BLST_SUPPORTED OFF) | ||
| else() | ||
| string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" BLST_HOST_PROCESSOR) | ||
| if(BLST_HOST_PROCESSOR MATCHES "^(x86_64|amd64|aarch64|arm64)$" AND CMAKE_SIZEOF_VOID_P EQUAL 8) | ||
| set(BLST_SUPPORTED ON) | ||
| else() | ||
| set(BLST_SUPPORTED OFF) | ||
| endif() | ||
| endif() | ||
| option(USE_BLST "Use the bundled blst library to accelerate BLS12-381 deserialization" ${BLST_SUPPORTED}) | ||
| if(USE_BLST AND NOT BLST_SUPPORTED) | ||
| message(FATAL_ERROR "blst is not supported on this host (requires little-endian x86_64 or aarch64)") | ||
| endif() | ||
| message(STATUS "Use blst: ${USE_BLST}") | ||
| if(USE_BLST) | ||
| add_subdirectory(depends/blst) | ||
| endif() |
There was a problem hiding this comment.
🔴 Blocking: USE_BLST auto-enables on MSVC/Windows, but blst's CMake build only compiles GNU-flavour assembly
BLST_SUPPORTED is derived purely from CMAKE_SYSTEM_PROCESSOR matching x86_64/aarch64 and 8-byte pointers (lines 122–127) — nothing excludes MSVC. On a standard 64-bit Visual Studio configuration, CMAKE_SYSTEM_PROCESSOR reports AMD64, so USE_BLST defaults ON. But depends/blst/CMakeLists.txt calls enable_language(ASM) and compiles build/assembly.S directly (a GNU-as-flavoured file selected via C-preprocessor #includes) and unconditionally applies -fno-builtin, a GCC/Clang-only flag never gated behind NOT MSVC. MSVC's toolchain (ml64/cl) cannot assemble this file. The vendored blst tree separately ships MASM (build/win64/*.asm) sources for native Windows/MSVC builds, but nothing in this PR's CMake integration wires them in.
This isn't a hypothetical platform: .github/workflows/build-wheels.yml has a windows-latest matrix entry building Python wheels via cibuildwheel with no compiler override, implying the default MSVC toolchain. I confirmed via gh api .../check-runs on the reviewed SHA (fc7e967) that no Windows check ran at all for this commit — so this regression is unverified by CI, not disproven by it.
| if(EMSCRIPTEN) | |
| set(BLST_SUPPORTED OFF) | |
| else() | |
| string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" BLST_HOST_PROCESSOR) | |
| if(BLST_HOST_PROCESSOR MATCHES "^(x86_64|amd64|aarch64|arm64)$" AND CMAKE_SIZEOF_VOID_P EQUAL 8) | |
| set(BLST_SUPPORTED ON) | |
| else() | |
| set(BLST_SUPPORTED OFF) | |
| endif() | |
| endif() | |
| option(USE_BLST "Use the bundled blst library to accelerate BLS12-381 deserialization" ${BLST_SUPPORTED}) | |
| if(USE_BLST AND NOT BLST_SUPPORTED) | |
| message(FATAL_ERROR "blst is not supported on this host (requires little-endian x86_64 or aarch64)") | |
| endif() | |
| message(STATUS "Use blst: ${USE_BLST}") | |
| if(USE_BLST) | |
| add_subdirectory(depends/blst) | |
| endif() | |
| if(BLST_HOST_PROCESSOR MATCHES "^(x86_64|amd64|aarch64|arm64)$" AND CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT MSVC) | |
| set(BLST_SUPPORTED ON) | |
| else() | |
| set(BLST_SUPPORTED OFF) | |
| endif() |
source: ['codex-general', 'sonnet5-general']
| if(EMSCRIPTEN) | ||
| set(BLST_SUPPORTED OFF) | ||
| else() | ||
| string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" BLST_HOST_PROCESSOR) | ||
| if(BLST_HOST_PROCESSOR MATCHES "^(x86_64|amd64|aarch64|arm64)$" AND CMAKE_SIZEOF_VOID_P EQUAL 8) | ||
| set(BLST_SUPPORTED ON) | ||
| else() | ||
| set(BLST_SUPPORTED OFF) | ||
| endif() | ||
| endif() | ||
| option(USE_BLST "Use the bundled blst library to accelerate BLS12-381 deserialization" ${BLST_SUPPORTED}) | ||
| if(USE_BLST AND NOT BLST_SUPPORTED) | ||
| message(FATAL_ERROR "blst is not supported on this host (requires little-endian x86_64 or aarch64)") | ||
| endif() |
There was a problem hiding this comment.
🔴 Blocking: USE_BLST auto-detection doesn't exclude big-endian (BIGED) builds, unlike autotools
The blst fast path's entire safety argument rests on relic and blst sharing an identical in-memory field-element layout (6×64-bit little-endian limbs, Montgomery form). configure.ac explicitly protects this invariant: blst_supported=no; if test x$use_big_endian != xyes; then case $host_cpu in x86_64|amd64|aarch64|arm64) blst_supported=yes ;; esac; fi (configure.ac:448–455), gated on the same --enable-big-endian flag that controls relic's own BIGED define.
The CMake side has no equivalent: BLST_SUPPORTED (CMakeLists.txt:119–128) checks only CMAKE_SYSTEM_PROCESSOR and pointer size, never referencing the BIGED option that depends/relic/CMakeLists.txt:48 itself defines (option(BIGED "Build with big-endian support" off)). A build configured with -DBIGED=ON on a big-endian aarch64 host would still get USE_BLST=ON by default, since nothing here consults BIGED. Because relic's field layout flips under BIGED, the limb-for-limb memcpy in G1FromBytesBlst/G2FromBytesBlst (src/elements.cpp) would silently produce corrupted points from valid input — a consensus-safety violation, not a build failure. This requires a non-default -DBIGED=ON configuration to trigger, so it's a narrow target, but it's a real asymmetry between the two build systems on a safety-load-bearing invariant, and this repo documents CMake as the primary standalone build system.
| if(EMSCRIPTEN) | |
| set(BLST_SUPPORTED OFF) | |
| else() | |
| string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" BLST_HOST_PROCESSOR) | |
| if(BLST_HOST_PROCESSOR MATCHES "^(x86_64|amd64|aarch64|arm64)$" AND CMAKE_SIZEOF_VOID_P EQUAL 8) | |
| set(BLST_SUPPORTED ON) | |
| else() | |
| set(BLST_SUPPORTED OFF) | |
| endif() | |
| endif() | |
| option(USE_BLST "Use the bundled blst library to accelerate BLS12-381 deserialization" ${BLST_SUPPORTED}) | |
| if(USE_BLST AND NOT BLST_SUPPORTED) | |
| message(FATAL_ERROR "blst is not supported on this host (requires little-endian x86_64 or aarch64)") | |
| endif() | |
| if(EMSCRIPTEN OR BIGED) | |
| set(BLST_SUPPORTED OFF) | |
| else() | |
| string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" BLST_HOST_PROCESSOR) | |
| if(BLST_HOST_PROCESSOR MATCHES "^(x86_64|amd64|aarch64|arm64)$" AND CMAKE_SIZEOF_VOID_P EQUAL 8) | |
| set(BLST_SUPPORTED ON) | |
| else() | |
| set(BLST_SUPPORTED OFF) | |
| endif() | |
| endif() |
source: ['sonnet5-general', 'sonnet5-security-auditor']
Issue being fixed or feature implemented
BLS12-381 point deserialization in this library is slow. Checked
FromBytespays for point decompression (a field square root) plus asubgroup membership check, all executed on relic's arithmetic. On an
Apple M1 this costs ~195us per G1 public key and ~210us per G2 signature.
Anywhere a consumer deserializes attacker-supplied points (network
message paths, batch/bulk validation of large point sets) this is a
meaningful CPU cost and a potential DoS vector.
What was done?
Use blst v0.3.16 to accelerate
BLS12-381 point deserialization and validation, while keeping relic as
the arithmetic backend for every other operation (signing, pairing,
aggregation, etc. are untouched).
e7f90de) intodepends/blst(C sources,the pre-generated per-platform assembly, and the two public headers
only — no language bindings, tests, or the experimental CHERI support).
dashblsin bothbuild systems, enabled automatically only on little-endian
x86_64/aarch64 hosts (
--enable-blst=auto/USE_BLSTcmake option).All other platforms (32-bit ARM, riscv64, ppc64, Emscripten,
big-endian) keep the pure relic path unchanged and don't compile blst
at all. On x86_64 the assembly is compiled with
-D__BLST_PORTABLE__,which selects the ADX code path at run time, keeping release binaries
portable.
G1Element/G2ElementFromBytes/FromBytesUncheckednow try a blstfast path first: decompression via
blst_p1/p2_uncompressand, forthe checked non-legacy path, subgroup checks via
blst_p1/p2_affine_in_g1/g2(the Scott 2021 membership test,https://eprint.iacr.org/2021/1130).
IsValid()/CheckValid()use thesame acceleration for affine points.
an identical in-memory field-element representation (6x64-bit
little-endian limbs, Montgomery form with R = 2^384) — enforced with
static_asserts and verified by tests — so an accepted point iscopied limb-for-limb into relic's point struct (affine,
z = 1,coord = BASIC, matchingep_normoutput exactly).Acceptance behaviour is preserved bit-for-bit, since deserialization
acceptance is consensus-critical for downstream consumers (this library
is used by Chia and Dash Core, among others):
on: a well-formed non-infinity compressed encoding that decompresses
onto the curve (plus subgroup membership when required). Everything
else — infinity encodings, malformed headers, x >= p, all-zero
payloads, not-on-curve x values (which the legacy scheme historically
accepts without throwing) — falls back unchanged to the original relic
path, keeping historical error types, messages, and legacy-scheme
quirks.
std::invalid_argumentasCheckValid()without re-running the relicpath, so the attacker-controlled "on curve but wrong subgroup" input
class gets the fast rejection.
bls::SetDeserializationFastPathEnabled()is a runtime toggle (defaulton) for tests, benchmarking, and as an escape hatch.
Also included, as a build prerequisite (first commit): a fix for a
pre-existing, unrelated bug that breaks the autotools build on a
completely clean checkout of
developtoday —configure_file()(cmake)and
AC_CONFIG_HEADERS(autotools) both templateddepends/relic/include/relic_conf.h.in, but with incompatible syntax(
#cmakedefinevs. autoconf's#undefplaceholders), so autotools'sconfig.statussilently passes the cmake directives through unmodifiedinto the generated header and the build fails with "invalid
preprocessing directive". I needed autotools working to validate this
PR, so I fixed it: renamed the checked-in cmake template to
relic_conf.h.cmake.inand pointeddepends/relic/CMakeLists.txt'sconfigure_file()at it, lettingautoheadergenerate a properautoconf-flavored
relic_conf.h.inon every./autogen.sh(this alreadymatches the project's own
.gitignore, which excludesrelic_conf.h.in— it just wasn't being honored because the filepredates that rule).
Performance (Apple M1; relative numbers are what matters, both paths
measured in the same process via the runtime toggle,
runbench's newbenchDeserialize()):x86_64 gains are expected to be at least as large (blst's ADX assembly
vs. relic's GMP backend).
How Has This Been Tested?
runtestdifferential suite (Accelerated deserialization differential) comparing the fast path against the pure relic path(via the runtime toggle) and requiring identical outcomes —
throw/no-throw, point equality, serialization round-trip, and
IsValid()— across: valid points (both schemes, both formats), pointson the curve but outside the r-order subgroup, canonical/non-canonical
infinity encodings, all-zero payloads, header corner cases, bit-flip
mutations of valid encodings, random buffers, and the known-invalid
vectors already covered by the existing
CheckValidtests.PR, used to validate the approach before writing the permanent tests):
runtestsuite passes on this branch: 5371 assertions, 18 testcases (relic-conf-fix + blst commits combined).
systems:
./autogen.sh && ./configure --enable-optimizations && make— builds and./runtestpasses, with blst enabled (default onthis host) and with
--disable-blst(pure relic fallback).runtestpasses, withblst enabled (default
USE_BLST=ONon this host) and with-DUSE_BLST=OFF(pure relic fallback).runbenchbenchmark (benchDeserialize) added so the improvementis directly visible in a normal benchmark run, printed side by side
for the fast path and the relic-only path.
Breaking Changes
None. Serialization formats, acceptance semantics, and all public APIs
are unchanged. Builds on platforms without blst support (or with it
explicitly disabled) are unaffected — pure relic path, byte-for-byte the
same as before this PR.
Checklist: