Skip to content

pkc%feat(bls): migrate operational types to Bls{PublicKey,SecretKey,BlsSignature}<S>, reap bls_{chia,ietf} modules for unified bls module - #25

Merged
kwvg merged 14 commits into
dashpay:developfrom
kwvg:pkc_p2
Aug 10, 2026
Merged

Conversation

@kwvg

@kwvg kwvg commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Additional Information

Breaking Changes

Old New
SecretKey::to_bytes() -> [u8; 32] BlsSecretKey::<S>::to_bytes() -> Zeroizing<[u8; 32]>
bls_chia::{PublicKey, SecretKey, Signature} bls::{BlsPublicKey, BlsSecretKey, BlsSignature}<BlsScChia>
bls_ietf::{PublicKey, SecretKey, Signature} bls::{BlsPublicKey, BlsSecretKey, BlsSignature}<BlsScIetf>
bls_{chia,ietf}::threshold::SecretKeyShare bls::BlsSkShare<S>
bls_{chia,ietf}::threshold::SignatureShare bls::BlsSigShare<S>
bls_ietf::Scheme bls::BlsSigId
PublicKey::dh_exchange(sk, peer_pk) BlsSecretKey::<S>::dh_exchange(&self, peer_pk)
bls_ietf::SecretKey::prove_possession, bls_ietf::PublicKey::verify_possession bls::BlsSecretKey::<BlsScIetf>::prove_possession, bls::BlsPublicKey::<BlsScIetf>::verify_possession
bls_{chia,ietf}::aggregate_pk BlsPublicKey::<S>::aggregate
bls_{chia,ietf}::aggregate_sk BlsSecretKey::<S>::aggregate
bls_{chia,ietf}::aggregate_sig BlsSignature::<S>::aggregate
bls_{chia,ietf}::{fast,secure}_verify_aggregates methods of the same name on BlsSignature<S>
bls_ietf::verify_aggregates BlsSignature::<BlsScIetf>::verify_aggregates
bls_{chia,ietf}::threshold::split_sk(sk, threshold, ids, rng) BlsSecretKey::<S>::split(&self, threshold, ids, rng)
bls_{chia,ietf}::threshold::recover_sig(shares) BlsSignature::<S>::recover(shares)
bls_{chia,ietf}::threshold::derive_pk_share(master_pks, id) BlsPublicKey::<S>::derive_share(master_pks, id)

How Has This Been Tested?

cargo fmt --check
cargo test --features full
cargo clippy --features full --all-targets
./contrib/lint_all.py --exclude lint_codeql
./contrib/lint/lint_codeql.py --with-suite rust-security-and-quality

Checklist

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

@kwvg kwvg added this to the 0.1 milestone Aug 10, 2026
@kwvg kwvg self-assigned this Aug 10, 2026
@github-actions

Copy link
Copy Markdown

Note

This pull request has no conflicts! 🎊 🎉 🎊

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR replaces separate Chia and IETF BLS APIs with scheme-generic key, signature, aggregation, threshold, and proof-of-possession APIs. It removes legacy modules, updates benchmarks and dependencies, and adjusts CodeQL secret classification.

Changes

Generic BLS API

