Skip to content

perf(auth): use ring for DPoP P-256 signature verification#43

Merged
m2papierz merged 8 commits into
latchgate-ai:mainfrom
CapThunder19:perf/dpop-ring-verify
Jun 13, 2026
Merged

perf(auth): use ring for DPoP P-256 signature verification#43
m2papierz merged 8 commits into
latchgate-ai:mainfrom
CapThunder19:perf/dpop-ring-verify

Conversation

@CapThunder19

@CapThunder19 CapThunder19 commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Replace RustCrypto p256 signature verification with ring in the DPoP verification hot path.

The previous implementation reconstructed a P256VerifyingKey from the JWK coordinates and verified ES256 signatures using p256::ecdsa::VerifyingKey::verify. This change switches verification to ring::signature::UnparsedPublicKey::verify with ECDSA_P256_SHA256_FIXED.

The public API of verify_dpop_proof remains unchanged. Client-side DPoP signing continues to use p256.

Changes

DPoP verification

  • Replaced P256VerifyingKey::verify with ring::signature::UnparsedPublicKey::verify.
  • Replaced vk_from_xy() with build_sec1_uncompressed().
  • Verify using SEC1 uncompressed public key bytes (0x04 || x || y).
  • Decode the JWT signature once and pass raw signature bytes into verify_sig().

Dependencies

  • Added ring as a direct dependency of latchgate-auth.

Benchmarks

  • Added dpop_verify_only_p256 benchmark to measure server-side DPoP verification cost in isolation.
  • Kept existing dpop_sign_verify_p256 benchmark for round-trip regression tracking.

Tests

  • Existing latchgate-auth test suite passes unchanged.
  • Added a regression test ensuring malformed/invalid EC public keys are rejected by the verification path.

Security

This change does not alter the cryptographic algorithm:

  • Curve: P-256
  • Signature scheme: ECDSA
  • Hash: SHA-256
  • Signature format: ES256 raw (r || s) format

Only the verification implementation changes from RustCrypto p256 to ring.

The DPoP proof is still verified on every request and all existing security checks remain intact.

Validation

  • cargo check -p latchgate-auth
  • cargo test -p latchgate-auth
  • Added regression coverage for invalid EC public keys

solves #39

@CapThunder19 CapThunder19 requested a review from m2papierz as a code owner June 11, 2026 07:26
@CapThunder19

CapThunder19 commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

Please review and let me know if there's anything that should be changed or improved

@m2papierz

Copy link
Copy Markdown
Contributor

@CapThunder19 thanks for taking this issue. Please first resolve the conflicts with the main branch after merging this: #41

@codspeed-hq

codspeed-hq Bot commented Jun 11, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by ×2.5

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 2 improved benchmarks
✅ 7 untouched benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
dpop_verify_cached_p256 1,040.9 µs 299.3 µs ×3.5
dpop_sign_verify_p256 1,665.7 µs 937.7 µs +77.63%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing CapThunder19:perf/dpop-ring-verify (0bc1a3d) with main (b3917a9)

Open in CodSpeed

@CapThunder19

Copy link
Copy Markdown
Contributor Author

Pls review it I have fixed the issue

@m2papierz m2papierz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The core migration is correct - right algorithm (ECDSA_P256_SHA256_FIXED = raw r||s, matching JWT ES256), security invariants intact, public API unchanged, all existing tests passing. Solid work.

Requesting changes on one high-severity performance issue and a handful of medium/low items. The high item is that the cache-hit hot path now pays for a P256VerifyingKey clone -> to_encoded_point -> ring re-parse round-trip on every request, which partially undermines the stated ~60–70 µs savings goal. The fix is changing the cache value type to raw [u8; 65] - the issue itself anticipated this, and since this PR already touches both the verify path and the cache insertion site, it belongs here rather than in a follow-up.

See inline comments for details on each item.

Comment thread crates/latchgate-auth/src/dpop/verify.rs Outdated
Comment thread crates/latchgate-auth/src/dpop/verify.rs
Comment thread crates/latchgate-auth/src/dpop/verify.rs
Comment thread tests/stress/benches/hot_paths.rs Outdated
Comment thread crates/latchgate-auth/src/dpop/verify.rs Outdated
Comment thread crates/latchgate-auth/src/dpop/verify.rs Outdated
Comment thread crates/latchgate-auth/src/dpop/verify.rs Outdated
@CapThunder19

Copy link
Copy Markdown
Contributor Author

pls review

@m2papierz m2papierz self-requested a review June 13, 2026 16:50

@m2papierz m2papierz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@CapThunder19 all resolved correctly. I am merging the PR. Thanks again for your contribution!

@m2papierz m2papierz merged commit 8b3a629 into latchgate-ai:main Jun 13, 2026
10 checks passed
@CapThunder19 CapThunder19 deleted the perf/dpop-ring-verify branch June 13, 2026 17:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants