Repository navigation
pkc%fix(bls): read legacy BLS keys and signatures as the reference implementation does - #101
Conversation
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 8 minutes. View limit details
No actionable comments were generated in the recent review. Summary
Merge Risk:
|
|
✅ Final review complete — no blockers (commit 1ebd2c2) · triage: critical |
|
Note This pull request has no conflicts! 🎊 🎉 🎊 |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! 🚀 New features to boost your workflow:
|
thepastaclaw
left a comment
There was a problem hiding this comment.
Final validation — Phase 1 + Phase 2
The legacy read rules match the inspected Core/relic and blst behavior; no blocking correctness defects were confirmed. Two non-blocking improvements remain: explicitly testing typed-decoder rejection of off-curve inputs and avoiding repeated decompression in canonicality checks. Validation was static only; current CI shows stable platform checks passing, with lint, Linux cross-build, and several MSRV build/test jobs still pending.
🟡 2 suggestion(s)
Review provenance
Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 4: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 5: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
criticalbygpt-6.1-sol(effort low) — The intricate changes in scheme_chia.rs canonicality predicates and blst_ffi.rs::uncompress_on_curve alter cryptographic key and signature acceptance rules, including off-curve encodings and special handling of a decompression error. - Phase 1 reviewers:
muse-spark-1.3-contributor— general (completed, effort xhigh); agentphase1-reviewer,muse-spark-1.3-contributor— rust-quality (completed, effort xhigh); agentphase1-reviewer - Phase 1 model:
muse-spark-1.3-contributor— not quota-gated; passed overgemini-3.8-flash-high(antigravity quota lookup failed),glm-5.3-flash(not used above high effort; tier asks max) - Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
- Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer
🤖 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 `pkgs/pkc/src/bls/sig_basic.rs`:
- [SUGGESTION] pkgs/pkc/src/bls/sig_basic.rs:277-282: Assert the off-curve typed-decoder boundary independently
These assertions allow either successful decoding with identical reserialization or failure classified by chia_sig_off_curve. They therefore do not require off-curve inputs to fail typed decoding, despite that being an explicit boundary of this change. The failure classifier also repeats the production fallback's byte transformation and blst error check, so a shared classification mistake can excuse an unexpected decoding failure. Record an independent on-curve/decodability expectation for the relevant corpus inputs, then require errors for legacy off-curve encodings and successful round-trips for the other reference-valid inputs. Apply the same assertion to assert_pk_reads in public_ops.rs. Do not use only class.starts_with("off_"): the corpus also contains off-curve boundary inputs such as G1 x_max_000 and x_max_100.
In `pkgs/pkc/src/bls/scheme_chia.rs`:
- [SUGGESTION] pkgs/pkc/src/bls/scheme_chia.rs:139-150: Reuse the decompression result in canonicality checks
For an eligible off-curve encoding, pk_from_bytes performs blst decompression and maps BLST_POINT_NOT_ON_CURVE to InvalidPublicKey; this fallback then decompresses the same bytes again to recover the discarded error. sig_is_canonical repeats the same pattern for G2. The inspected blst implementation performs the field square-root computation before returning this error, so these inputs incur that work twice, including off-curve inputs intentionally accepted by the new canonicality predicates. Preserve the internal decompression result or error classification so canonicality can reuse it, while typed decoding continues to reject off-curve values.
Out-of-scope follow-up suggestions (1)
These are valid observations, but they are outside this PR's scope and should be handled in separate issues or author/maintainer-requested PRs rather than blocking this review.
- Separate legacy wire compatibility from DH/IES peer validation — The base revision already accepts non-prime-order legacy public keys, and its off_subgroup_peer_policy test explicitly preserves their use in DH. BlsScheme::dh_exchange multiplies the peer point by the secret scalar without subgroup validation, and ies_open derives its encryption key from that result. Small-order peer points can confine the shared secret to an enumerable set. This is a concrete pre-existing operation-level security concern; the legacy reader's compatibility policy and the absence of DH subgroup validation predate this PR.
- Follow-up: Track hardened DH/IES entry points that reject identity and non-prime-order peers separately from the consensus-compatible legacy reader, and document the existing peer-validation requirements.
thepastaclaw
left a comment
There was a problem hiding this comment.
Re-review — Final validation — Phase 1 + Phase 2
Reviewed the complete diff at 975df95 and found no actionable in-scope defects: the legacy acceptance rules match the inspected reference sources, while typed decoding still rejects off-curve encodings. The independent curve annotations and strict decoder assertions fix the prior coverage finding; keeping decoding and canonicality separate is a reasonable trade-off despite bounded repeated decompression. This was static-only validation: no builds or tests were run, and current-head MSRV checks, lint, and macOS/Windows stable builds remain pending; the Ubuntu ARM stable build passed.
🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)
Review provenance
Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 3: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 5: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
criticalbygpt-6.1-sol(effort low) — The intricate changes in pkgs/pkc/src/bls/scheme_chia.rs and blst_ffi.rs alter legacy BLS public-key decoding and key/signature canonicality rules, directly changing cryptographic input acceptance. - Phase 1 reviewers:
muse-spark-1.3-contributor— general (completed, effort xhigh); agentphase1-reviewer,muse-spark-1.3-contributor— rust-quality (completed, effort xhigh); agentphase1-reviewer - Phase 1 model:
muse-spark-1.3-contributor— not quota-gated; passed overgemini-3.8-flash-high(antigravity quota lookup failed),glm-5.3-flash(not used above high effort; tier asks max) - Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
- Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
- Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.
No unresolved findings remain from the prior review on this head.
Out-of-scope follow-up suggestions (1)
These are valid observations, but they are outside this PR's scope and should be handled in separate issues or author/maintainer-requested PRs rather than blocking this review.
- Separate legacy parsing compatibility from DH/IES subgroup safety — BlsScheme::dh_exchange in pkgs/pkc/src/bls/scheme_ops.rs multiplies an admitted legacy peer key by the secret scalar without requiring prime-order subgroup membership. The base already contains this behavior and explicitly documents it in assert_off_subgroup_peer_policy. Applications exposing DH-dependent responses to adversarial peers can therefore reveal information about the scalar through small-subgroup components. This is a concrete, pre-existing key-agreement admission issue, separate from matching the reference's wire canonicality rules.
- Follow-up: Track subgroup-validated peer admission for DH/IES, or a hardened key-agreement API, separately while preserving consensus-compatible legacy parsing.
kwvg
left a comment
There was a problem hiding this comment.
Also reorder the commits so that you first include the reference method (C++ or Python, your pick) that can regenerate the existing pkc corpora to establish baseline credibility before bundling your changes to include the tests to validate it so that just comb can prove each incremental change stands on its own
975df95 to
91b3644
Compare
|
Reordered. The first commit, 🤖 Posted autonomously by Claude on behalf of pasta. |
91b3644 to
34b142d
Compare
thepastaclaw
left a comment
There was a problem hiding this comment.
Re-review — Final validation — Phase 1 + Phase 2
Independently reviewed the complete diff at 34b142d and found no actionable in-scope defects. The legacy acceptance rules match the pinned Dash Core/relic readers and blst 0.3.17 behavior; typed decoding still rejects off-curve inputs, with independent corpus expectations enforcing that boundary. Validation was static only: current CI shows no failures and lint passing, while one MSRV build/test job, macOS testing, and three cross-target checks remain pending.
🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)
Review provenance
Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 3: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 5: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
criticalbygpt-6.1-sol(effort low) — The coordinated changes to legacy BLS decoding and canonicality in scheme_chia.rs, public_ops.rs and sig_basic.rs introduce intricate cryptographic input-acceptance rules, including off-curve encodings and exceptional point handling. - Phase 1 reviewers:
muse-spark-1.3-contributor— general (completed, effort xhigh); agentphase1-reviewer,muse-spark-1.3-contributor— rust-quality (completed, effort xhigh); agentphase1-reviewer - Phase 1 model:
muse-spark-1.3-contributor— not quota-gated; passed overgemini-3.8-flash-high(antigravity quota lookup failed),glm-5.3-flash(not used above high effort; tier asks max) - Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
- Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
- Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.
No unresolved findings remain from the prior review on this head.
kwvg
left a comment
There was a problem hiding this comment.
Suggestion, split this PR in two, the first PR generates the existing corpora, I'll contribute additional commits to ensure linting and static analysis for C++ are setup, the second commit focuses on dash-pkc modifications and corpora to support those changes.
|
Thanks, we'll take all of it:
I'll link the new PR here when it's up. 🤖 Posted autonomously by Claude on behalf of pasta. |
34b142d to
c9fac99
Compare
|
The split is up. #112 holds the programs that write the existing corpora, from its own branch, for your C++ lint and static analysis commits. This PR is rebased onto it (base
🤖 Posted autonomously by Claude on behalf of pasta. |
8505bf4 to
fa6c595
Compare
c9fac99 to
b821aff
Compare
thepastaclaw
left a comment
There was a problem hiding this comment.
Re-review — Final validation — Phase 1 + Phase 2
Independently reviewed the complete fa6c595..b821aff diff and found no actionable in-scope defects. The legacy read exceptions match the inspected pinned Dash Core/Relic and blst implementations, while off-curve encodings remain rejected by typed decoding. Validation was static-only: current CI reports passing lint, documentation, completed stable-platform jobs, and the Linux cross-build; MSRV, remaining ARM jobs, and Windows/macOS cross-builds remain pending, with no failed checks reported.
🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)
Review provenance
Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 4: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 5: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
criticalbygpt-6.1-sol(effort low) — The intricate changes to legacy public-key and signature decoding and canonicality in scheme_chia.rs, public_ops.rs, and sig_basic.rs directly alter cryptographic input acceptance rules. - Phase 1 reviewers:
muse-spark-1.3-contributor— general (completed, effort xhigh); agentphase1-reviewer,muse-spark-1.3-contributor— rust-quality (completed, effort xhigh); agentphase1-reviewer - Phase 1 model:
muse-spark-1.3-contributor— not quota-gated; passed overgemini-3.8-flash-high(antigravity quota lookup failed),glm-5.3-flash(not used above high effort; tier asks max) - Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
- Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
- Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.
No unresolved findings remain from the prior review on this head.
ccae7d7 to
b9ab99a
Compare
ce2818b to
b80238e
Compare
thepastaclaw
left a comment
There was a problem hiding this comment.
Re-review — Final validation — Phase 1 + Phase 2
Verified the complete diff at b80238e against the pinned Dash Core/relic readers and blst 0.3.17; no actionable in-scope defects were found. Independent relic-derived corpus annotations now enforce typed rejection of legacy off-curve encodings, while IETF validation remains unchanged. This was static-only verification: current CI reports Windows and ARM Linux stable passing, with lint, MSRV, macOS, cross-platform and corpus checks pending and no failed code checks reported.
🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)
Review provenance
Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 5: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
criticalbygpt-6.1-sol(effort low) — The diff makes intricate changes to cryptographic key decoding and signature canonicality in pkgs/pkc/src/bls/scheme_chia.rs, including pk_from_bytes, is_canonical_pk and is_canonical_sig, with scheme-specific flag handling and off-curve acceptance rules. - Phase 1 reviewers:
muse-spark-1.3-contributor— general (completed, effort xhigh); agentphase1-reviewer,muse-spark-1.3-contributor— rust-quality (completed, effort xhigh); agentphase1-reviewer - Phase 1 model:
muse-spark-1.3-contributor— not quota-gated; passed overgemini-3.8-flash-high(antigravity quota lookup failed),glm-5.3-flash(not used above high effort; tier asks max) - Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
- Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
- Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.
No unresolved findings remain from the prior review on this head.
Out-of-scope follow-up suggestions (1)
These are valid observations, but they are outside this PR's scope and should be handled in separate issues or author/maintainer-requested PRs rather than blocking this review.
- Validate legacy DH peers separately from consensus-compatible decoding — The base already admits off-subgroup legacy G1 points, explicitly exercised by off_subgroup_peer_policy. The unchanged BlsScheme::dh_exchange multiplies these points by a secret scalar without subgroup validation, and legacy IES reaches this operation through supplied ephemeral keys. Small-subgroup inputs restrict the possible shared secrets and can reveal information about a reused scalar when application-level plaintext acceptance is observable. This is a pre-existing secret-operation boundary issue, separate from the parsing compatibility corrected here.
- Follow-up: Track subgroup and identity validation at the legacy DH/IES boundary in a separate security issue or maintainer-requested PR, with small-subgroup attack vectors; retain consensus-compatible parsing.
b9ab99a to
b59f374
Compare
b80238e to
5cf2356
Compare
b59f374 to
5e0c21a
Compare
5cf2356 to
93f399c
Compare
thepastaclaw
left a comment
There was a problem hiding this comment.
Re-review — Final validation — Phase 1 + Phase 2
Reviewed the complete diff at 93f399c against the pinned Dash Core/relic readers and blst 0.3.17; no actionable in-scope defects remain. The independent corpus annotations and assertions address the prior typed-decoder coverage finding, and the performance suggestion remains withdrawn. Validation was static-only: diff checks passed and the worktree is unchanged; current CI shows all three stable-platform jobs and documentation passing, with lint, MSRV, cross-build, and corpus-regeneration checks still pending and no reported failures.
🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)
Review provenance
Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 5: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
criticalbygpt-6.1-sol(effort low) — The diff intricately changes cryptographic key and signature decoding and canonicality across scheme_chia.rs, public_ops.rs, and sig_basic.rs, including legacy off-curve acceptance and special-case G1 decoding. - Phase 1 reviewers:
muse-spark-1.3-contributor— general (completed, effort xhigh); agentphase1-reviewer,muse-spark-1.3-contributor— rust-quality (completed, effort xhigh); agentphase1-reviewer - Phase 1 model:
muse-spark-1.3-contributor— not quota-gated; passed overgemini-3.8-flash-high(antigravity quota lookup failed),glm-5.3-flash(not used above high effort; tier asks max) - Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
- Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
- Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.
No unresolved findings remain from the prior review on this head.
* [e8ce915] pkc%test(bls): add the reference implementation as a submodule (pasta) * [76704ec] sdk%build(nix): add `corpora.nix` with CMake, Boost and GMP (pasta) * [4feb192] pkc%test(bls): add programs that write the BLS corpora (pasta) * [5e0c21a] sdk%ci(gha): build the corpus generators weekly (pasta) Description: ````` ## Motivation The BLS corpora in `pkgs/pkc/corpus` are written from the reference implementation, but the programs that wrote them are not in the repository. This pull request adds them, with `regen.py` to write every corpus again from a pinned release, so a corpus can be checked or extended later. It is split out of #101, which adds one more program on top of it. ## Additional Information | Description | Notes | | ----------- | ----- | | Add the reference implementation as a submodule | `pkgs/pkc/contrib/dash`, pinned at v24.0.0-rc.5 (8163290aa0), shallow and with `update = none`, so a clone, `git submodule update` and CI checkouts skip it. Only `regen.py` checks it out. Bazel, CodeQL and the crate package skip it, as its tree carries build files of its own. | | Add programs that write the BLS corpora | Each `gen_*.cpp` links the release's BLS library (dashbls, with relic), plus a few of the release's own sources where a corpus needs them, and prints one corpus. `regen.py` extracts the release's `src`, builds the library, compiles and runs every program, and writes the corpora only when all of them succeed. The nine corpora come out byte-identical, so this changes no corpus. `pkgs/pkc/contrib/README.md` has the recipe. | | Add autotools and GMP to the dev shell | `contrib/nix/shell/dev.nix` gains autoconf, automake, libtool, pkg-config and GMP for `regen.py`. The CI shell is unchanged. | Bazel has no build for the library, and the release's copy of the library builds with autotools only, as the reference implementation stopped tracking relic's CMake configuration template. So `regen.py` runs that build, which needs a POSIX shell, and GMP is required. When these programs were added, the corpora were also checked equal at v23.1.8 (728f505583). The C++ here is as it was in #101 and predates the clang-format style in #111. As discussed in #101, this branch is open for the C++ lint and static analysis commits. Whichever of this and #111 lands second will adapt. ## Breaking Changes None. No library code changes. ## How Has This Been Tested? - `regen.py` writes the nine corpora byte-identical to the committed ones, with GCC 15 and with clang 21 building both the library and the programs, from a fresh clone that fetches the submodule and from an existing build. - A failed library build, a submodule checked out at another commit and an invalid option each stop the run with nothing written. - Only Linux x86_64 was run. macOS and Windows are untested, and the dev shell change has not been run in a Nix shell. - `cargo test -p dash-pkc --all-features` passes, and the lint suite is clean with the submodule checked out. - CI (`just test lint fuzz::test`, CodeQL included) is green on each commit. ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional tests - [x] I have made corresponding changes to the documentation - [ ] I did not use agentic assistance (i.e. LLMs, AI) except as [disclosed](#agent-disclosure) and can answer questions, comments and concerns without said assistance. I assume authorship of the code submitted. - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ ### Agent disclosure Code, commit messages and this description were generated with Claude Code using Claude Opus 5.5, running autonomously as an agent on behalf of the author. The agent also built the pinned release's BLS library and wrote the corpora with it. The change was reviewed by a Claude Code agent using Opus 5.5. 🤖 Generated with [Claude Code](https://claude.com/claude-code) `````
kwvg
left a comment
There was a problem hiding this comment.
Change the base branch to develop now that the underlying branch has been merged, see comments.
|
Thanks. I've retargeted the base to We'll take both comments:
The corpus will be regenerated and checked to be byte-identical wherever it's unaffected. I'll reply on each thread when the update is pushed. 🤖 Posted autonomously by Claude on behalf of pasta. |
gen_read.cpp draws seeded inputs, each class's property decided or checked by the pinned release's BLS library, and records how that library reads each as a key or signature under both schemes.
The reference implementation reads `x = 0` with the sign bit set, (0, -2), under the legacy scheme. blst's decompression writes the point out but reports an error, so keep the point it wrote.
The reference implementation accepts a legacy encoding of an `x` with no point on the curve, for signatures only with the sign bit clear. `to` has no point to return for these bytes and still refuses them.
Each `bls_read` input must read as in the reference implementation: `is_canonical` follows its outcome, and a valid input decodes and encodes back to itself unless the corpus marks its `x` off the curve.
93f399c to
1ebd2c2
Compare
thepastaclaw
left a comment
There was a problem hiding this comment.
Re-review — Final validation — Phase 1 + Phase 2
Static verification of the complete diff at 1ebd2c2 found no actionable in-scope defects. The legacy acceptance changes match the pinned Dash Core/RELIC readers, while typed decoding continues to reject off-curve inputs and the corpus independently asserts that boundary. No builds or tests were run in this static lane; current-head build/test, lint, cross-platform, and corpus-validation checks remain pending, so the description's all-green claim is not yet confirmed.
🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)
Review provenance
Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 4: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 5: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
criticalbygpt-6.1-sol(effort low) — The coordinated changes to G1/G2 encoding conversion and canonicality in pkgs/pkc/src/bls/scheme_chia.rs, together with error-dependent point recovery in G1Affine::uncompress_on_curve, constitute intricate changes to cryptographic key and signature handling. - Phase 1 reviewers:
muse-spark-1.3-contributor— general (completed, effort xhigh); agentphase1-reviewer,muse-spark-1.3-contributor— rust-quality (completed, effort xhigh); agentphase1-reviewer - Phase 1 model:
muse-spark-1.3-contributor— not quota-gated; passed overgemini-3.8-flash-high(antigravity quota lookup failed),glm-5.3-flash(not used above high effort; tier asks max) - Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
- Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
- Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— general (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort xhigh); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort xhigh); agentphase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.
No unresolved findings remain from the prior review on this head.
Out-of-scope follow-up suggestions (1)
These are valid observations, but they are outside this PR's scope and should be handled in separate issues or author/maintainer-requested PRs rather than blocking this review.
- Validate legacy DH peers separately from consensus-compatible wire reads — The unchanged BlsScheme::dh_exchange in pkgs/pkc/src/bls/scheme_ops.rs multiplies the peer point by the secret scalar without validating subgroup membership, and the legacy point-conversion paths add no validation. This behavior predates the PR and is explicitly exercised by the existing off_subgroup_peer_policy test. Attacker-supplied small-order peers can restrict shared secrets to a small set; observable decryption outcomes can consequently disclose secret-dependent information. This is a separate cryptographic-operation boundary issue, not a reason to tighten consensus-compatible legacy decoding.
- Follow-up: Track a separate issue or maintainer-requested PR to validate subgroup membership and reject identity peers at the legacy DH/IES operation boundary while preserving legacy wire-read compatibility.
Takes dashpay#100 dashpay#88 dashpay#108 dashpay#107 dashpay#111 dashpay#110 dashpay#112 dashpay#115 dashpay#114 dashpay#101. ChainSetup keeps the DEC-1043 policy fields; the BS11 BLS wrappers, i64 TxOut values and MAX_SER_SIZE payload bound stay for Core parity.
…plementation does (dashpay#101) * [03eefd7] pkc%test(bls): add a program that writes the BLS read corpus (pasta) * [6bff16d] pkc%fix(bls): read legacy G1 `x = 0` with the sign bit set (pasta) * [ac2355f] pkc%fix(bls): accept legacy encodings off the curve in `is_canonical` (pasta) * [137d329] pkc%test(bls): check BLS reads against the reference outcomes (pasta) * [1ebd2c2] pkc%doc: update changelog for the legacy BLS reads (pasta) Description: ````` ## Motivation `dash-pkc` reads BLS bytes at two levels. `to::<S>()` decodes an element, and `is_canonical::<S>()` says whether the scheme reads the bytes as an element that encodes back to them. Under the legacy scheme, the reference implementation accepts three kinds of input that `dash-pkc` refuses: - a public key with `x = 0` with the sign bit set, (0, -2). blst's decompression writes this point out but reports an error; - a public key encoding an `x` below the field prime with no point on the curve, with bits 5-6 clear, under either sign; - a signature encoding an `x` with no point on the curve, with both halves below the field prime and the sign bit and the top three bits of `x.c1` clear. This pull request makes `to::<BlsScChia>()` decode the first kind and `is_canonical::<BlsScChia>()` accept all three. `to` still refuses the off-curve encodings, since there is no point to return for them, and its rustdoc says so. The basic scheme is unchanged, and so is the stray-bit masking on the legacy G1 path. ## Additional Information This pull request is based on `pasta/bls-corpus-gen` (dashpay#112), which adds the reference implementation as a submodule and the programs that write the other BLS corpora. | Description | Notes | | ----------- | ----- | | Add a program that writes the BLS read corpus | `gen_read.cpp` builds seeded inputs with relic's field and curve operations and writes `pkgs/pkc/corpus/bls_read.json5`: 79 public-key and 130 signature inputs, each with the library's outcome under the legacy and basic schemes, `null`, `valid` or `invalid`. For each input the legacy scheme reads as valid, relic also gives whether its `x` has a point on the curve. `regen.py` writes it with the other corpora. | | Read legacy G1 `x = 0` with the sign bit set | `to` and `is_canonical` accept it, and it round-trips. With the sign bit clear, stray bits 5-6 mask `x = 0` down to the null encoding, so those bytes still do not decode. Adds `BlsScheme` methods `g1_bytes`, a point in the scheme's 48-byte layout, and `pk_ietf_bytes`, the IETF compressed form of an encoding in that layout; `BlsScChia` moves its legacy encoder and its legacy-to-IETF conversion into them. | | Accept legacy encodings off the curve in `is_canonical` | New `BlsScheme` methods `is_canonical_pk` and `is_canonical_sig` hold each scheme's rule. `BlsScIetf` keeps the previous rule, decode plus byte-exact re-encode. `BlsScChia` also accepts the off-curve encodings. `g2_bytes` is the G2 counterpart of `g1_bytes`, and `sig_ietf_x_bytes` gives the `x` of a G2 encoding in the IETF compressed layout, with the sign bit clear. | | Check BLS reads against the reference outcomes | Every corpus input is checked under both schemes, against `is_null`, `is_canonical` and the scheme's own predicate. `to` must fail for each legacy input the corpus marks off the curve, and decode and re-encode to itself for every other valid input. | | Update the changelog | Under "Changed" for the two read changes, and "Added" for the `BlsScheme` methods. | Each outcome in `bls_read.json5` comes from the release's read of the input: - the all-zero input is `null`; - otherwise the input is `valid` when the library's element reader, under the scheme flag, returns an element other than the identity that encodes back to the input; - anything else is `invalid`. The program is C++ because the library's element readers are its C++ API over relic. `pkgs/pkc/contrib/README.md` has the regeneration recipe. ## Breaking Changes None. `is_canonical::<BlsScChia>()` accepts more inputs and `to::<BlsScChia>()` decodes one more. `BlsScheme` gains six required methods, but the trait is sealed, so no implementation outside `dash-pkc` exists. CI (`just test lint fuzz::test`, CodeQL included) is green on each commit. ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have added or updated relevant unit/integration/functional tests - [x] I have made corresponding changes to the documentation - [ ] I did not use agentic assistance (i.e. LLMs, AI) except as [disclosed](#agent-disclosure) and can answer questions, comments and concerns without said assistance. I assume authorship of the code submitted. - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ ### Agent disclosure Code, commit messages and this description were generated with Claude Code using Claude Opus 5.5, running autonomously as an agent on behalf of the author. The agent also built the pinned release's BLS library and wrote the corpora with it. The change was reviewed by a Claude Code agent using Opus 5.5 and a Codex agent using GPT-6.1. 🤖 Generated with [Claude Code](https://claude.com/claude-code) `````
* [f3ac1b6] pkc%test(bls): run the legacy map's own steps in `gen_hash.cpp` (pasta) Description: ````` ## Motivation In #101 the program that writes `bls_read.json5` was reworked so that nothing in it stands in for the library. `gen_hash.cpp`, from #112, still repeats the legacy hash to G2's tag hashing and reduction steps with relic and takes only the final point from the library, so nothing showed that the steps it records are the ones the library runs. This pull request is the follow-up agreed in [the #101 review](#101 (comment)). ## Additional Information | Description | Notes | | ----------- | ----- | | Give two steps of the legacy map external linkage | `pkgs/pkc/contrib/util/legacy_steps.patch` gives the release's legacy map's encoding of a field element and its cofactor multiplication external linkage. Their code is unchanged. `regen.py` applies it after the relic template patch, and the build directory's name now covers both patches, so a build from before is not reused. | | Check the recorded steps against the library | For each message, `gen_hash.cpp` runs those two steps on the four field elements it writes, as the map does: the encodings of the two pairs, their sum and its cofactor multiple. The program stops, writing nothing, unless the result is the library's own map of the message. The hashing and reduction are still repeated with relic, as the map computes them inline. | The check ties every `_hash` and `_fp` value to the library except the order of the two pairs of tags, since the sum of their encodings is the same either way. `pkgs/pkc/contrib/README.md` says so. ## Breaking Changes None. No library code changes, and `bls_hash.json5` is unchanged. ## How Has This Been Tested? - `regen.py --program hash` extracts and builds the patched release afresh and writes `bls_hash.json5` byte-identical to the committed one, with GCC 15. Only Linux x86_64 was run. - With a wrong byte planted in the tag hashing, the program stops and nothing is written. Swapping the two elements of a pair, negating an element or a pair, and leaving out the cofactor step each stop it too. - The lint suite is clean with the submodule checked out. - CI (`just test lint fuzz::test`) is green on the commit. ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional tests - [x] I have made corresponding changes to the documentation - [ ] I did not use agentic assistance (i.e. LLMs, AI) except as [disclosed](#agent-disclosure) and can answer questions, comments and concerns without said assistance. I assume authorship of the code submitted. - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ ### Agent disclosure Code, commit messages and this description were generated with Claude Code using Claude Opus 5.5, running autonomously as an agent on behalf of the author. The agent also built the pinned release's BLS library and wrote the corpus with it. The change was reviewed by a Claude Code agent using Opus 5.5. 🤖 Generated with [Claude Code](https://claude.com/claude-code) `````
Motivation
dash-pkcreads BLS bytes at two levels.to::<S>()decodes an element, andis_canonical::<S>()says whether the scheme reads the bytes as an element that encodes back to them. Under the legacy scheme, the reference implementation accepts three kinds of input thatdash-pkcrefuses:x = 0with the sign bit set, (0, -2). blst's decompression writes this point out but reports an error;xbelow the field prime with no point on the curve, with bits 5-6 clear, under either sign;xwith no point on the curve, with both halves below the field prime and the sign bit and the top three bits ofx.c1clear.This pull request makes
to::<BlsScChia>()decode the first kind andis_canonical::<BlsScChia>()accept all three.tostill refuses the off-curve encodings, since there is no point to return for them, and its rustdoc says so. The basic scheme is unchanged, and so is the stray-bit masking on the legacy G1 path.Additional Information
This pull request is based on
pasta/bls-corpus-gen(#112), which adds the reference implementation as a submodule and the programs that write the other BLS corpora.gen_read.cppbuilds seeded inputs with relic's field and curve operations and writespkgs/pkc/corpus/bls_read.json5: 79 public-key and 130 signature inputs, each with the library's outcome under the legacy and basic schemes,null,validorinvalid. For each input the legacy scheme reads as valid, relic also gives whether itsxhas a point on the curve.regen.pywrites it with the other corpora.x = 0with the sign bit settoandis_canonicalaccept it, and it round-trips. With the sign bit clear, stray bits 5-6 maskx = 0down to the null encoding, so those bytes still do not decode. AddsBlsSchememethodsg1_bytes, a point in the scheme's 48-byte layout, andpk_ietf_bytes, the IETF compressed form of an encoding in that layout;BlsScChiamoves its legacy encoder and its legacy-to-IETF conversion into them.is_canonicalBlsSchememethodsis_canonical_pkandis_canonical_sighold each scheme's rule.BlsScIetfkeeps the previous rule, decode plus byte-exact re-encode.BlsScChiaalso accepts the off-curve encodings.g2_bytesis the G2 counterpart ofg1_bytes, andsig_ietf_x_bytesgives thexof a G2 encoding in the IETF compressed layout, with the sign bit clear.is_null,is_canonicaland the scheme's own predicate.tomust fail for each legacy input the corpus marks off the curve, and decode and re-encode to itself for every other valid input.BlsSchememethods.Each outcome in
bls_read.json5comes from the release's read of the input:null;validwhen the library's element reader, under the scheme flag, returns an element other than the identity that encodes back to the input;invalid.The program is C++ because the library's element readers are its C++ API over relic.
pkgs/pkc/contrib/README.mdhas the regeneration recipe.Breaking Changes
None.
is_canonical::<BlsScChia>()accepts more inputs andto::<BlsScChia>()decodes one more.BlsSchemegains six required methods, but the trait is sealed, so no implementation outsidedash-pkcexists.CI (
just test lint fuzz::test, CodeQL included) is green on each commit.Checklist
comments and concerns without said assistance. I assume authorship of the code submitted.
Agent disclosure
Code, commit messages and this description were generated with Claude Code using Claude Opus 5.5, running autonomously as an agent on behalf of the author. The agent also built the pinned release's BLS library and wrote the corpora with it. The change was reviewed by a Claude Code agent using Opus 5.5 and a Codex agent using GPT-6.1.
🤖 Generated with Claude Code