# `@suaveplan/crypto-curve` — Add P-384 (`secp384r1`) and P-521 (`secp521r1`) primitives **Package**: `@suaveplan/crypto-curve` (extension) **Status**: PROPOSED **Type**: capability-extension **Date**: 2026-05-10 **Tier**: universal ## Why `@suaveplan/cbor` ships RFC 9052 COSE_Sign1 verify but the ES384 / ES512 algorithm branches throw `CborError(UNEXPECTED_TYPE)` with the message *"not implemented in @suaveplan/crypto-curve yet"* because the curve primitives were not previously exposed. Downstream consumers (WebAuthn attestation, federation tokens, FIDO2 device certificates) need both algorithms to interoperate with mainstream issuers — Apple's WebAuthn attestation, in particular, signs with ES384 in some configurations. `@noble/curves@1.9.7` (already installed across the workspace) exposes `p384` and `p521` with the same surface contract as `p256`. The work is purely additive — mirroring the existing `p256` per-primitive layout for two more curves and threading them through to the COSE verifier. ## What changes ### New primitives in `@suaveplan/crypto-curve` #### P-384 - ADDED: `primitives/p384/p384.ts` — re-exports the select layer. - ADDED: `primitives/p384/p384.select/p384.select.ts` — selector pinned to the noble implementation (generated forwarder, mirroring p256). - ADDED: `primitives/p384/impl/p384.noble/p384.noble.ts` — noble-backed `getPublicKey`, `sign`, `verify`, `randomPrivateKey`. - ADDED: `primitives/p384/impl/p384.native/p384.native.ts` — `PrimitiveNotImplemented` stubs matching the p256 native pattern. #### P-521 - ADDED: `primitives/p521/p521.ts` and full mirror of the p384 layout (`p521.select`, `impl/p521.noble`, `impl/p521.native`). #### Barrel + subpath exports - ADDED: `export * as p384 from "./primitives/p384/p384.js"` to root barrel. - ADDED: `export * as p521 from "./primitives/p521/p521.js"` to root barrel. - ADDED: `./p384` and `./p521` subpath exports in `package.json`. - ADDED: corresponding entries in `vite.config.ts` external list (so consumers can tree-shake to the individual primitive). ### COSE wiring in `@suaveplan/cbor` - MODIFIED: `verifyCoseSign1` switch — `ES384` and `ES512` branches call `p384.verify(sig, sha384(tbs), pk)` and `p521.verify(sig, sha512(tbs), pk)` respectively (replacing the `UNEXPECTED_TYPE` placeholder throws). - MODIFIED: `ec2ToCompressedPoint` — generalised to accept coordinate length (32 / 48 / 66) so the same helper compresses P-256 / P-384 / P-521. ### Dependencies No new dependencies. `@noble/curves@1.9.7` is the catalog-pinned version that ships both `p384` and `p521` subpath exports. ## Out of scope - WebCrypto-native impls — the existing `p256.native` stub pattern (`PrimitiveNotImplemented`) is preserved for both new curves; an opt-in WebCrypto path lands in a separate change when needed. - COSE Sign1 / Mac0 / Encrypt0 surfaces beyond the alg switch — already wired generically and need no changes. ## Source mapping | Requirement | Source | Notes | |---|---|---| | P-384 ECDSA | FIPS 186-4 §6 + NIST SP 800-186 | `@noble/curves/p384` | | P-521 ECDSA | FIPS 186-4 §6 + NIST SP 800-186 | `@noble/curves/p521` | | COSE ES384 / ES512 | RFC 9053 §2.1 | Already mapped in `alg-map.ts` | | Per-primitive selector layout | Existing crypto-curve convention | mirrors p256 | ## Verification approach - `packages/crypto/crypto-curve/src/primitives/p384/p384.test.ts` — noble - native impl: sign / verify round-trip, signature length, tampered-sig rejection, native `PrimitiveNotImplemented` throw. - `packages/crypto/crypto-curve/src/primitives/p521/p521.test.ts` — same. - `packages/vault/cbor/src/cose/sign1.test.ts` — extend to cover ES384 and ES512 round-trip via the new primitives. ## Migration impact Additive. No existing consumers break — the deferred branches in cbor were already throwing. ## Impact ### Affected dependents `@suaveplan/cbor` — ES384 / ES512 paths become operational; previously threw `UNEXPECTED_TYPE`. For all other packages: no behavioural change. The new primitives are opt-in subpath imports.