Skip to content

perf: accelerate BLS12-381 deserialization with blst - #124

Open
PastaPastaPasta wants to merge 8 commits into
dashpay:developfrom
PastaPastaPasta:feat/blst-deserialization
Open

perf: accelerate BLS12-381 deserialization with blst#124
PastaPastaPasta wants to merge 8 commits into
dashpay:developfrom
PastaPastaPasta:feat/blst-deserialization

Conversation

@PastaPastaPasta

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

BLS12-381 point deserialization in this library is slow. Checked
FromBytes pays for point decompression (a field square root) plus a
subgroup 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).

  • Vendor blst v0.3.16 (commit e7f90de) into depends/blst (C sources,
    the pre-generated per-platform assembly, and the two public headers
    only — no language bindings, tests, or the experimental CHERI support).
  • Build it as a static/convenience library folded into dashbls in both
    build systems, enabled automatically only on little-endian
    x86_64/aarch64 hosts (--enable-blst=auto / USE_BLST cmake 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/G2Element FromBytes/FromBytesUnchecked now try a blst
    fast path first: decompression via blst_p1/p2_uncompress and, for
    the 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 the
    same acceleration for affine points.
  • On the platforms where the fast path is compiled, blst and relic use
    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 is
    copied limb-for-limb into relic's point struct (affine, z = 1,
    coord = BASIC, matching ep_norm output 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):

  • The fast path only decides inputs both implementations provably agree
    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.
  • 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.
  • bls::SetDeserializationFastPathEnabled() is a runtime toggle (default
    on) 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 develop today — configure_file() (cmake)
and AC_CONFIG_HEADERS (autotools) both templated
depends/relic/include/relic_conf.h.in, but with incompatible syntax
(#cmakedefine vs. autoconf's #undef placeholders), so autotools's
config.status silently passes the cmake directives through unmodified
into 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.in and pointed depends/relic/CMakeLists.txt's
configure_file() at it, letting autoheader generate a proper
autoconf-flavored relic_conf.h.in on every ./autogen.sh (this already
matches the project's own .gitignore, which excludes
relic_conf.h.in — it just wasn't being honored because the file
predates that rule).

Performance (Apple M1; relative numbers are what matters, both paths
measured in the same process via the runtime toggle, runbench's new
benchDeserialize()):

operation relic only blst fast path speedup
G1 FromBytes, checked (pubkey) 195us 55us 3.5x
G1 FromBytes, legacy 34us 15us 2.5x
G2 FromBytes, checked (sig) 208us 73us 2.9x
G2 FromBytes, legacy 86us 26us 3.4x

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?

  • New runtest differential 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), points
    on 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 CheckValid tests.
  • Standalone differential fuzzing during development (not part of this
    PR, used to validate the approach before writing the permanent tests):

    65,000 randomized cases with zero mismatches. This caught one real
    edge case: 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); IsValid() now excludes that
    case explicitly.

  • Full runtest suite passes on this branch: 5371 assertions, 18 test
    cases (relic-conf-fix + blst commits combined).
  • Verified from a single clean checkout of this branch, in both build
    systems:
    • autotools: ./autogen.sh && ./configure --enable-optimizations && make — builds and ./runtest passes, with blst enabled (default on
      this host) and with --disable-blst (pure relic fallback).
    • cmake: default configure/build — builds and runtest passes, with
      blst enabled (default USE_BLST=ON on this host) and with
      -DUSE_BLST=OFF (pure relic fallback).
  • New runbench benchmark (benchDeserialize) added so the improvement
    is 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:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

PastaPastaPasta and others added 7 commits July 10, 2026 11:12
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>
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 06b30f63-cc68-4ac5-997c-319e38f28f33

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@thepastaclaw

thepastaclaw commented Jul 10, 2026

Copy link
Copy Markdown

✅ 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 thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread CMakeLists.txt
Comment on lines +119 to +136
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()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Suggested change
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']

Comment thread CMakeLists.txt
Comment on lines +119 to +132
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()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Suggested change
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']

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants