Audited & minimal JS implementation of elliptic curve cryptography
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Native browser WebCrypto API wrappers providing hardware-accelerated elliptic curve operations. These wrappers offer the same API as the main curve implementations but use the browser's built-in cryptographic primitives for better performance and security.
Hardware-accelerated ECDSA signatures and ECDH key exchange for NIST P-curves.
import { p256, p384, p521 } from "@noble/curves/webcrypto";
// NIST P-256 (secp256r1)
const p256: WebCryptoNIST;
// NIST P-384 (secp384r1)
const p384: WebCryptoNIST;
// NIST P-521 (secp521r1)
const p521: WebCryptoNIST;
interface WebCryptoNIST extends WebCryptoBaseCurve, WebCryptoSigner, WebCryptoECDH {
name: string;
isAvailable(): Promise<boolean>;
getPublicKey(secretKey: Key, opts?: WebCryptoGetPubOpts): Promise<Key>;
sign(msgHash: Uint8Array, privateKey: Key, opts?: WebCryptoOpts): Promise<Uint8Array>;
verify(signature: Uint8Array, msgHash: Uint8Array, publicKey: Key, opts?: WebCryptoOpts): Promise<boolean>;
getSharedSecret(priv: Uint8Array, pub: Uint8Array, opts?: WebCryptoOpts): Promise<Uint8Array>;
utils: {
randomSecretKey: (format?: Format) => Promise<Key>;
convertSecretKey: (key: Key, inFormat?: Format, outFormat?: Format) => Promise<Key>;
convertPublicKey: (key: Key, inFormat?: Format, outFormat?: Format) => Promise<Key>;
};
}Usage Examples:
import { p256 } from "@noble/curves/webcrypto";
// Check if WebCrypto P-256 is available
const available = await p256.isAvailable();
if (available) {
// Generate random secret key
const secretKey = await p256.utils.randomSecretKey();
// Get public key from secret key
const publicKey = await p256.getPublicKey(secretKey);
// Sign message hash
const msgHash = new Uint8Array(32); // Your message hash
const signature = await p256.sign(msgHash, secretKey);
// Verify signature
const isValid = await p256.verify(signature, msgHash, publicKey);
// ECDH key exchange
const alicePriv = await p256.utils.randomSecretKey();
const bobPriv = await p256.utils.randomSecretKey();
const bobPub = await p256.getPublicKey(bobPriv);
const sharedSecret = await p256.getSharedSecret(alicePriv, bobPub);
}Hardware-accelerated EdDSA signatures for Edwards curves.
import { ed25519, ed448 } from "@noble/curves/webcrypto";
// Ed25519 with WebCrypto
const ed25519: WebCryptoEdDSA;
// Ed448 with WebCrypto
const ed448: WebCryptoEdDSA;
interface WebCryptoEdDSA extends WebCryptoBaseCurve, WebCryptoSigner {
name: string;
isAvailable(): Promise<boolean>;
getPublicKey(secretKey: Key, opts?: WebCryptoGetPubOpts): Promise<Key>;
sign(msgHash: Uint8Array, privateKey: Key, opts?: WebCryptoOpts): Promise<Uint8Array>;
verify(signature: Uint8Array, msgHash: Uint8Array, publicKey: Key, opts?: WebCryptoOpts): Promise<boolean>;
utils: {
randomSecretKey: (format?: Format) => Promise<Key>;
convertSecretKey: (key: Key, inFormat?: Format, outFormat?: Format) => Promise<Key>;
convertPublicKey: (key: Key, inFormat?: Format, outFormat?: Format) => Promise<Key>;
};
}Hardware-accelerated ECDH key exchange for Montgomery curves.
import { x25519, x448 } from "@noble/curves/webcrypto";
// X25519 with WebCrypto
const x25519: WebCryptoMontgomery;
// X448 with WebCrypto
const x448: WebCryptoMontgomery;
interface WebCryptoMontgomery extends WebCryptoBaseCurve, WebCryptoECDH {
name: string;
isAvailable(): Promise<boolean>;
getPublicKey(secretKey: Key, opts?: WebCryptoGetPubOpts): Promise<Key>;
getSharedSecret(priv: Uint8Array, pub: Uint8Array, opts?: WebCryptoOpts): Promise<Uint8Array>;
utils: {
randomSecretKey: (format?: Format) => Promise<Key>;
convertSecretKey: (key: Key, inFormat?: Format, outFormat?: Format) => Promise<Key>;
convertPublicKey: (key: Key, inFormat?: Format, outFormat?: Format) => Promise<Key>;
};
}Usage Examples:
import { x25519 } from "@noble/curves/webcrypto";
// Check availability
if (await x25519.isAvailable()) {
// Generate key pair
const alicePriv = await x25519.utils.randomSecretKey();
const alicePub = await x25519.getPublicKey(alicePriv);
const bobPriv = await x25519.utils.randomSecretKey();
const bobPub = await x25519.getPublicKey(bobPriv);
// Compute shared secret
const sharedSecret = await x25519.getSharedSecret(alicePriv, bobPub);
}Utility function to check if a curve is supported by the WebCrypto implementation.
import { supportsWc } from "@noble/curves/webcrypto";
/**
* Check if WebCrypto curve is available
* @param curve - WebCrypto curve instance to test
* @returns Promise resolving to availability status
*/
function supportsWc(curve: WebCryptoBaseCurve): Promise<boolean>;Usage Example:
import { p256, ed25519, x25519, supportsWc } from "@noble/curves/webcrypto";
// Check multiple curve availability
const p256Available = await supportsWc(p256);
const ed25519Available = await supportsWc(ed25519);
const x25519Available = await supportsWc(x25519);
console.log(`P-256: ${p256Available}`);
console.log(`Ed25519: ${ed25519Available}`);
console.log(`X25519: ${x25519Available}`);// Key formats supported by WebCrypto
type Format = 'raw' | 'jwk' | 'spki' | 'pkcs8';
// Key input type - either JWK object or raw bytes
type Key = JsonWebKey | Uint8Array;
// JSON Web Key structure
type JsonWebKey = {
crv?: string;
d?: string;
kty?: string;
x?: string;
y?: string;
[key: string]: unknown;
};
// WebCrypto operation options
interface WebCryptoOpts {
format?: Format;
}
// Public key generation options
interface WebCryptoGetPubOpts {
secFormat?: Format;
pubFormat?: Format;
}
// Base curve interface
interface WebCryptoBaseCurve {
name: string;
isAvailable(): Promise<boolean>;
getPublicKey(secretKey: Key, opts?: WebCryptoGetPubOpts): Promise<Key>;
utils: {
randomSecretKey: (format?: Format) => Promise<Key>;
convertSecretKey: (key: Key, inFormat?: Format, outFormat?: Format) => Promise<Key>;
convertPublicKey: (key: Key, inFormat?: Format, outFormat?: Format) => Promise<Key>;
};
}
// Signature operations
interface WebCryptoSigner {
sign(msgHash: Uint8Array, privateKey: Key, opts?: WebCryptoOpts): Promise<Uint8Array>;
verify(signature: Uint8Array, msgHash: Uint8Array, publicKey: Key, opts?: WebCryptoOpts): Promise<boolean>;
}
// ECDH operations
interface WebCryptoECDH {
getSharedSecret(priv: Uint8Array, pub: Uint8Array, opts?: WebCryptoOpts): Promise<Uint8Array>;
}Raw Format Issues:
Point Encoding Differences:
getSharedSecret returns different output lengths:
Always check availability before using WebCrypto curves:
import { p256, ed25519 } from "@noble/curves/webcrypto";
const curves = [
{ name: 'P-256', curve: p256 },
{ name: 'Ed25519', curve: ed25519 }
];
for (const { name, curve } of curves) {
const available = await curve.isAvailable();
console.log(`${name}: ${available ? 'supported' : 'not supported'}`);
}WebCrypto implementations offer several advantages:
Use WebCrypto wrappers when: