Skip to content

feat: revive Python binds requiring Python >=3.10, rename to dashbls, repair setup.py to work on Windows, update authorship, drop unmaintained parallel impl, shave down README, add build and publish script - #125

Merged
PastaPastaPasta merged 31 commits into
dashpay:developfrom
kwvg:pybinds
Aug 11, 2026

Conversation

@kwvg

@kwvg kwvg commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Motivation

By and large since forking from upstream the Python binds have been unmaintained as we've had no active consumers for it but work on base-sdk's pkc crate like dashpay/base-sdk#20 and its cousin agora-blsful are both in requirement of one common thing, the ability to invoke this library as and when new edge cases are discovered when establishing implementation conformity.

At least for base-sdk's pkc, this was done by writing C++ code linked against dashbls to generate the necessary vectors (see corpus) and then import them but dashpay/base-sdk#20 was a result of newer edge cases surfacing as a result of the API being refined and as it revealed a need to extend test vectors, provenance became a sticking issue, the need

  • To prove these vectors are genuine (as we also have a pre-specification scheme);
  • To be able to generate more of them as newer cases are discovered; and
  • In a manner that any person seeking to verify them can do so trivially

This pull request attempts to address this by reviving the Python bindings to allow dashbls to serve as an oracle both during development and during optimisation work. This pull request does not include updating the binds to be API-complete, the scope is limited to getting to a point where the binds work at all.

