Context
Sui recently added a Move-callable P-384 ECDSA verify native (sui#26934, 0x2::ecdsa_p384::secp384r1_verify) for verifying Apple App Attest / Android Key Attestation certificate chains on-chain. It currently verifies via the RustCrypto p384 crate, which benchmarks ~12.8x slower than fastcrypto's secp256r1 verify (~532µs vs ~41.6µs on Apple Silicon), so the native shipped with a correspondingly high gas base (54,000).
A faster P-384 in fastcrypto would let Sui cut that gas cost ~3.6x and consolidate P-384 into its canonical crypto library.
Proposal
I have a working implementation that mirrors the existing secp256r1 module's architecture exactly:
ark-secp384r1 0.4.0 (same arkworks 0.4 family already used for ark-secp256r1/ark-secp256k1) for field/curve arithmetic.
- The existing generic
WindowedScalarMultiplier (256-point precomputed generator table, width-5 sliding window Straus double-mul) — same constants as secp256r1; width 6 and a 512-point table both benchmarked worse/marginal.
- The
p384 crate only for key/signature encoding and RFC6979 nonce generation, exactly as secp256r1 uses p256.
Measured (Apple Silicon, criterion, same inputs for both):
| op |
fastcrypto |
RustCrypto p384 |
speedup |
| verify |
143.5 µs |
518.6 µs |
3.61x |
| sign |
119.1 µs |
284.1 µs |
2.39x |
Correctness: wycheproof EcdsaSecp384r1Sha384 + EcdsaSecp384r1Sha512 sets (each vector also cross-checked to accept/reject identically to the p384 crate), RFC 6979 A.2.6 KATs, byte-for-byte sign equality with p384, proptest round-trips. ~34 scheme tests mirroring secp256r1_tests.rs.
Questions for maintainers before I finalize the PR
- Low-s policy: unlike
secp256r1, this module does not enforce low-s on verify (and does not normalize s on sign), because the target use case is verifying externally-produced X.509/attestation signatures and the goal is exact accept/reject equivalence with the p384 crate the Sui native uses today (which accepts high-s). Is this divergence acceptable if clearly documented, or would you prefer a separate strict/lenient API?
- Feature gating: I've gated the module behind
experimental ("features not yet audited"). If Sui is to consume this for a production native, what's your preferred path — audit then un-gate, or un-gated from the start like secp256r1?
- Scope: v1 is the full trait family (KeyPair/Signer/VerifyingKey/serde/zeroize/etc.) but without public-key recovery (
recoverable.rs), since the use case doesn't need it. OK?
Draft PR with the full implementation incoming — happy to adjust any of the above. The eventual win is letting sui#26934 lower its P-384 gas once this lands.
Context
Sui recently added a Move-callable P-384 ECDSA verify native (sui#26934,
0x2::ecdsa_p384::secp384r1_verify) for verifying Apple App Attest / Android Key Attestation certificate chains on-chain. It currently verifies via the RustCryptop384crate, which benchmarks ~12.8x slower than fastcrypto's secp256r1 verify (~532µs vs ~41.6µs on Apple Silicon), so the native shipped with a correspondingly high gas base (54,000).A faster P-384 in fastcrypto would let Sui cut that gas cost ~3.6x and consolidate P-384 into its canonical crypto library.
Proposal
I have a working implementation that mirrors the existing
secp256r1module's architecture exactly:ark-secp384r10.4.0 (same arkworks 0.4 family already used forark-secp256r1/ark-secp256k1) for field/curve arithmetic.WindowedScalarMultiplier(256-point precomputed generator table, width-5 sliding window Straus double-mul) — same constants as secp256r1; width 6 and a 512-point table both benchmarked worse/marginal.p384crate only for key/signature encoding and RFC6979 nonce generation, exactly assecp256r1usesp256.Measured (Apple Silicon, criterion, same inputs for both):
Correctness: wycheproof
EcdsaSecp384r1Sha384+EcdsaSecp384r1Sha512sets (each vector also cross-checked to accept/reject identically to thep384crate), RFC 6979 A.2.6 KATs, byte-for-byte sign equality withp384, proptest round-trips. ~34 scheme tests mirroringsecp256r1_tests.rs.Questions for maintainers before I finalize the PR
secp256r1, this module does not enforce low-s on verify (and does not normalize s on sign), because the target use case is verifying externally-produced X.509/attestation signatures and the goal is exact accept/reject equivalence with thep384crate the Sui native uses today (which accepts high-s). Is this divergence acceptable if clearly documented, or would you prefer a separate strict/lenient API?experimental("features not yet audited"). If Sui is to consume this for a production native, what's your preferred path — audit then un-gate, or un-gated from the start likesecp256r1?recoverable.rs), since the use case doesn't need it. OK?Draft PR with the full implementation incoming — happy to adjust any of the above. The eventual win is letting sui#26934 lower its P-384 gas once this lands.