Skip to content

Conversation

@commonware-llm
Copy link
Contributor

@commonware-llm commonware-llm commented Jan 1, 2026

Summary

Add batch verification for secp256r1 recoverable signatures using algebraic batching with random coefficients.

Features

  • Add Batch struct implementing BatchVerifier trait for recoverable signatures
  • Use algebraic batch verification: sum(z_i * u1_i) * G + sum(z_i * u2_i * P_i) - sum(z_i * R_i) = O
  • Random coefficients (z_i) prevent cancelling forgery attacks
  • Explicit rejection of malleable (high-s) signatures
  • Montgomery batch inversion optimization (1 inversion + 3(n-1) multiplications instead of n inversions)

Why Only Recoverable Signatures?

Standard ECDSA cannot benefit from algebraic batch verification because determining R requires computing u1*G + u2*P per signature - which IS the main verification cost. Recoverable signatures include the recovery ID needed to reconstruct R directly via point decompression.

Performance

Benchmark comparing batch verification vs individual verification (Apple Silicon):

Batch Size Individual Batch Speedup Per-sig (Individual) Per-sig (Batch)
1 406 µs 306 µs 1.33x 406 µs 306 µs
2 808 µs 502 µs 1.61x 404 µs 251 µs
4 1,649 µs 926 µs 1.78x 412 µs 232 µs
8 3,219 µs 1,704 µs 1.89x 402 µs 213 µs
16 6,432 µs 3,073 µs 2.09x 402 µs 192 µs
32 12,928 µs 6,063 µs 2.13x 404 µs 190 µs
64 26,178 µs 12,065 µs 2.17x 409 µs 189 µs
128 51,977 µs 23,930 µs 2.17x 406 µs 187 µs

Key Results

  • Asymptotic speedup: ~2.17x for large batches
  • Per-signature cost drops from ~406 µs to ~187 µs (54% reduction)
  • Even single signatures benefit (1.33x) because batch verification uses algebraic verification instead of public key recovery

claude added 5 commits January 1, 2026 18:25
Add BatchVerifier implementations for both standard and recoverable
secp256r1 signature variants.

For recoverable signatures: implements algebraic batch verification
using random coefficients. The recovery ID allows reconstructing the
signature point R directly, enabling the batch equation check:
  sum(z_i * u1_i) * G + sum(z_i * u2_i * P_i) - sum(z_i * R_i) = O

For standard signatures: implements sequential verification due to
ECDSA's limitation that standard signatures only contain r (the
x-coordinate of R). Without the recovery ID, determining R requires
computing u1*G + u2*P for each signature, which is the main cost of
individual verification.

Also adds:
- Unit tests for both batch verifiers
- Benchmarks for batch verification with multiple public keys/messages
Remove batch verification from the standard signature variant since
ECDSA without recovery ID cannot benefit from algebraic batch
verification - computing u1*G + u2*P for each signature to determine
R is the main verification cost anyway.

Batch verification is only available for recoverable signatures which
include the recovery ID needed to reconstruct R without scalar
multiplication.
…ation

Add explicit high-s check in batch verification to reject malleable
signatures. ECDSA signatures have a malleability property where both
(r, s) and (r, n-s) are mathematically valid. We enforce low-s to
prevent signature malleability attacks.

Also adds test that explicitly verifies batch verification rejects
malleable (high-s) signatures.
Add test that verifies batch verification correctly rejects the
"cancelling forgery" attack where an attacker creates two invalid
signatures with R1'=R1+delta and R2'=R2-delta. The random coefficients
(z_i) in batch verification prevent this attack since z1*(error) +
z2*(-error) = error*(z1-z2) ≠ 0 with overwhelming probability.
Move all inline imports in batch verification tests to the top of
the test module per project style guidelines.
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Jan 1, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
commonware-mcp 6595bd4 Jan 03 2026, 08:35 PM

@patrick-ogrady patrick-ogrady marked this pull request as draft January 1, 2026 19:14
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 370 to 374
// The x-coordinate might be r or r + n (if is_x_reduced)
// For P-256, this is extremely rare since n is close to p
if recovery_id.is_x_reduced() {
// r + n case - extremely rare for P-256
return None;

Choose a reason for hiding this comment

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

P2 Badge Handle x_reduced recovery IDs instead of rejecting

The batch verifier always returns false when recovery_id.is_x_reduced() is set because recover_r_point bails out, but valid recoverable signatures can legitimately have x = r + n (that is exactly what is_x_reduced signals). In that case individual verification/recovery would succeed, while batch verification will deterministically fail for that signature, so batch verification is not equivalent to single verification for all valid inputs. This is rare for P-256 but still a correctness bug; the fix is to reconstruct the point with x = r + n when is_x_reduced is true instead of rejecting.

Useful? React with 👍 / 👎.

…ication

Fix recover_r_point to properly handle the is_x_reduced case by computing
x = r + n instead of rejecting. While rare for P-256 (since n is close to p),
valid recoverable signatures can have x = r + n, and batch verification must
handle them equivalently to single verification.
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Jan 1, 2026

Deploying monorepo with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6595bd4
Status: ✅  Deploy successful!
Preview URL: https://86ed851d.monorepo-eu0.pages.dev
Branch Preview URL: https://claude-add-secp256r1-batch-v.monorepo-eu0.pages.dev

View logs

@patrick-ogrady
Copy link
Contributor

This isn't really worth the squeeze/complexity (the only place where batch verification makes sense is recoverable signatures where we already have the associated public keys).

@codecov
Copy link

codecov bot commented Jan 3, 2026

Codecov Report

❌ Patch coverage is 94.32990% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.63%. Comparing base (c5c573e) to head (dfae497).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
cryptography/src/secp256r1/recoverable.rs 94.32% 11 Missing ⚠️
@@           Coverage Diff            @@
##             main    #2661    +/-   ##
========================================
  Coverage   92.62%   92.63%            
========================================
  Files         357      357            
  Lines      102956   103150   +194     
========================================
+ Hits        95366    95548   +182     
- Misses       7590     7602    +12     
Files with missing lines Coverage Δ
cryptography/src/secp256r1/recoverable.rs 94.25% <94.32%> (+0.04%) ⬆️

... and 2 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c5c573e...dfae497. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…inversion

- Implement Montgomery's trick for batch scalar inversion, reducing n
  inversions to 1 inversion + 3(n-1) multiplications
- Add batch_vs_individual benchmark comparing batch to individual verification
- Add tests for batch_invert function

Performance improvement: ~7% faster batch verification, achieving ~2.17x
speedup over individual verification for large batches.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@patrick-ogrady
Copy link
Contributor

This isn't really worth the squeeze/complexity (the only place where batch verification makes sense is recoverable signatures where we already have the associated public keys).

It may be worth it if we want to just use recoverable signatures always (but seems to be slower than #2684)

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.

4 participants