# ecdsa-p384 _(no submodules)_ ## Purpose Provides ECDSA (Elliptic Curve Digital Signature Algorithm) operations using the NIST P-384 curve and SHA-384 hash, backed by `crypto.subtle`. P-384 offers 192 bits of security — stronger than P-256's 128 bits — and is required by many compliance frameworks (NIST SP 800-57, CNSA Suite 2.0, NSA Suite B). This module is intended for contexts where P-384 is mandated by policy or interoperability requirements. The public key format is the 97-byte uncompressed point representation (0x04 prefix followed by 48-byte X and Y coordinates). The private key is PKCS8 DER. Both formats are standard and directly importable by other Web Crypto implementations. ## Features - `generateKeypair()` — generates a P-384 ECDSA keypair using `crypto.subtle.generateKey` - `sign(privateKey, message)` — signs with ECDSA-P384 / SHA-384 - `verify(publicKey, signature, message)` — verifies an ECDSA-P384 signature - Public key: 97-byte uncompressed point (raw format) - Private key: PKCS8 DER bytes - Signature format: IEEE P1363 (R || S) as returned by `crypto.subtle` - `assertWebCryptoAvailable()` guard on every call - Typed `BrowserCryptoError` for all failure paths ## Usage: Basic Example ```ts import { ecdsaP384 } from "@suaveplan/crypto-browser/ecdsa-p384/ecdsa-p384"; const kp = await ecdsaP384.generateKeypair(); // kp.publicKey is 97 bytes (uncompressed P-384 point) // kp.privateKey is PKCS8 DER bytes const message = new TextEncoder().encode("document to sign"); const signature = await ecdsaP384.sign(kp.privateKey, message); const valid = await ecdsaP384.verify(kp.publicKey, signature, message); console.log(valid); // true ``` ## Usage: Advanced Example ```ts import { ecdsaP384 } from "@suaveplan/crypto-browser/ecdsa-p384/ecdsa-p384"; import { BrowserCryptoError } from "@suaveplan/crypto-browser/errors"; // Issue a signed certificate-like structure async function issueAttestation( issuerPrivateKey: Uint8Array, payload: Uint8Array ): Promise<{ signature: Uint8Array; algorithm: string }> { try { const signature = await ecdsaP384.sign(issuerPrivateKey, payload); return { signature, algorithm: "ECDSA-P384-SHA384" }; } catch (err) { if (err instanceof BrowserCryptoError) { throw new Error(`Signing failed: ${err.code}`); } throw err; } } // Verify the attestation with a stored public key async function verifyAttestation( publicKey: Uint8Array, payload: Uint8Array, signature: Uint8Array ): Promise { return ecdsaP384.verify(publicKey, signature, payload); } ``` ## API Reference ### `ecdsaP384.generateKeypair(): Promise<{ publicKey: Uint8Array; privateKey: Uint8Array }>` Generates a P-384 ECDSA keypair. **Returns:** `Promise<{ publicKey: Uint8Array; privateKey: Uint8Array }>` — 97-byte uncompressed public key and PKCS8 DER private key. **Throws:** `BrowserCryptoError` — `BROWSER_CRYPTO.KEY.GENERATION_FAILED` or `BROWSER_CRYPTO.NOT_AVAILABLE`. --- ### `ecdsaP384.sign(privateKey, message): Promise` Signs `message` using ECDSA-P384 with SHA-384. | Parameter | Type | Description | |-----------|------|-------------| | `privateKey` | `Uint8Array` | PKCS8 DER private key bytes | | `message` | `Uint8Array` | Bytes to sign | **Returns:** `Promise` — IEEE P1363 signature (96 bytes for P-384). **Throws:** `BrowserCryptoError` — `BROWSER_CRYPTO.OPERATION.FAILED` or `BROWSER_CRYPTO.NOT_AVAILABLE`. --- ### `ecdsaP384.verify(publicKey, signature, message): Promise` Verifies an ECDSA-P384 / SHA-384 signature. | Parameter | Type | Description | |-----------|------|-------------| | `publicKey` | `Uint8Array` | 97-byte uncompressed P-384 public key | | `signature` | `Uint8Array` | IEEE P1363 signature bytes | | `message` | `Uint8Array` | Original message bytes | **Returns:** `Promise` — `true` if signature is valid. **Throws:** `BrowserCryptoError` — `BROWSER_CRYPTO.OPERATION.FAILED` or `BROWSER_CRYPTO.NOT_AVAILABLE`. ## Implementation Notes SHA-384 is paired with P-384 because the security level of the hash should match that of the curve. Using SHA-256 with P-384 would create a mismatch: the 192-bit curve security would be limited to the 128-bit collision resistance of SHA-256. The signature output format from `crypto.subtle.sign` for ECDSA is IEEE P1363 (raw R || S concatenation), not DER/ASN.1. This differs from OpenSSL's default DER encoding. When interoperating with systems that expect DER signatures, a conversion layer is needed. P-384 key generation is typically 2–5× slower than P-256 due to the larger field size. For high-throughput signing workloads where P-256 security is sufficient, consider using `webCryptoEcdsaP256Engine` instead.