7.8 KiB
secp256k1
(no submodules)
- secp256k1.native — (no submodules)- secp256k1.noble — (no submodules) - secp256k1.noble — (no submodules)- secp256k1.select — (no submodules) - secp256k1.select — (no submodules)- secp256k1 — (no submodules)- secp256k1.native — _(no sub…
- secp256k1.native — (no submodules)- secp256k1.noble — (no submodules)- secp256k1.noble — (no submodules)- secp256k1.select — (no submodules)- secp256k1.select — (no submodules)- secp256k1 — (no submodules)- secp256k1.native — (no submodules)- secp256k1.noble — (no submodules)- secp256k1.noble — (no submodules)- secp256k1.select — (no submodules)- secp256k1.select — (no submodules)- secp256k1 — (no submodules)- secp256k1.native — <!-- begi…
- secp256k1.native — (no submodules)- secp256k1.noble — (no submodules)- secp256k1.noble — (no submodules)- secp256k1.select — (no submodules)- secp256k1.select — (no submodules)- secp256k1 — (no submodules)- secp256k1.native — _(no su…
- secp256k1.native — (no submodules)- secp256k1.noble — (no submodules) - secp256k1.noble — (no submodules)- secp256k1.select — (no submodules) - secp256k1.select — (no submodules)- secp256k1 — (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)— returnsboolean, 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 is0or1.recoverPublicKey(signatureWithRecovery, digest)— recovers the 33-byte compressed public key from a 65-byte signature-with-recovery and the original digest. ThrowsCryptoCurveError(RECOVERY_BYTE_MISSING)for 64-byte inputs andCryptoCurveError(RECOVERY_BYTE_INVALID)when the recovery byte is not0or1.verifyWithRecovery(signatureWithRecovery, digest, expectedPublicKey)— recovers the public key and compares it toexpectedPublicKeyin constant time. Returnsfalseon mismatch (does not throw); structural errors (RECOVERY_BYTE_MISSING,RECOVERY_BYTE_INVALID) still throw.
Usage: Basic Example
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
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): Uint8Arraysign(digest: Uint8Array, privateKey: Uint8Array): Uint8Arrayverify(signature: Uint8Array, digest: Uint8Array, publicKey: Uint8Array): booleangetSharedSecret(privateKey: Uint8Array, peerPublicKey: Uint8Array): Uint8ArrayrandomPrivateKey(): Uint8ArraysignWithRecovery(digest: Uint8Array, privateKey: Uint8Array): Uint8ArrayrecoverPublicKey(signatureWithRecovery: Uint8Array, digest: Uint8Array): Uint8ArrayverifyWithRecovery(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.