Additional Information

  • G1Element and G2Element exposed __mul__ and __rmul__ taking bn_t, a relic array typedef that pybind11 has no type caster for, so every call raised TypeError regardless of the argument and the operators were unreachable from Python. This has been resolved by binding against const PrivateKey&.

  • from_message() was bound through py::overload_cast onto a C++ signature taking a bare const uint8_t* with a separate length argument, a shape pybind11 cannot convert a Python object into, which left the domain separation tag impossible to supply from Python. This has been resolved with an explicit static method taking msg and dst as bytes.

  • relic caps the domain separation tag at 255 bytes but compares the length as a signed int (source), so a tag >= 2 GiB, passes the check and is then widened back to an enormous length inside the hash. The binds now reject any tag longer than 255 bytes before that cast can happen.

  • Upstream had retired their codebase on Jul 3, 2025 (source) and the contents of our codebase have reasonably diverged to the point that the README says almost nothing about our codebase. As updating references to blspy (Chia's name for their Python bindings) were part of this PR, it was preferable to rip the bandaid off and rewrite the README to be minimal.

  • The Python-only parallel implementation has bitrotted due to lack of supervision or usage, on that account it has been dropped wholesale. Binds, while posing their own disadvantages, are a facade over the C++ implementation used in Dash Core and serves as a more reliable oracle.

  • Since bls-signatures#116 the de facto minimum CMake version was 3.18 (Debian trixie ships with 3.31, source) but some files, notably the root definition still used 3.14, which gives off an incorrect impression as attempting to use 3.14 would result in hard errors.

  • To make the package maintainable the set of released wheels reasonable (as every version of Python from minimum supported to tip needs to be built times the number of supported platforms), we have opted to set the minimum required Python to 3.10 (trixie ships with 3.13, source), the same minimum version used by Dash Core (source)

  • The Python-specific README was dropped in favour of a samples directory that is then included in the unit test suite to prove the API correctness of them in every build.

  • The macOS wheels do not use GMP because Homebrew ships their prebuilt packages targeting the version of macOS requesting the download, since our target version is macOS 14 and the GitHub Runners are on macOS 26, we are unable to generate the wheel. For an oracle, the performance degradation is tolerable.

  • The CI builds for Linux use manylinux_2_28 as Dash Core requires glibc 2.31 (source) and the closest version without going over that has available builds is targeting glibc 2.28.

  • To allow casual installation without having to guide a user through wheels or placing a package that very likely is liable to be sunset in the not-too-distant-future on PyPi, we generate a PEP 503 index and simply host it using GitHub Pages, installation therefore would look something the command below with the added bonus of being pre-built, so no compilation needed!

    pip install --index-url https://dashpay.github.io/bls-signatures/pep503 dashbls
    

    Note that we need to update Environments to allow v* tags or the Pages deployment will fail.

  • Windows on ARM (windows-arm64) had to be dropped despite Python itself supporting it since the vendored copy of relic does not properly treat Windows for ARM as a valid target due to its unconditional use of _umul128, _udiv128 and __lzcnt64, which are AMD64-specific.

    As bumping relic was decided against in dashpay/bls-signatures#93 and patching relic has a unknown payoff, it was decided to drop the target instead.

  • To allow the binds to build at all MULTI was disabled, meaning relic shares a shared global context. This was necessary because MSVC rejects OpenMP's threadprivate pragma and glibc rejected thread-local storage blocks at the sizes demanded by relic. This is only acceptable because we don't offer free-threaded builds and extension modules hold the GIL.

Breaking changes

None expected.

How Was This Tested?

$ python --version
Python 3.10.20

$ pip install --index-url https://kwvg.github.io/bls-signatures/simple dashbls
Looking in indexes: https://kwvg.github.io/bls-signatures/simple
Collecting dashbls
  Downloading dashbls-2.1.0-cp310-cp310-macosx_14_0_arm64.whl (382 kB)
Installing collected packages: dashbls
Successfully installed dashbls-2.1.0

$ ./binds/python/samples/creating_keys_and_signatures.py
public key: 86243290bbcbfd9ae75bdece7981965350208eb5e99b04d5cd24e955ada961f8c0a162dee740be7bdc6c3c0613ba2eb1
signature:  b00ab9a8af54804b43067531d96c176710c05980fccf8eee1ae12a4fd543df929cce860273af931fe4fdbc407d495f73114ab7d17ef08922e56625daada0497582340ecde841a9e997f2f557653c21c070119662dd2efa47e2d6c5e2de00eefa

Build

Summary by CodeRabbit

  • New Features

    • Introduced the dashbls Python package with CMake-based builds and improved validation.
    • Added Python examples for signing, aggregation, key derivation, serialization, and proof of possession.
    • Added automated build, test, release, and package-index workflows for Python, JavaScript, Go, and Rust bindings.
    • Added benchmark coverage and comprehensive Python tests.
  • Documentation

    • Updated project documentation with build requirements, usage guidance, security notices, and licensing information.
    • Added third-party licensing details.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

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 Plus

Run ID: 88f67a90-def1-45d8-a882-43acc9b197ea

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
📝 Walkthrough

Walkthrough

The project moved to CMake-based Python packaging under dashbls, added guarded Python bindings with expanded tests and samples, split binding builds into reusable workflows, and added GitHub Pages package indexing. Repository metadata, documentation, manifests, and development tooling were updated.

Changes

Dash BLS packaging and binding migration

Layer / File(s) Summary
CMake packaging and project metadata
CMakeLists.txt, binds/python/CMakeLists.txt, pyproject.toml, setup.py, MANIFEST.in, .python-version
Python packaging now builds the dashbls extension through CMake 3.18+, with pinned pybind11 fallback support, updated project metadata, cibuildwheel settings, and manifest exclusions.
Python binding API and validation
binds/python/pythonbindings.cpp, binds/python/test_unit.py, binds/python/samples/*, binds/python/test_bench.py, binds/python/conftest.py
The extension now uses guarded Relic access and centralized buffer validation. Message mapping, scalar multiplication, serialization, aggregation, samples, unit tests, and benchmarks were added or updated.
Binding workflows and package publishing
.github/workflows/binds-*.yml, .github/workflows/build-binds.yml, .github/workflows/build-docs.yml, .github/scripts/build_simple_index.py
Reusable Go, JavaScript, Python, and Rust workflows build bindings. Python releases upload artifacts and publish a PEP 503 index through GitHub Pages.
Repository documentation and developer tooling
README.md, NOTICE, .gitignore, .vscode/*, autogen.sh, mypi.ini
Documentation, third-party notices, ignore rules, editor recommendations, header generation, and mypy configuration were updated.

Estimated code review effort: 5 (Critical) | ~90+ minutes

Suggested reviewers: knst, pastapastapasta, udjinm6

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.46% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes, including revived Python bindings, the dashbls rename, packaging fixes, implementation removal, documentation updates, and publishing workflows.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@thepastaclaw

thepastaclaw commented Aug 2, 2026

Copy link
Copy Markdown

⛔ Blockers found — Opus deferred (commit fe6fbf7)
Canonical validated blockers: 1

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 12

🧹 Nitpick comments (4)
setup.py (1)

1-2: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the # coding: latin-1 declaration from both new files. Python 3 source defaults to UTF-8, so the declaration is obsolete and it actively misdecodes any non-ASCII character added later, for example an accented author name or a typographic dash in a docstring.

  • setup.py#L1-L2: delete the # coding: latin-1 line.
  • .github/scripts/build_simple_index.py#L1-L2: delete the # coding: latin-1 line.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@setup.py` around lines 1 - 2, Remove the obsolete “# coding: latin-1”
declaration from setup.py lines 1-2 and .github/scripts/build_simple_index.py
lines 1-2, leaving Python 3’s default UTF-8 source encoding in effect.
binds/python/CMakeLists.txt (1)

14-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

${INCLUDE_DIRECTORIES} expands to nothing.

INCLUDE_DIRECTORIES is a directory property, not a variable. The reference on Line 15 is empty unless a same-named variable exists. Remove it, and prefer target-scoped includes on dashbls_py.

♻️ Proposed cleanup
-include_directories(
-        ${INCLUDE_DIRECTORIES}
-        ${CMAKE_CURRENT_SOURCE_DIR}
-        ${CMAKE_CURRENT_SOURCE_DIR}/../../include
-)
-
 pybind11_add_module(dashbls_py ${CMAKE_CURRENT_SOURCE_DIR}/pythonbindings.cpp)
+target_include_directories(dashbls_py PRIVATE
+        ${CMAKE_CURRENT_SOURCE_DIR}
+        ${CMAKE_CURRENT_SOURCE_DIR}/../../include
+)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@binds/python/CMakeLists.txt` around lines 14 - 18, Remove the empty
${INCLUDE_DIRECTORIES} entry from the include_directories block and configure
the dashbls_py target with target-scoped include directories instead, preserving
the current source and ../../include paths.
.github/scripts/build_simple_index.py (1)

55-98: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider emitting data-requires-python on each anchor.

The project declares requires-python = ">=3.10". Without a data-requires-python attribute, pip on Python 3.9 selects the sdist and fails during the build instead of reporting that no compatible distribution exists. The value is available from each release asset's metadata, or it can be a constant that mirrors pyproject.toml.

The empty-index guard at Line 72 is a good safeguard against overwriting a working index.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/scripts/build_simple_index.py around lines 55 - 98, Update the
distribution anchor generation in main to emit a data-requires-python attribute
for every wheel and sdist, using the release asset metadata when available or a
constant matching pyproject.toml’s >=3.10 requirement. Preserve the existing
asset collection, sorting, and empty-index guard behavior.
.github/workflows/binds-py.yml (1)

22-23: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reduce the duplicated, manually-synced python-version: '3.10' value.

The value is hard-coded three times, each annotated with a comment reminding maintainers to keep it in sync with .python-version. This is a manual-sync risk: an update to .python-version without updating all three sites silently reintroduces drift.

Since astral-sh/setup-uv does not expose a python-version-file input (only version-file, which pins the uv tool version, not the Python version), read .python-version once per job and pass it through a step output:

    - name: Read Python version
      id: pyver
      run: echo "version=$(cat .python-version)" >> "$GITHUB_OUTPUT"

    - name: Install uv
      uses: astral-sh/setup-uv@v5
      with:
        python-version: ${{ steps.pyver.outputs.version }}

Please confirm whether a newer astral-sh/setup-uv release has since added native .python-version file support before applying this change.

Also applies to: 59-60, 89-90

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/binds-py.yml around lines 22 - 23, Update each affected
job in the workflow to read .python-version once via a step identified as pyver,
expose the value through GITHUB_OUTPUT, and pass steps.pyver.outputs.version to
astral-sh/setup-uv instead of hard-coding Python 3.10. First verify whether the
current setup-uv release supports a native Python version file input; use that
supported input if available, otherwise apply the read-and-output approach
consistently to all three occurrences.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/scripts/build_simple_index.py:
- Around line 26-40: Update the jq expression in releases to exclude entries
where the release is marked draft before constructing the tag and assets object.
Preserve the existing pagination, asset digest fields, and literal subprocess
argument list.

In @.github/workflows/binds-py.yml:
- Around line 16-17: Disable persisted checkout credentials on every binding
workflow checkout step: add persist-credentials: false to the lint checkout in
.github/workflows/binds-py.yml (lines 16-17), and to the existing fetch-depth
blocks in its build checkout (lines 51-54) and sdist checkout (lines 81-84);
also add it to the checkout steps in .github/workflows/binds-go.yml (lines
21-22), .github/workflows/binds-js.yml (lines 20-21), and
.github/workflows/binds-rs.yml (lines 21-22).
- Around line 136-143: Update the release-upload step’s `run` block to pass
`github.ref_name` through the step environment, then use a quoted shell variable
for the `gh release upload` release argument instead of interpolating the GitHub
expression directly. Preserve the existing wheel and sdist upload behavior.

In @.github/workflows/build-docs.yml:
- Around line 25-32: Update the checkout step to set persist-credentials to
false, then add an actions/setup-python step before Generate index with an
explicit Python version of 3.10 or newer, and keep the existing script
invocation unchanged.

In @.python-version:
- Line 1: Align the Python 3.10 version contract by updating the CI
configuration’s python-version entry to the pinned 3.10.19 value used by
.python-version, or consistently revise the workflow comments and package
metadata to document that patch-level versions may vary.

In `@pyproject.toml`:
- Line 76: In the Ruff lint configuration in pyproject.toml, replace the
deprecated “TCH” selector with “TC” while preserving the existing type-checking
rule configuration.

In `@README.md`:
- Line 87: Update the license code fence in README.md to specify the text
language, or remove the fence while preserving the copyright block content.
- Around line 85-90: Update the package distribution metadata around
pyproject.toml and MANIFEST.in to include a NOTICE or third-party license file
containing the vendored MIT, Apache-2.0, and LGPL-2.1 dependency notices,
alongside the existing root LICENSE. Ensure the file is included in both source
distributions and wheels via the project’s established license-file
configuration.
- Around line 54-55: Update the README dependency references for pytest and ruff
to consistently use the declared development extra name `.[dev]`, correcting any
`[.den]` spelling in the surrounding prose or install command.
- Around line 29-46: Update the README “Build library” instructions to be
cross-platform: replace generator-sensitive parallel build syntax with `cmake
--build . --parallel 4`, provide Windows-compatible executable paths for
`runtest` and `runbench`, and include Windows command or activation equivalents,
or clearly label any remaining Unix-only commands.

In `@setup.py`:
- Around line 104-121: Add a CMake directory-creation step using
file(MAKE_DIRECTORY ...) for the repository build directory before the existing
file(APPEND ...) calls that write include_paths.txt and gmp_libraries.txt. Keep
the current append behavior unchanged and ensure the default in-source
configuration creates the directory before writing.
- Around line 90-102: Update the Windows branch around the generator selection
so non-Visual-Studio generators receive the existing cfg value through
CMAKE_BUILD_TYPE. Keep -A and /m arguments restricted to the Visual Studio
generator path, while preserving the current Windows architecture handling and
multi-config behavior.

---

Nitpick comments:
In @.github/scripts/build_simple_index.py:
- Around line 55-98: Update the distribution anchor generation in main to emit a
data-requires-python attribute for every wheel and sdist, using the release
asset metadata when available or a constant matching pyproject.toml’s >=3.10
requirement. Preserve the existing asset collection, sorting, and empty-index
guard behavior.

In @.github/workflows/binds-py.yml:
- Around line 22-23: Update each affected job in the workflow to read
.python-version once via a step identified as pyver, expose the value through
GITHUB_OUTPUT, and pass steps.pyver.outputs.version to astral-sh/setup-uv
instead of hard-coding Python 3.10. First verify whether the current setup-uv
release supports a native Python version file input; use that supported input if
available, otherwise apply the read-and-output approach consistently to all
three occurrences.

In `@binds/python/CMakeLists.txt`:
- Around line 14-18: Remove the empty ${INCLUDE_DIRECTORIES} entry from the
include_directories block and configure the dashbls_py target with target-scoped
include directories instead, preserving the current source and ../../include
paths.

In `@setup.py`:
- Around line 1-2: Remove the obsolete “# coding: latin-1” declaration from
setup.py lines 1-2 and .github/scripts/build_simple_index.py lines 1-2, leaving
Python 3’s default UTF-8 source encoding in effect.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a143dbb1-bf47-4883-bc02-8f54ac4ead75

📥 Commits

Reviewing files that changed from the base of the PR and between a89fd49 and 36180e3.

📒 Files selected for processing (53)
  • .flake8
  • .github/scripts/build_simple_index.py
  • .github/workflows/binds-go.yml
  • .github/workflows/binds-js.yml
  • .github/workflows/binds-py.yml
  • .github/workflows/binds-rs.yml
  • .github/workflows/build-binds.yml
  • .github/workflows/build-docs.yml
  • .github/workflows/build-wheels.yml
  • .github/workflows/js-bindings.yml
  • .github/workflows/relic-nightly.yml
  • .gitignore
  • .python-version
  • .vscode/extensions.json
  • .vscode/settings.json
  • CMakeLists.txt
  • MANIFEST.in
  • README.md
  • binds/python/CMakeLists.txt
  • binds/python/conftest.py
  • binds/python/pythonbindings.cpp
  • binds/python/samples/aggregate_signatures.py
  • binds/python/samples/creating_keys_and_signatures.py
  • binds/python/samples/hd_keys.py
  • binds/python/samples/loading_from_bytes.py
  • binds/python/samples/proof_of_possession.py
  • binds/python/samples/serializing_to_bytes.py
  • binds/python/samples/tree_aggregates.py
  • binds/python/test_bench.py
  • binds/python/test_unit.py
  • depends/catch2/CMakeLists.txt
  • js-bindings/CMakeLists.txt
  • lgtm.yml
  • mypi.ini
  • pyproject.toml
  • python-bindings/CMakeLists.txt
  • python-bindings/README.md
  • python-bindings/benchmark.py
  • python-bindings/test.py
  • python-impl/README.md
  • python-impl/bls12381.py
  • python-impl/ec.py
  • python-impl/fields.py
  • python-impl/hash_to_field.py
  • python-impl/hd_keys.py
  • python-impl/hkdf.py
  • python-impl/impl-test.py
  • python-impl/op_swu_g2.py
  • python-impl/pairing.py
  • python-impl/private_key.py
  • python-impl/schemes.py
  • python-impl/util.py
  • setup.py
💤 Files with no reviewable changes (23)
  • .flake8
  • python-bindings/CMakeLists.txt
  • lgtm.yml
  • .github/workflows/js-bindings.yml
  • python-impl/README.md
  • python-bindings/README.md
  • .github/workflows/relic-nightly.yml
  • python-bindings/test.py
  • python-impl/schemes.py
  • .github/workflows/build-wheels.yml
  • mypi.ini
  • python-impl/hash_to_field.py
  • python-impl/private_key.py
  • python-bindings/benchmark.py
  • python-impl/pairing.py
  • python-impl/fields.py
  • python-impl/op_swu_g2.py
  • python-impl/hkdf.py
  • python-impl/hd_keys.py
  • python-impl/ec.py
  • python-impl/util.py
  • python-impl/impl-test.py
  • python-impl/bls12381.py

Comment thread .github/scripts/build_simple_index.py
Comment thread .github/workflows/binds-py.yml Outdated
Comment thread .github/workflows/binds-py.yml
Comment thread .github/workflows/build-docs.yml
Comment thread .python-version
Comment thread README.md Outdated
Comment thread README.md
Comment thread README.md Outdated
Comment thread setup.py Outdated
Comment thread setup.py

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

Preliminary review — Codex only

The Python packaging revival exposes three blocking issues that must be fixed before publishing: non-contiguous buffers permit out-of-bounds native reads, the wheel configuration combines a shared RELIC context with pervasive GIL release, and the standalone index cannot build its advertised sdist fallback. The new DST guard is correct for normal inputs but should inspect the Python byte length before making the potentially multi-gigabyte copy it is intended to reject.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — security-auditor (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 3 blocking | 🟡 1 suggestion(s)

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 `binds/python/pythonbindings.cpp`:
- [BLOCKING] binds/python/pythonbindings.cpp:65-75: Reject non-contiguous buffers before reading native memory
  Checking only the format, dimension, and logical element count does not establish that `info.ptr` addresses `info.size` contiguous bytes. A strided view such as `memoryview(bytearray(range(64)))[::2]` is parsed from the first 32 contiguous backing bytes instead of the bytes in the view. A reversed 32-byte view has stride -1 and points at the final backing byte, so the forward `std::copy` reads 31 bytes beyond the allocation. At this head, `PrivateKey.from_bytes(memoryview(bytearray(32))[::-1])` accepted and serialized adjacent heap contents, confirming a native-memory disclosure primitive. The same issue affects the G1, G2, and GT constructors and their `from_bytes`/`from_bytes_unchecked` methods. Require `itemsize == 1`, one dimension, and `strides[0] == 1` at every buffer entry point, or gather the logical bytes according to the supplied stride; add strided and reversed-buffer tests.
- [SUGGESTION] binds/python/pythonbindings.cpp:43-51: Check the DST length before copying its contents
  `CopyDst` constructs a `std::string` containing the entire Python bytes object before enforcing the 255-byte limit. A multi-gigabyte value of the kind this guard is specifically intended to reject therefore requires another multi-gigabyte allocation and may raise `MemoryError` instead of the documented `ValueError`. Read the Python object's length first, reject oversized values, and copy only accepted inputs.

In `setup.py`:
- [BLOCKING] setup.py:72-79: Do not release the GIL while RELIC uses a shared context
  Passing `-DMULTI=` overrides the root CMake defaults and produces a RELIC build with `MULTI` undefined, where `core_ctx` is a single process-wide static context. The binding nevertheless has 78 `py::gil_scoped_release` sites around parsing, signing, verification, and other RELIC operations, so ordinary CPython threads can concurrently access that shared mutable context. In particular, RELIC operations and `BLS::CheckRelicErrors()` race on `core_ctx->code`; an error from malformed input can be cleared or observed by an unrelated valid verification, making verification nondeterministic and potentially raising `ValueError: Relic library error`. Restore a per-thread RELIC configuration, retain the GIL around every RELIC operation, or serialize all RELIC access with one process-wide native mutex. Skipping free-threaded Python wheels does not prevent races after an explicit GIL release.

In `.github/scripts/build_simple_index.py`:
- [BLOCKING] .github/scripts/build_simple_index.py:63-70: Make source distributions installable through the standalone index
  The generated index deliberately includes `.tar.gz` assets as the fallback for platforms without a compatible wheel, but it contains distributions only for `dashbls`. When pip selects an sdist through this index, its isolated PEP 517 build environment uses the same index and cannot resolve the requirements declared in `pyproject.toml`: `cmake`, `pybind11`, `setuptools_scm`, and `setuptools`. Installation therefore fails before compilation begins, for example with no matching distribution for `cmake>=3.18`. Supply build dependencies through the installation design, document a direct-sdist flow that resolves dependencies from the normal package index, or stop listing the sdist as an installable fallback in this standalone index.

Comment thread setup.py
Comment thread .github/scripts/build_simple_index.py
Comment thread binds/python/pythonbindings.cpp Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
autogen.sh (1)

13-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep the compatibility handling in autoreconf.

Line 12 already invokes autoheader through autoreconf. On older Autoconf versions, Line 13 therefore reports an unsupported-option error and runs autoheader a second time. Newer Autoconf versions support --replace-handwritten on autoreconf and pass it to autoheader; Autoconf 2.72 does not document this option. (gnu.googlesource.com)

Feature-detect the option on autoreconf and invoke autoreconf once.

Proposed refactor
 autoreconf --install --force --warnings=all
-autoheader --force --replace-handwritten || autoheader --force
+if autoreconf --help 2>&1 | grep -q 'replace-handwritten'; then
+  autoreconf --install --force --replace-handwritten --warnings=all
+else
+  autoreconf --install --force --warnings=all
+fi

Verify the Autoconf versions used by CI:

#!/bin/sh
set -eu

sh -n autogen.sh
command -v autoreconf >/dev/null
command -v autoheader >/dev/null

autoreconf --version | sed -n '1p'
autoheader --version | sed -n '1p'

if autoreconf --help 2>&1 | grep -q 'replace-handwritten'; then
  echo "autoreconf supports --replace-handwritten"
else
  echo "autoreconf requires the fallback path"
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@autogen.sh` at line 13, Update the autogen.sh autoreconf/autoheader flow to
feature-detect whether autoreconf supports --replace-handwritten, then invoke
autoreconf exactly once with that option when available and without it
otherwise. Remove the separate autoheader fallback invocation while preserving
compatibility with older Autoconf versions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@setup.py`:
- Around line 106-108: Update the non-Windows build argument construction in
setup.py to use CMake’s generator-independent “--parallel” option with the
existing CPU count, instead of passing “-- -j” directly to the selected
generator. Keep the existing CMAKE_BUILD_TYPE configuration and Windows-specific
behavior unchanged.

---

Nitpick comments:
In `@autogen.sh`:
- Line 13: Update the autogen.sh autoreconf/autoheader flow to feature-detect
whether autoreconf supports --replace-handwritten, then invoke autoreconf
exactly once with that option when available and without it otherwise. Remove
the separate autoheader fallback invocation while preserving compatibility with
older Autoconf versions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b00b5741-f735-41aa-83b4-afdfb889d878

📥 Commits

Reviewing files that changed from the base of the PR and between 36180e3 and 5e6ac4a.

📒 Files selected for processing (55)
  • .flake8
  • .github/scripts/build_simple_index.py
  • .github/workflows/binds-go.yml
  • .github/workflows/binds-js.yml
  • .github/workflows/binds-py.yml
  • .github/workflows/binds-rs.yml
  • .github/workflows/build-binds.yml
  • .github/workflows/build-docs.yml
  • .github/workflows/build-wheels.yml
  • .github/workflows/js-bindings.yml
  • .github/workflows/relic-nightly.yml
  • .gitignore
  • .python-version
  • .vscode/extensions.json
  • .vscode/settings.json
  • CMakeLists.txt
  • MANIFEST.in
  • NOTICE
  • README.md
  • autogen.sh
  • binds/python/CMakeLists.txt
  • binds/python/conftest.py
  • binds/python/pythonbindings.cpp
  • binds/python/samples/aggregate_signatures.py
  • binds/python/samples/creating_keys_and_signatures.py
  • binds/python/samples/hd_keys.py
  • binds/python/samples/loading_from_bytes.py
  • binds/python/samples/proof_of_possession.py
  • binds/python/samples/serializing_to_bytes.py
  • binds/python/samples/tree_aggregates.py
  • binds/python/test_bench.py
  • binds/python/test_unit.py
  • depends/catch2/CMakeLists.txt
  • js-bindings/CMakeLists.txt
  • lgtm.yml
  • mypi.ini
  • pyproject.toml
  • python-bindings/CMakeLists.txt
  • python-bindings/README.md
  • python-bindings/benchmark.py
  • python-bindings/test.py
  • python-impl/README.md
  • python-impl/bls12381.py
  • python-impl/ec.py
  • python-impl/fields.py
  • python-impl/hash_to_field.py
  • python-impl/hd_keys.py
  • python-impl/hkdf.py
  • python-impl/impl-test.py
  • python-impl/op_swu_g2.py
  • python-impl/pairing.py
  • python-impl/private_key.py
  • python-impl/schemes.py
  • python-impl/util.py
  • setup.py
💤 Files with no reviewable changes (23)
  • python-impl/pairing.py
  • python-bindings/CMakeLists.txt
  • .flake8
  • python-bindings/README.md
  • python-bindings/benchmark.py
  • .github/workflows/build-wheels.yml
  • python-impl/README.md
  • lgtm.yml
  • python-impl/ec.py
  • python-impl/util.py
  • python-impl/private_key.py
  • .github/workflows/relic-nightly.yml
  • python-impl/impl-test.py
  • python-impl/hash_to_field.py
  • python-impl/hd_keys.py
  • mypi.ini
  • python-impl/op_swu_g2.py
  • python-impl/bls12381.py
  • python-bindings/test.py
  • python-impl/schemes.py
  • .github/workflows/js-bindings.yml
  • python-impl/fields.py
  • python-impl/hkdf.py
🚧 Files skipped from review as they are similar to previous changes (25)
  • .vscode/extensions.json
  • .gitignore
  • CMakeLists.txt
  • .python-version
  • binds/python/samples/creating_keys_and_signatures.py
  • .github/workflows/binds-js.yml
  • binds/python/samples/proof_of_possession.py
  • binds/python/samples/aggregate_signatures.py
  • depends/catch2/CMakeLists.txt
  • binds/python/samples/hd_keys.py
  • binds/python/conftest.py
  • .github/workflows/build-binds.yml
  • .github/workflows/build-docs.yml
  • js-bindings/CMakeLists.txt
  • binds/python/CMakeLists.txt
  • binds/python/samples/serializing_to_bytes.py
  • MANIFEST.in
  • binds/python/test_unit.py
  • binds/python/samples/tree_aggregates.py
  • .github/workflows/binds-go.yml
  • binds/python/samples/loading_from_bytes.py
  • .vscode/settings.json
  • binds/python/pythonbindings.cpp
  • pyproject.toml
  • .github/workflows/binds-rs.yml

Comment thread setup.py Outdated
@UdjinM6

UdjinM6 commented Aug 3, 2026

Copy link
Copy Markdown

pls see 551d801 for some findings by Claude

@thepastaclaw

Copy link
Copy Markdown

Thanks — I reviewed 551d80134e3bb48394db63b6ac49cc602b72defa against the current PR head (5e6ac4ae).

The removal of the 78 gil_scoped_release guards addresses the shared-RELIC-context blocker, and checking DST/message lengths before copying is sound.

Two blocking issues from my review are still open in that commit:

  1. The py::buffer constructors and from_bytes/from_bytes_unchecked paths still accept strided or reversed one-dimensional uint8 buffers and then copy forward from info.ptr. They need to require itemsize == 1 and strides[0] == 1 (or gather according to the stride), with strided/reversed-buffer tests.
  2. The standalone package index still advertises the sdist while containing only dashbls. When pip uses it as the index, the isolated PEP 517 environment cannot resolve cmake, pybind11, setuptools_scm, and setuptools. The install/index design still needs to address that or stop listing the sdist as an installable fallback.

One proposed change should not be carried over: removing the autoheader --force --replace-handwritten handling reverts 0705266. Autoconf 2.73 intentionally preserves a handwritten-looking config.h.in unless --replace-handwritten (-R) is requested, so dropping that behavior can restore the Autotools failure the commit fixed. The invocation can be cleaned up/feature-detected, but the 2.73 behavior must remain covered.

The PR head itself has not changed yet; the exact-head automated re-review is still queued.

@thepastaclaw

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@thepastaclaw

Copy link
Copy Markdown

Latest tip is now 0da820d3. The earlier setup-uv failure is fixed: Python lint, sdist, Linux/macOS wheels, and the completed native jobs are green; the Windows wheel and CodeRabbit are still running. The exact-head automated review is queued. I’ll revise the stale review and its existing findings from that validated result rather than clearing them prematurely.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
binds/python/pythonbindings.cpp (1)

212-242: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Apply the message length bound before all BLS message hash operations.

Messages at or beyond 2 GiB are rejected in g2_from_message by CopyMsg, but sign, verify, aggregate_verify, and fast_aggregate_verify still convert msg without that check. If the input is larger than INT_MAX, passing it through Sign/Verify/AggregateVerify/FastAggregateVerify can still reach relic hash-to-curve functions, because CoreMPL::Sign and CoreMPL::Verify cast the message size to int before G2Element::FromMessage. Use CopyMsg for these Python binding message conversions before constructing vector<uint8_t>.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@binds/python/pythonbindings.cpp` around lines 212 - 242, Update the Python
binding lambdas for sign, verify, aggregate_verify, and fast_aggregate_verify to
convert each message through CopyMsg before constructing vector<uint8_t>. Ensure
the existing message length bound is applied before calling BasicSchemeMPL Sign,
Verify, AggregateVerify, or FastAggregateVerify, while preserving their current
inputs and return behavior.
🧹 Nitpick comments (2)
binds/python/pythonbindings.cpp (1)

47-61: 🧹 Nitpick | 🔵 Trivial

Note: a single process-wide mutex serializes all RELIC operations.

RelicGuard correctly fixes the shared-context race, but it also means every guarded call (signing, verification, aggregation, element construction) is now fully serialized across all Python threads, since MULTI is unset in the RELIC build. This is a deliberate, documented trade-off given the single process-wide RELIC context, and matches the PR's stated scope of prioritizing correctness over feature/performance completeness. Worth keeping in mind if multi-threaded verification throughput becomes a concern later; a per-thread RELIC context would be the eventual path to remove this bottleneck.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@binds/python/pythonbindings.cpp` around lines 47 - 61, No code change is
required: retain the process-wide RelicMutex and RelicGuard serialization for
correctness with the single shared RELIC context. Treat per-thread contexts as
future optimization scope, not part of this change.
.github/workflows/binds-js.yml (1)

90-94: 🔒 Security & Privacy | 🔵 Trivial | 🏗️ Heavy lift

Consider npm trusted publishing (OIDC) instead of NPM_TOKEN.

zizmor flags this npm publish step for trusted publishing. npm's OIDC trusted publishing is generally available and removes the need to store, rotate, or risk leaking a long-lived NPM_TOKEN secret.

Adopting it requires: permissions: id-token: write on this job, npm CLI ≥ 11.5.1 (via npm install -g npm@latest or a Node version bundling it), and configuring a trusted publisher for this package on npmjs.com pointing at this workflow file.

♻️ Proposed direction (requires npmjs.com-side trusted publisher setup first)
     - name: Set up Node
       uses: actions/setup-node@v6
       with:
         node-version: '20'
         registry-url: https://registry.npmjs.org
+
+    - name: Update npm for trusted publishing
+      run: npm install -g npm@latest
   publish:
     name: Publish (releases), Javascript
     if: startsWith(github.ref, 'refs/tags/')
     needs: build
     runs-on: ubuntu-latest
+    permissions:
+      id-token: write
     - name: Publish to npm
       working-directory: js_build/js-bindings
-      env:
-        NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
       run: npm publish --access public
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/binds-js.yml around lines 90 - 94, Update the Publish to
npm job to use npm OIDC trusted publishing instead of secrets.NPM_TOKEN: grant
the job id-token: write permission, install or select npm CLI version 11.5.1 or
newer before publishing, and remove NODE_AUTH_TOKEN from the step. Preserve the
existing npm publish command and configure the package’s trusted publisher to
reference this workflow.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 61-64: Update the Python installation documentation in README.md
to target an actually published dashbls distribution: either publish the
configured PEP 503 index with a resolvable dashbls page and required sdist, or
change the documented install command and index URL to match the distribution
currently available. Keep the guidance using --extra-index-url so PyPI remains
available for build dependencies.

---

Outside diff comments:
In `@binds/python/pythonbindings.cpp`:
- Around line 212-242: Update the Python binding lambdas for sign, verify,
aggregate_verify, and fast_aggregate_verify to convert each message through
CopyMsg before constructing vector<uint8_t>. Ensure the existing message length
bound is applied before calling BasicSchemeMPL Sign, Verify, AggregateVerify, or
FastAggregateVerify, while preserving their current inputs and return behavior.

---

Nitpick comments:
In @.github/workflows/binds-js.yml:
- Around line 90-94: Update the Publish to npm job to use npm OIDC trusted
publishing instead of secrets.NPM_TOKEN: grant the job id-token: write
permission, install or select npm CLI version 11.5.1 or newer before publishing,
and remove NODE_AUTH_TOKEN from the step. Preserve the existing npm publish
command and configure the package’s trusted publisher to reference this
workflow.

In `@binds/python/pythonbindings.cpp`:
- Around line 47-61: No code change is required: retain the process-wide
RelicMutex and RelicGuard serialization for correctness with the single shared
RELIC context. Treat per-thread contexts as future optimization scope, not part
of this change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fcfab7cc-9fc5-4f5c-ab48-30a8e9a09bad

📥 Commits

Reviewing files that changed from the base of the PR and between ebbab75 and 0da820d.

📒 Files selected for processing (13)
  • .github/scripts/build_simple_index.py
  • .github/workflows/binds-go.yml
  • .github/workflows/binds-js.yml
  • .github/workflows/binds-py.yml
  • .github/workflows/binds-rs.yml
  • .github/workflows/build-binds.yml
  • .github/workflows/build-docs.yml
  • .gitignore
  • README.md
  • binds/python/pythonbindings.cpp
  • binds/python/test_unit.py
  • pyproject.toml
  • setup.py
🚧 Files skipped from review as they are similar to previous changes (7)
  • .github/workflows/binds-rs.yml
  • .github/workflows/build-docs.yml
  • .github/workflows/binds-py.yml
  • .github/workflows/binds-go.yml
  • .gitignore
  • pyproject.toml
  • binds/python/test_unit.py

Comment thread README.md
@thepastaclaw

Copy link
Copy Markdown

Reconciled the review against current tip 0da820d3:

  • The prior non-contiguous-buffer blocker is addressed by requesting PyBUF_C_CONTIGUOUS before copying.
  • The shared RELIC context/GIL blocker is addressed by RelicGuard serializing RELIC entry points with a process-wide mutex.
  • The sdist/index concern is addressed by documenting --extra-index-url, so isolated build dependencies still resolve from PyPI.
  • The DST-copy suggestion is addressed by checking py::len in CopyChecked before constructing the string.

I replied on each existing PastaClaw thread that had a GitHub comment; GitHub does not grant my account permission to resolve those threads. All current CI checks are green.

One blocking issue remains at this tip: CopyMsg is used by the direct g2_from_message/element from_message paths, but the sign, verify, aggregate_verify, and fast_aggregate_verify bindings still copy messages directly before the native code narrows their lengths to int. This affects the Basic, Aug, and Pop scheme bindings. CodeRabbit has already raised it in its exact-tip review, so I am not duplicating an inline finding.

The exact-head PastaClaw automated review is still queued. I’ll update the formal preliminary review disposition from that validated result rather than approving while this blocker remains.

@thepastaclaw

Copy link
Copy Markdown

The exact-head automated review has now completed for 0da820d3, so the revised disposition is changes requested with two validated blockers:

  1. Validate every byte length before RELIC narrows it to int. The remaining scope is broader than the earlier CodeRabbit comment: Util.hash256, each scheme's key_gen, and the Basic/Aug/Pop sign, verify, aggregate_verify, and fast_aggregate_verify paths still accept unrestricted Python byte lengths before reaching native int parameters. The fix needs to account for key-generation/HMAC arithmetic and the augmented scheme's 48-byte public-key prefix.
  2. Avoid dependency confusion in the documented install command. pip --extra-index-url merges candidates from PyPI and the Dash index rather than prioritizing the Dash index. The dashbls project name currently returns 404 on PyPI, so another party could claim it and publish a higher version. Please reserve/control the PyPI name or redesign the install flow so dashbls itself comes only from a Dash-controlled source while build requirements are obtained separately.

The remaining non-blocking documentation suggestion is to add PowerShell/Command Prompt activation commands (or label the current activation block POSIX-only).

The earlier non-contiguous-buffer, shared RELIC context, standalone-index build-dependency, DST-copy, and CMake parallelism findings are confirmed fixed at this tip. Existing PastaClaw threads were already updated where GitHub allowed replies; this account still cannot resolve them. All CI checks are green.

@kwvg
kwvg requested review from UdjinM6 and removed request for UdjinM6 August 3, 2026 15:12
@kwvg

kwvg commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

@thephez

@thephez thephez 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.

Readme looks okay to me 👍

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

Preliminary review — Codex only

The revived Python bindings and publishing workflows are substantially improved, but two security blockers remain at exact head: several Python byte inputs still reach RELIC through unchecked size narrowing, and the documented merged-index installation exposes users to dependency confusion while dashbls remains unreserved on PyPI. The Python development instructions also remain POSIX-only despite the documented Windows support.
Source: reviewer backends — gpt-5.6-sol (Codex general) and gpt-5.6-sol (Codex security-auditor); final verifier backend — gpt-5.6-sol. openclaw-agent/cliproxy/gpt-5.6-sol is orchestration-only and not reviewer evidence.

Validated blockers were found in the Codex precheck. Opus is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — security-auditor (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 2 blocking | 🟡 1 suggestion(s)

🤖 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 `binds/python/pythonbindings.cpp`:
- [BLOCKING] binds/python/pythonbindings.cpp:171-177: Validate every byte length before RELIC narrows it to int
  `CopyMsg` protects only the direct `g2_from_message` and element `from_message` APIs. `Util.hash256` still passes `str.size()` through `Util::Hash256` to RELIC's signed `int` parameter, all three `key_gen` wrappers pass unrestricted seeds through HKDF to `md_hmac`, and the Basic/Aug/Pop `sign`, `verify`, `aggregate_verify`, and `fast_aggregate_verify` wrappers copy unrestricted messages before native hashing. Values above `INT_MAX` therefore undergo implementation-defined narrowing and can be hashed incompletely or interpreted as negative lengths. The key-generation path is especially unsafe because `md_hmac` computes `block_size + in_len`, allocates from that signed result, and then passes `in_len` to `memcpy`; augmented operations also prepend 48 bytes before the final narrowing. Check the Python length before the first copy and use limits appropriate to each path: at most `INT_MAX` for direct hashes, `INT_MAX - 48` for augmented messages, and a bound accounting for the appended key-generation byte and HMAC block arithmetic.

In `README.md`:
- [BLOCKING] README.md:57-64: Avoid dependency confusion when combining the private index with PyPI
  `--extra-index-url` does not prioritize the Dash index; pip merges candidates from PyPI and the additional index and selects the best compatible version. The `dashbls` project currently returns 404 from PyPI, so another party can register it and publish a higher compatible version that this documented command will download and execute. Hash fragments attached to Dash-hosted links do not constrain a different candidate selected from PyPI. Reserve and securely control the PyPI project name, use a direct hashed Dash-hosted artifact URL, or redesign installation so the `dashbls` candidate comes exclusively from a Dash-controlled source while build requirements are resolved separately.
- [SUGGESTION] README.md:79-84: Document Windows Python environment activation
  The development block still provides only `source dashbls/bin/activate`, which does not work in PowerShell or Command Prompt even though this PR presents the bindings as cross-platform and publishes Windows wheels. Add the `dashbls\Scripts\Activate.ps1` and `dashbls\Scripts\activate.bat` equivalents, or explicitly label the entire development block as POSIX-shell-only.

Comment thread binds/python/pythonbindings.cpp Outdated
Comment thread README.md
Comment on lines +57 to +64
```sh
pip install --extra-index-url https://dashpay.github.io/bls-signatures/pep503/ dashbls
```

## Very fast verification with Proof of Possession scheme
> [!IMPORTANT]
> Use `--extra-index-url`, not `--index-url`. Platforms we do not ship a wheel for fall back to the sdist, and building
> it needs `cmake`, `pybind11`, `setuptools_scm` and `setuptools` from PyPI. `--index-url` would replace PyPI with an
> index that carries only `dashbls`, so the build would fail before it started.

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: Avoid dependency confusion when combining the private index with PyPI

--extra-index-url does not prioritize the Dash index; pip merges candidates from PyPI and the additional index and selects the best compatible version. The dashbls project currently returns 404 from PyPI, so another party can register it and publish a higher compatible version that this documented command will download and execute. Hash fragments attached to Dash-hosted links do not constrain a different candidate selected from PyPI. Reserve and securely control the PyPI project name, use a direct hashed Dash-hosted artifact URL, or redesign installation so the dashbls candidate comes exclusively from a Dash-controlled source while build requirements are resolved separately.

source: ['codex']

Comment thread README.md

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

Preliminary review — Codex only

The prior RELIC integer-narrowing paths are now guarded, but key generation still accepts seeds large enough to exhaust the native stack inside RELIC, and the documented merged-index installation remains vulnerable to dependency confusion while dashbls is unreserved on PyPI. The release pipeline should also pin third-party wheel-building actions to immutable commits before publishing cryptographic binaries.
Source: reviewer backends gpt-5.6-sol (Codex general) and gpt-5.6-sol (Codex security-auditor); final verifier backend gpt-5.6-sol. openclaw-agent/cliproxy/gpt-5.6-sol is orchestration-only and not reviewer evidence.

Validated blockers were found in the Codex precheck. Opus is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — security-auditor (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 2 blocking | 🟡 1 suggestion(s)

1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

🤖 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 `binds/python/pythonbindings.cpp`:
- [BLOCKING] binds/python/pythonbindings.cpp:108-112: Prevent large key-generation seeds from exhausting the native stack
  `CopySeed` permits seeds up to approximately 2 GiB, but the wheel uses RELIC's default `ALLOC=AUTO`. In that configuration, `RLC_ALLOCA` expands to `alloca`, and `md_hmac` allocates `block_size + in_len` bytes on the native stack. Each scheme's `key_gen` appends one byte and passes the resulting seed through this path, so a seed far below the documented limit terminates the interpreter rather than raising a Python exception. This was reproduced against the exact-head local extension: `BasicSchemeMPL.key_gen(b"x" * (16 << 20))` exited with status 139. Impose a conservative seed-size limit before copying, build RELIC with dynamic allocation for this path, or change HMAC to process accepted inputs without an input-sized stack allocation.

In `.github/workflows/binds-py.yml`:
- [SUGGESTION] .github/workflows/binds-py.yml:59-65: Pin third-party wheel-build actions to immutable commits
  The release build executes `astral-sh/setup-uv@v9.0.0` and `pypa/cibuildwheel@v4.1.1` through mutable Git tags, and the resulting wheels are published without an independent source-to-binary verification step. If either upstream action repository is compromised or one of those tags is moved, the action can modify the source or generated cryptographic extension before publication. Pin these third-party build actions to reviewed full commit SHAs and update the pins through reviewed dependency changes.

In `README.md`:
- [BLOCKING] README.md:57-64: Avoid dependency confusion when combining the private index with PyPI
  (existing thread: https://github.com/dashpay/bls-signatures/pull/125#discussion_r3753583021)
  `--extra-index-url` does not prioritize the Dash index. Pip merges candidates from PyPI and the additional index, then selects the best compatible version. The `dashbls` project still returns HTTP 404 from PyPI at this exact head, so another party can register the name and publish a higher compatible version that users following this command will download and execute. Hash fragments on Dash-hosted links do not constrain a different candidate selected from PyPI. Reserve and securely control the PyPI project name, use a direct hashed Dash-hosted artifact URL, or redesign installation so the `dashbls` candidate comes exclusively from a Dash-controlled source while build requirements are resolved separately.

Comment thread binds/python/pythonbindings.cpp Outdated
Comment on lines +59 to +65
- name: Install uv
uses: astral-sh/setup-uv@v9.0.0
with:
enable-cache: false

- name: Build and test wheels
uses: pypa/cibuildwheel@v4.1.1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Pin third-party wheel-build actions to immutable commits

The release build executes astral-sh/setup-uv@v9.0.0 and pypa/cibuildwheel@v4.1.1 through mutable Git tags, and the resulting wheels are published without an independent source-to-binary verification step. If either upstream action repository is compromised or one of those tags is moved, the action can modify the source or generated cryptographic extension before publication. Pin these third-party build actions to reviewed full commit SHAs and update the pins through reviewed dependency changes.

source: ['codex']

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

Preliminary review — Codex only

The 64 KiB seed cap fixes the prior native stack-exhaustion blocker, and the corresponding boundary tests cover both rejection and the accepted maximum. Two release-security issues remain: the documented merged-index installation permits dependency confusion while dashbls is unclaimed on PyPI, and the wheel workflow executes mutable third-party action tags before publishing the cryptographic extension.
Source: reviewers gpt-5.6-sol (Codex general) and gpt-5.6-sol (Codex security-auditor); final verifier gpt-5.6-sol. openclaw-agent/cliproxy/gpt-5.6-sol is orchestration-only and not reviewer evidence.

Validated blockers were found in the Codex precheck. Opus is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — security-auditor (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking

2 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

🤖 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 `README.md`:
- [BLOCKING] README.md:57-64: Avoid dependency confusion when combining the private index with PyPI
  (existing thread: https://github.com/dashpay/bls-signatures/pull/125#discussion_r3753583021)
  `--extra-index-url` does not prioritize the Dash-controlled index. Pip merges candidates from PyPI and every additional index, then selects the best compatible version. The `dashbls` project returns HTTP 404 from PyPI at this exact head, so another party can claim the name and publish a higher compatible version that users following this command will download and execute. Hash fragments on Dash-hosted links only verify those specific links; they do not constrain a different candidate selected from PyPI. Reserve and securely control the PyPI project name, use a direct hashed Dash-hosted artifact requirement, or redesign installation so the `dashbls` candidate comes exclusively from a Dash-controlled source while build requirements are resolved separately.

In `.github/workflows/binds-py.yml`:
- [SUGGESTION] .github/workflows/binds-py.yml:59-65: Pin third-party wheel-build actions to immutable commits
  (existing thread: https://github.com/dashpay/bls-signatures/pull/125#discussion_r3758700847)
  The release build executes `astral-sh/setup-uv@v9.0.0` and `pypa/cibuildwheel@v4.1.1` through mutable Git tags. If either upstream repository is compromised or a tag is moved, the substituted action can alter the source or generated native extension before the publish job distributes it. Because these wheels expose consensus-critical cryptographic operations and there is no independent source-to-binary verification step, pin both third-party actions to reviewed full commit SHAs and update those pins through reviewed dependency changes.

@PastaPastaPasta
PastaPastaPasta merged commit f7c90b9 into dashpay:develop Aug 11, 2026
31 checks passed

@UdjinM6 UdjinM6 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.

post-merge utACK

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.

5 participants