Layer / File(s) Summary
BLS module and scheme foundation
pkgs/pkc/Cargo.toml, pkgs/pkc/src/bls/*, pkgs/pkc/src/prelude.rs
The crate wires generic BLS modules, exposes FFI wrappers, strengthens scheme bounds, updates test configuration, and replaces hex-literal. Legacy Chia and IETF modules and shared contracts are removed.
Generic keys, signatures, and proof of possession
pkgs/pkc/src/bls/public_ops.rs, pkgs/pkc/src/bls/secret_ops.rs, pkgs/pkc/src/bls/sig_basic.rs, pkgs/pkc/src/bls/sig_pop.rs
The new wrappers provide key generation, serialization, signing, verification, DH exchange, conversions, hashing, zeroization, IETF domain separation, and proof-of-possession operations.
Aggregation and threshold operations
pkgs/pkc/src/bls/share_ops.rs, pkgs/pkc/src/bls/sig_aggregate.rs, pkgs/pkc/src/bls/sig_threshold.rs
The generic API adds public-key and signature aggregation, aggregate verification, threshold splitting, share derivation, signature recovery, and validation tests.
Unified BLS benchmarks
pkgs/pkc/bench/bls.rs, pkgs/pkc/bench/main.rs
The benchmark harness uses one BLS module and measures signing, verification, aggregation, serialization, threshold operations, IETF operations, and parallel standard-library operations.

CodeQL secret classification

Layer / File(s) Summary
Secret-type classification
contrib/codeql/lib/policy.qll, contrib/codeql/zeroize.ql
CodeQL excludes BlsSigShare and classifies types that satisfy wipesSelf as secret-bearing.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant BlsSecretKey
  participant BlsSignature
  participant BlsScheme
  Caller->>BlsSecretKey: sign(message)
  BlsSecretKey->>BlsScheme: sign_with(secret key, message)
  BlsScheme-->>BlsSecretKey: inner signature
  BlsSecretKey-->>Caller: BlsSignature
  Caller->>BlsSignature: verify(message, public key)
  BlsSignature->>BlsScheme: verify_with(signature, message, public key)
  BlsScheme-->>BlsSignature: verify_ok(BLST_ERROR)
  BlsSignature-->>Caller: Result
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
Title check ✅ Passed The title clearly summarizes the migration to generic BLS types and the removal of separate scheme modules.
Description check ✅ Passed The description directly explains the BLS migration, breaking API changes, security updates, dependencies, and testing performed.

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

@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: 3

🧹 Nitpick comments (3)
pkgs/pkc/src/bls/scheme_ietf.rs (1)

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

Extract the DST selection into one helper.

sign_with and verify_with repeat the same match over BlsSigId. If one copy changes, signing and verification can select different domain separation tags, and the mismatch is silent until a verification fails.

♻️ Proposed refactor
 impl BlsScIetf {
+  /// Select the DST for the given signature scheme id.
+  fn dst_for(id: BlsSigId) -> &'static [u8] {
+    match id {
+      BlsSigId::Basic => DST_BASIC,
+      BlsSigId::ProofOfPossession => DST_POP,
+    }
+  }
+
   /// Sign under the DST selected by `id`.
   pub(crate) fn sign_with(sk: &SecretKey, msg: &[u8], id: BlsSigId) -> Signature {
-    let dst = match id {
-      BlsSigId::Basic => DST_BASIC,
-      BlsSigId::ProofOfPossession => DST_POP,
-    };
-    sk.sign(msg, dst, &[])
+    sk.sign(msg, Self::dst_for(id), &[])
   }
 
   /// Verify under the DST selected by `id`.
   ///
   /// # Errors
   ///
   /// Returns `VerifyFailed` when the pairing check does not hold.
   pub(crate) fn verify_with(sig: &Signature, msg: &[u8], pk: &PublicKey, id: BlsSigId) -> Result<(), BlsError> {
-    let dst = match id {
-      BlsSigId::Basic => DST_BASIC,
-      BlsSigId::ProofOfPossession => DST_POP,
-    };
-    verify_ok(sig.verify(true, msg, dst, &[], pk, true))
+    verify_ok(sig.verify(true, msg, Self::dst_for(id), &[], pk, true))
   }
🤖 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 `@pkgs/pkc/src/bls/scheme_ietf.rs` around lines 158 - 179, Extract the shared
BlsSigId-to-DST match into a helper associated with BlsScIetf, then update
sign_with and verify_with to reuse it instead of selecting the DST
independently. Preserve the existing DST_BASIC and DST_POP mappings.
pkgs/pkc/src/bls/sig_aggregate.rs (1)

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

Add coverage for the verify_aggregates error contract.

BlsScIetf::verify_aggregates documents CountMismatch for unequal counts and EmptyAggregation for no keys. ietf_verify_distinct_messages covers only the success path and the swapped-message path. Add cases for a message/key count mismatch and for empty inputs, so the documented error contract stays pinned.

💚 Proposed additional test
+  #[rstest]
+  fn ietf_verify_aggregates_rejects_bad_inputs() {
+    let sk = BlsSecretKey::<BlsScIetf>::generate(&SEED_0).unwrap();
+    let msg: &[u8] = b"first message";
+    let sig = sk.sign(msg);
+    let pk = sk.public_key();
+
+    assert!(matches!(
+      sig.verify_aggregates(&[msg], &[&pk, &pk]),
+      Err(BlsError::CountMismatch)
+    ));
+    assert!(matches!(
+      sig.verify_aggregates(&[], &[]),
+      Err(BlsError::EmptyAggregation)
+    ));
+  }
🤖 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 `@pkgs/pkc/src/bls/sig_aggregate.rs` around lines 150 - 165, Extend
ietf_verify_distinct_messages to assert the verify_aggregates error contract:
add a case with unequal message and public-key counts that returns
CountMismatch, and a case with empty inputs that returns EmptyAggregation. Keep
the existing successful and swapped-message assertions unchanged.
pkgs/pkc/src/bls/sig_threshold.rs (1)

17-31: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Document that Ok does not prove a sufficient quorum.

recover interpolates any set of two or more valid shares. The test assert_sub_threshold_does_not_verify at lines 79-91 confirms that a below-threshold set still returns Ok, and only verification rejects the result. The current Rustdoc does not state this. A caller can read Ok as proof of a valid quorum. Add a note that the caller must verify the recovered signature against the group public key.

📝 Proposed doc addition
   /// Recover a full signature from threshold signature shares via Lagrange
   /// interpolation in G2.
   ///
+  /// Recovery does not check that the share count reaches the threshold used
+  /// at split time. A below-threshold set still interpolates to a point and
+  /// returns `Ok`. Verify the recovered signature against the group public
+  /// key before you trust it.
+  ///
   /// # Errors
🤖 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 `@pkgs/pkc/src/bls/sig_threshold.rs` around lines 17 - 31, Update the Rustdoc
for `BlsSignature::recover` to state that successful interpolation does not
establish a sufficient quorum, since two or more valid shares may return `Ok`.
Explicitly instruct callers to verify the recovered signature against the group
public key.
🤖 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 `@pkgs/pkc/bench/bls.rs`:
- Around line 171-184: Update the 1,000-item benchmark setup around BlsSecretKey
generation and test_msg calls to use inputs that remain unique across all n
entries, avoiding the u8 truncation at 256. Prefer usize-compatible helper
inputs while preserving the existing n-sized keys, messages, signatures, and
aggregate flow.

In `@pkgs/pkc/src/bls/scheme_ietf.rs`:
- Around line 203-211: Update verify_aggregates to reject duplicate entries in
msgs before invoking sig.aggregate_verify, while preserving the existing count
and empty-aggregation checks. Detect equality across the full message byte
slices, return the appropriate BlsError for invalid aggregation, and only call
aggregate_verify when all messages are unique.

In `@pkgs/pkc/src/bls/secret_ops.rs`:
- Around line 63-75: Change dh_exchange to return a dedicated shared-secret
newtype rather than BlsPublicKey, with redacted Debug, constant-time equality,
and zeroization, and update callers accordingly. Add explicit prime-order
subgroup validation in the BlsScChia DH implementation before scalar
multiplication, including validation of the peer key and resulting point as
required by the existing error contract. Add a regression test covering
rejection of an on-curve, non-subgroup peer key.

---

Nitpick comments:
In `@pkgs/pkc/src/bls/scheme_ietf.rs`:
- Around line 158-179: Extract the shared BlsSigId-to-DST match into a helper
associated with BlsScIetf, then update sign_with and verify_with to reuse it
instead of selecting the DST independently. Preserve the existing DST_BASIC and
DST_POP mappings.

In `@pkgs/pkc/src/bls/sig_aggregate.rs`:
- Around line 150-165: Extend ietf_verify_distinct_messages to assert the
verify_aggregates error contract: add a case with unequal message and public-key
counts that returns CountMismatch, and a case with empty inputs that returns
EmptyAggregation. Keep the existing successful and swapped-message assertions
unchanged.

In `@pkgs/pkc/src/bls/sig_threshold.rs`:
- Around line 17-31: Update the Rustdoc for `BlsSignature::recover` to state
that successful interpolation does not establish a sufficient quorum, since two
or more valid shares may return `Ok`. Explicitly instruct callers to verify the
recovered signature against the group public key.
🪄 Autofix

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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dc0d1af9-30c9-4d4f-a786-35c53aa16017

📥 Commits

Reviewing files that changed from the base of the PR and between 5321155 and c5357d1.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock, !**/*.lock
📒 Files selected for processing (53)
  • contrib/codeql/lib/policy.qll
  • contrib/codeql/zeroize.ql
  • pkgs/pkc/Cargo.toml
  • pkgs/pkc/bench/bls.rs
  • pkgs/pkc/bench/bls_chia.rs
  • pkgs/pkc/bench/bls_ietf.rs
  • pkgs/pkc/bench/main.rs
  • pkgs/pkc/src/bls/blst_ffi.rs
  • pkgs/pkc/src/bls/chia_h2c.rs
  • pkgs/pkc/src/bls/mod.rs
  • pkgs/pkc/src/bls/public_ops.rs
  • pkgs/pkc/src/bls/scheme_chia.rs
  • pkgs/pkc/src/bls/scheme_ietf.rs
  • pkgs/pkc/src/bls/scheme_ops.rs
  • pkgs/pkc/src/bls/secret_ops.rs
  • pkgs/pkc/src/bls/share_ops.rs
  • pkgs/pkc/src/bls/sig_aggregate.rs
  • pkgs/pkc/src/bls/sig_basic.rs
  • pkgs/pkc/src/bls/sig_pop.rs
  • pkgs/pkc/src/bls/sig_threshold.rs
  • pkgs/pkc/src/bls/tests.rs
  • pkgs/pkc/src/bls_chia/agg.rs
  • pkgs/pkc/src/bls_chia/mod.rs
  • pkgs/pkc/src/bls_chia/pk.rs
  • pkgs/pkc/src/bls_chia/sig.rs
  • pkgs/pkc/src/bls_chia/sk.rs
  • pkgs/pkc/src/bls_chia/threshold.rs
  • pkgs/pkc/src/bls_ietf/agg.rs
  • pkgs/pkc/src/bls_ietf/mod.rs
  • pkgs/pkc/src/bls_ietf/pk.rs
  • pkgs/pkc/src/bls_ietf/sig.rs
  • pkgs/pkc/src/bls_ietf/sk.rs
  • pkgs/pkc/src/bls_ietf/threshold.rs
  • pkgs/pkc/src/common/bls/contract.rs
  • pkgs/pkc/src/common/bls/mod.rs
  • pkgs/pkc/src/common/mod.rs
  • pkgs/pkc/src/lib.rs
  • pkgs/pkc/src/prelude.rs
  • pkgs/pkc/tests/bls_chia_aggregate.rs
  • pkgs/pkc/tests/bls_chia_dh.rs
  • pkgs/pkc/tests/bls_chia_keygen.rs
  • pkgs/pkc/tests/bls_chia_llmq.rs
  • pkgs/pkc/tests/bls_chia_ser.rs
  • pkgs/pkc/tests/bls_chia_sign.rs
  • pkgs/pkc/tests/bls_chia_threshold.rs
  • pkgs/pkc/tests/bls_ietf_aggregate.rs
  • pkgs/pkc/tests/bls_ietf_dh.rs
  • pkgs/pkc/tests/bls_ietf_keygen.rs
  • pkgs/pkc/tests/bls_ietf_llmq.rs
  • pkgs/pkc/tests/bls_ietf_pop.rs
  • pkgs/pkc/tests/bls_ietf_sign.rs
  • pkgs/pkc/tests/bls_ietf_threshold.rs
  • pkgs/pkc/tests/common/mod.rs
