130 lines
5.0 KiB
Markdown
130 lines
5.0 KiB
Markdown
<!-- markdownlint-disable MD024 -->
|
|
|
|
# Capability Spec Delta: crypto-curve (crypto-curve-p384-p521)
|
|
|
|
**Package**: `@suaveplan/crypto-curve`
|
|
**Status**: PROPOSED — additive delta; folded into canonical spec on archive.
|
|
|
|
## ADDED Requirements
|
|
|
|
### Requirement: NIST P-384 (secp384r1) ECDSA primitive
|
|
|
|
The package SHALL export a `p384` namespace from the root barrel and a
|
|
matching `./p384` subpath export, providing `getPublicKey`, `sign`,
|
|
`verify`, and `randomPrivateKey`. Private keys SHALL be 48 bytes,
|
|
compressed public keys SHALL be 49 bytes, and compact ECDSA signatures
|
|
SHALL be 96 bytes. Callers SHALL pre-hash messages; the module operates
|
|
on digests. The selector SHALL forward to the noble-backed implementation
|
|
by default; the native implementation SHALL throw
|
|
`PrimitiveNotImplemented("p384")` until a WebCrypto bridge lands.
|
|
|
|
#### Scenario: P-384 sign + verify round-trip
|
|
|
|
- **GIVEN** a freshly-generated P-384 private key and 48-byte digest
|
|
- **WHEN** `verify(sign(digest, sk), digest, getPublicKey(sk))` is computed
|
|
- **THEN** the result is `true`
|
|
|
|
#### Scenario: P-384 verify rejects tampered signature
|
|
|
|
- **WHEN** a single byte of a valid P-384 signature is XORed with `0xff`
|
|
- **THEN** `verify` returns `false`
|
|
|
|
#### Scenario: P-384 verify returns false on malformed inputs
|
|
|
|
- **WHEN** `verify` is invoked with non-`Uint8Array` inputs or empty
|
|
buffers
|
|
- **THEN** the call returns `false` (does not throw)
|
|
|
|
**Verified by:**
|
|
`packages/crypto/crypto-curve/src/primitives/p384/p384.test.ts::"sign + verify round-trips"`
|
|
AND `…::"verify returns false for tampered signature (no throw)"`
|
|
AND `…::"verify returns false for bogus input (caught)"`
|
|
|
|
---
|
|
|
|
### Requirement: NIST P-521 (secp521r1) ECDSA primitive
|
|
|
|
The package SHALL export a `p521` namespace from the root barrel and a
|
|
matching `./p521` subpath export, providing `getPublicKey`, `sign`,
|
|
`verify`, and `randomPrivateKey`. Private keys SHALL be 66 bytes (521-bit
|
|
scalar left-padded to a byte boundary), compressed public keys SHALL be
|
|
67 bytes, and compact ECDSA signatures SHALL be 132 bytes. Callers SHALL
|
|
pre-hash messages; the module operates on digests. The selector SHALL
|
|
forward to the noble-backed implementation by default; the native
|
|
implementation SHALL throw `PrimitiveNotImplemented("p521")`.
|
|
|
|
#### Scenario: P-521 sign + verify round-trip
|
|
|
|
- **GIVEN** a freshly-generated P-521 private key and 64-byte digest
|
|
- **WHEN** `verify(sign(digest, sk), digest, getPublicKey(sk))` is computed
|
|
- **THEN** the result is `true` and the signature is 132 bytes long
|
|
|
|
#### Scenario: P-521 verify rejects tampered signature
|
|
|
|
- **WHEN** a single byte of a valid P-521 signature is XORed with `0xff`
|
|
- **THEN** `verify` returns `false`
|
|
|
|
#### Scenario: P-521 verify returns false on malformed inputs
|
|
|
|
- **WHEN** `verify` is invoked with non-`Uint8Array` inputs or empty
|
|
buffers
|
|
- **THEN** the call returns `false` (does not throw)
|
|
|
|
**Verified by:**
|
|
`packages/crypto/crypto-curve/src/primitives/p521/p521.test.ts::"sign + verify round-trips"`
|
|
AND `…::"verify returns false for tampered signature (no throw)"`
|
|
AND `…::"verify returns false for bogus input (caught)"`
|
|
|
|
---
|
|
|
|
### Requirement: Native stubs preserve layout
|
|
|
|
The package SHALL ship native-backend placeholder modules
|
|
(`primitives/p384/impl/p384.native/`,
|
|
`primitives/p521/impl/p521.native/`) whose every exported function throws
|
|
`PrimitiveNotImplemented(<curve>)`. The placeholders SHALL match the
|
|
existing `p256.native` pattern so the selector switch is mechanical when
|
|
a real native implementation lands.
|
|
|
|
#### Scenario: P-384 native stub throws on every operation
|
|
|
|
- **WHEN** any of `getPublicKey`, `sign`, `verify`, or `randomPrivateKey`
|
|
is invoked on the native module
|
|
- **THEN** the call throws `PrimitiveNotImplemented("p384")`
|
|
|
|
#### Scenario: P-521 native stub throws on every operation
|
|
|
|
- **WHEN** the same operations are invoked on the P-521 native module
|
|
- **THEN** the call throws `PrimitiveNotImplemented("p521")`
|
|
|
|
**Verified by:**
|
|
`…/p384/p384.test.ts::"every operation throws PrimitiveNotImplemented"`
|
|
AND `…/p521/p521.test.ts::"every operation throws PrimitiveNotImplemented"`
|
|
|
|
---
|
|
|
|
### Requirement: Subpath exports for P-384 and P-521
|
|
|
|
The package SHALL declare `./p384` and `./p521` entries in
|
|
`package.json` `exports` so consumers tree-shake to the individual
|
|
primitive. The `vite.config.ts` build entry list SHALL include both new
|
|
primitives so the generated `dist/` tree carries the expected `.d.ts` and
|
|
`.js` files at the published path.
|
|
|
|
#### Scenario: P-384 subpath resolves
|
|
|
|
- **WHEN** a consumer imports `@suaveplan/crypto-curve/p384`
|
|
- **THEN** the import resolves with no `Module not found` error and
|
|
exposes `getPublicKey`, `sign`, `verify`, `randomPrivateKey`
|
|
|
|
#### Scenario: P-521 subpath resolves
|
|
|
|
- **WHEN** a consumer imports `@suaveplan/crypto-curve/p521`
|
|
- **THEN** the import resolves with no `Module not found` error and
|
|
exposes the same four symbols
|
|
|
|
**Verified by:** TypeScript compile of consumers (e.g.
|
|
`packages/vault/cbor/src/cose/sign1.ts`) that import these subpaths.
|
|
|
|
<!-- markdownlint-enable MD024 -->
|