# secp256k1 _(no submodules)_ - [secp256k1.native](./impl/secp256k1.native/secp256k1.native.md) — _(no submodules)_- [secp256k1.noble](./impl/secp256k1.noble/secp256k1.noble.md) — _(no submodules)_ - [secp256k1.noble](./impl/secp256k1.noble/secp256k1.noble.md) — _(no submodules)_- [secp256k1.select](./secp256k1.select/secp256k1.select.md) — _(no submodules)_ - [secp256k1.select](./secp256k1.select/secp256k1.select.md) — _(no submodules)_- [secp256k1](./secp256k1.md) — _(no submodules)_- secp256k1.native — _(no sub… - [secp256k1.native](./impl/secp256k1.native/secp256k1.native.md) — _(no submodules)_- [secp256k1.noble](./impl/secp256k1.noble/secp256k1.noble.md) — _(no submodules)_- [secp256k1.noble](./impl/secp256k1.noble/secp256k1.noble.md) — _(no submodules)_- [secp256k1.select](./secp256k1.select/secp256k1.select.md) — _(no submodules)_- [secp256k1.select](./secp256k1.select/secp256k1.select.md) — _(no submodules)_- [secp256k1](./secp256k1.md) — _(no submodules)_- [secp256k1.native](./impl/secp256k1.native/secp256k1.native.md) — _(no submodules)_- [secp256k1.noble](./impl/secp256k1.noble/secp256k1.noble.md) — _(no submodules)_- [secp256k1.noble](./impl/secp256k1.noble/secp256k1.noble.md) — _(no submodules)_- [secp256k1.select](./secp256k1.select/secp256k1.select.md) — _(no submodules)_- [secp256k1.select](./secp256k1.select/secp256k1.select.md) — _(no submodules)_- [secp256k1](./secp256k1.md) — _(no submodules)_- secp256k1.native — _(no submodules)_- [secp256k1.noble](./impl/secp256k1.noble/secp256k1.noble.md) — _(no submodules)_- [secp256k1.noble](./impl/secp256k1.noble/secp256k1.noble.md) — _(no submodules)_- [secp256k1.select](./secp256k1.select/secp256k1.select.md) — _(no submodules)_- [secp256k1.select](./secp256k1.select/secp256k1.select.md) — _(no submodules)_- [secp256k1](./secp256k1.md) — _(no submodules)_- secp256k1.native — _(no su… - [secp256k1.native](./impl/secp256k1.native/secp256k1.native.md) — _(no submodules)_- [secp256k1.noble](./impl/secp256k1.noble/secp256k1.noble.md) — _(no submodules)_ - [secp256k1.noble](./impl/secp256k1.noble/secp256k1.noble.md) — _(no submodules)_- [secp256k1.select](./secp256k1.select/secp256k1.select.md) — _(no submodules)_ - [secp256k1.select](./secp256k1.select/secp256k1.select.md) — _(no submodules)_- [secp256k1](./secp256k1.md) — _(no submodules)_ ## Purpose `secp256k1.ts` is the stable public entry point for the secp256k1 elliptic-curve primitive in `@suaveplan/crypto-curve`. It re-exports everything from the generated selector file `secp256k1.select.ts`, which in turn forwards to either the Noble-backed or native implementation depending on `crypto.config.ts`. secp256k1 is the Koblitz curve used by Bitcoin, Ethereum, and many other blockchain protocols. It supports ECDSA signing and ECDH key agreement. Callers import from this file and remain insulated from implementation changes. ## Features - `getPublicKey(privateKey)` — derives the 33-byte compressed public key. - `sign(digest, privateKey)` — produces a compact 64-byte ECDSA signature (r ‖ s). Caller must pre-hash the message. - `verify(signature, digest, publicKey)` — returns `boolean`, never throws on malformed inputs. - `getSharedSecret(privateKey, peerPublicKey)` — computes ECDH shared secret. - `randomPrivateKey()` — generates a cryptographically valid 32-byte private key via rejection sampling. - `signWithRecovery(digest, privateKey)` — produces a 65-byte signature (`64-byte compact || 1-byte recovery`). Recovery byte is `0` or `1`. - `recoverPublicKey(signatureWithRecovery, digest)` — recovers the 33-byte compressed public key from a 65-byte signature-with-recovery and the original digest. Throws `CryptoCurveError(RECOVERY_BYTE_MISSING)` for 64-byte inputs and `CryptoCurveError(RECOVERY_BYTE_INVALID)` when the recovery byte is not `0` or `1`. - `verifyWithRecovery(signatureWithRecovery, digest, expectedPublicKey)` — recovers the public key and compares it to `expectedPublicKey` in constant time. Returns `false` on mismatch (does not throw); structural errors (`RECOVERY_BYTE_MISSING`, `RECOVERY_BYTE_INVALID`) still throw. ## Usage: Basic Example ```ts import * as secp256k1 from "@suaveplan/crypto-curve/secp256k1"; import { sha256 } from "@suaveplan/crypto-hash/hash"; const sk = secp256k1.randomPrivateKey(); const pk = secp256k1.getPublicKey(sk); const msg = new TextEncoder().encode("transaction data"); const digest = sha256(msg); const sig = secp256k1.sign(digest, sk); console.log(secp256k1.verify(sig, digest, pk)); // true ``` ## Usage: Advanced Example ```ts import * as secp256k1 from "@suaveplan/crypto-curve/secp256k1"; import { hkdf } from "@suaveplan/crypto-hash/kdf"; import { zeroize } from "@suaveplan/crypto-utils/zeroize"; // Ephemeral ECDH for a sealed message. function sealedEphemeralKey(recipientPk: Uint8Array): { ephemeralPk: Uint8Array; sharedKey: Uint8Array; } { const ephemeralSk = secp256k1.randomPrivateKey(); try { const ephemeralPk = secp256k1.getPublicKey(ephemeralSk); const rawSecret = secp256k1.getSharedSecret(ephemeralSk, recipientPk); const sharedKey = hkdf("SHA-256", rawSecret, { salt: new Uint8Array(32), info: new TextEncoder().encode("secp256k1-sealed"), length: 32, }); return { ephemeralPk, sharedKey }; } finally { zeroize(ephemeralSk); } } ``` ## API Reference All symbols are re-exported from `secp256k1.select.ts`. See the active implementation (`secp256k1.noble.ts` or `secp256k1.native.ts`) for full parameter documentation. - `getPublicKey(privateKey: Uint8Array): Uint8Array` - `sign(digest: Uint8Array, privateKey: Uint8Array): Uint8Array` - `verify(signature: Uint8Array, digest: Uint8Array, publicKey: Uint8Array): boolean` - `getSharedSecret(privateKey: Uint8Array, peerPublicKey: Uint8Array): Uint8Array` - `randomPrivateKey(): Uint8Array` - `signWithRecovery(digest: Uint8Array, privateKey: Uint8Array): Uint8Array` - `recoverPublicKey(signatureWithRecovery: Uint8Array, digest: Uint8Array): Uint8Array` - `verifyWithRecovery(signatureWithRecovery: Uint8Array, digest: Uint8Array, expectedPublicKey: Uint8Array): boolean` ### Signature-with-recovery layout The 65-byte form is `[r:32 | s:32 | recovery:1]` (big-endian). The recovery byte selects which of the two possible public keys derived from `(r, s, digest)` was the signer; valid values are `0` and `1`. Some libraries (for compressed-vs-uncompressed keys) emit `2` and `3` — those are explicitly rejected here because suaveplan always returns the compressed (33-byte) form, so the lift bit is implicit. ## Implementation Notes This file is a zero-overhead re-export barrel. Its only role is to provide a stable import path (`@suaveplan/crypto-curve/secp256k1`) that survives future backend changes. The selector file underneath is generated; this file is not. Do not add logic here — it belongs in the concrete implementation files.