💤 Files with no reviewable changes (33)
  • pkgs/pkc/tests/common/mod.rs
  • pkgs/pkc/src/bls_chia/sk.rs
  • pkgs/pkc/src/bls_chia/pk.rs
  • pkgs/pkc/bench/bls_ietf.rs
  • pkgs/pkc/src/bls_chia/sig.rs
  • pkgs/pkc/src/lib.rs
  • pkgs/pkc/src/bls_ietf/sig.rs
  • pkgs/pkc/tests/bls_ietf_dh.rs
  • pkgs/pkc/tests/bls_ietf_pop.rs
  • pkgs/pkc/tests/bls_ietf_keygen.rs
  • pkgs/pkc/tests/bls_chia_dh.rs
  • pkgs/pkc/src/bls_chia/agg.rs
  • pkgs/pkc/src/bls_ietf/mod.rs
  • pkgs/pkc/src/bls_chia/mod.rs
  • pkgs/pkc/src/common/bls/contract.rs
  • pkgs/pkc/bench/bls_chia.rs
  • pkgs/pkc/src/bls_ietf/sk.rs
  • pkgs/pkc/tests/bls_ietf_llmq.rs
  • pkgs/pkc/tests/bls_chia_aggregate.rs
  • pkgs/pkc/src/common/mod.rs
  • pkgs/pkc/tests/bls_chia_llmq.rs
  • pkgs/pkc/tests/bls_chia_threshold.rs
  • pkgs/pkc/tests/bls_chia_ser.rs
  • pkgs/pkc/tests/bls_chia_keygen.rs
  • pkgs/pkc/src/bls_ietf/pk.rs
  • pkgs/pkc/tests/bls_ietf_aggregate.rs
  • pkgs/pkc/src/bls_chia/threshold.rs
  • pkgs/pkc/tests/bls_chia_sign.rs
  • pkgs/pkc/src/bls_ietf/agg.rs
  • pkgs/pkc/src/common/bls/mod.rs
  • pkgs/pkc/tests/bls_ietf_sign.rs
  • pkgs/pkc/tests/bls_ietf_threshold.rs
  • pkgs/pkc/src/bls_ietf/threshold.rs

Comment thread pkgs/pkc/bench/bls.rs
Comment thread pkgs/pkc/src/bls/scheme_ietf.rs
Comment thread pkgs/pkc/src/bls/secret_ops.rs
@kwvg
kwvg marked this pull request as ready for review August 10, 2026 11:02
@kwvg
kwvg merged commit 0b0770d into dashpay:develop Aug 10, 2026
55 checks passed
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.

1 participant