{"id":15482,"library":"secp256k1-wasm","title":"WebAssembly Bindings for libsecp256k1","description":"secp256k1-wasm provides high-performance WebAssembly bindings for `libsecp256k1`, the highly optimized C library for secp256k1 elliptic curve cryptography. This package enables cryptographic operations such as key generation, signature signing, and verification directly within JavaScript environments like web browsers and Node.js, offering near-native performance without requiring platform-specific native add-ons. The current stable version is 2.0.0, released in November 2023. While an explicit release cadence is not defined, releases appear to be feature-driven and occur periodically. Its primary differentiator is its reliance on Emscripten to compile the robust `libsecp256k1` to WebAssembly, making it ideal for applications where cryptographic throughput is critical, such as blockchain wallets or transaction processing, by avoiding the overhead of pure JavaScript implementations.","status":"active","version":"2.0.0","language":"javascript","source_language":"en","source_url":"https://github.com/aspectron/secp256k1-wasm","tags":["javascript"],"install":[{"cmd":"npm install secp256k1-wasm","lang":"bash","label":"npm"},{"cmd":"yarn add secp256k1-wasm","lang":"bash","label":"yarn"},{"cmd":"pnpm add secp256k1-wasm","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The package's default export is a function that, when called, returns a Promise. This Promise resolves to an object containing the high-level secp256k1 API functions (e.g., `sign`, `verify`, `pubkeyCreate`) after the WASM module has loaded and initialized.","wrong":"import { sign } from 'secp256k1-wasm'; // Incorrect: default export is a Promise-returning factory","symbol":"initSecp256k1","correct":"import initSecp256k1 from 'secp256k1-wasm';"},{"note":"Always await the result of `initSecp256k1()` to get the fully initialized API object. The API provides methods like `sign`, `verify`, `pubkeyCreate`, `recover`, etc., which handle memory management internally.","wrong":"const secp256k1 = initSecp256k1(); // Missing await: 'secp256k1' will be a Promise, not the API object","symbol":"High-level API (resolved)","correct":"const secp256k1 = await initSecp256k1(); // 'secp256k1' now holds functions like .sign, .verify"},{"note":"In CommonJS environments, `require('secp256k1-wasm')` returns the same Promise-returning factory function as the ESM default import. It must also be awaited to access the API functions.","wrong":"const { sign } = require('secp256k1-wasm'); // Incorrect: cannot destructure directly from the initial promise-returning export","symbol":"CommonJS Import","correct":"const initSecp256k1 = require('secp256k1-wasm');"}],"quickstart":{"code":"import initSecp256k1 from 'secp256k1-wasm';\nimport { randomBytes } from 'crypto'; // Node.js built-in for secure randomness\n\nasync function runSecp256k1Example() {\n  console.log(\"Loading secp256k1 WASM module...\");\n  // Initialize the WASM module. This returns a Promise that resolves to the API object.\n  const secp256k1 = await initSecp256k1();\n  console.log(\"secp256k1 WASM module loaded successfully.\");\n\n  // 1. Generate a random 32-byte private key\n  const privateKey = randomBytes(32);\n  console.log(`\\nPrivate Key: ${privateKey.toString('hex')}`);\n\n  // 2. Create a public key from the private key\n  // 'false' means uncompressed public key (65 bytes)\n  const publicKey = secp256k1.pubkeyCreate(privateKey, false);\n  console.log(`Public Key (uncompressed): ${publicKey.toString('hex')}`);\n\n  // 3. Prepare a 32-byte message hash to sign\n  const messageHash = randomBytes(32);\n  console.log(`Message Hash: ${messageHash.toString('hex')}`);\n\n  // 4. Sign the message hash with the private key\n  const { signature, recid } = secp256k1.sign(messageHash, privateKey);\n  console.log(`Signature: ${signature.toString('hex')}`);\n  console.log(`Recovery ID (RecID): ${recid}`);\n\n  // 5. Verify the signature using the original message hash, signature, and public key\n  const isValid = secp256k1.verify(messageHash, signature, publicKey);\n  console.log(`Signature valid: ${isValid}`);\n\n  // 6. Recover the public key from the message hash, signature, and recovery ID\n  const recoveredPublicKey = secp256k1.recover(messageHash, signature, recid, false);\n  console.log(`Recovered Public Key: ${recoveredPublicKey.toString('hex')}`);\n  console.log(`Recovery matches original public key: ${publicKey.equals(recoveredPublicKey)}`);\n}\n\nrunSecp256k1Example().catch(console.error);\n","lang":"typescript","description":"This quickstart demonstrates how to asynchronously load the secp256k1 WASM module, generate a private/public key pair, sign a random message hash, and then verify and recover the public key from the signature. It showcases the high-level API functions exposed by the package."},"warnings":[{"fix":"Always use `await initSecp256k1();` (or `.then()`) to ensure the WASM module is fully loaded and initialized before calling any methods on the returned API object.","message":"The `secp256k1-wasm` module, like most WebAssembly modules, loads asynchronously. Developers must `await` the result of the default export function (`initSecp256k1()`) before attempting to access any cryptographic functions (e.g., `sign`, `verify`). Failure to do so will result in `TypeError: secp256k1.sign is not a function` or similar errors because the API object will not yet be available.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure all binary data passed to or received from `secp256k1-wasm` functions are `Uint8Array` instances. Use `Buffer.from()` or `new Uint8Array()` for conversions if your data is not already in this format.","message":"All cryptographic inputs and outputs for `secp256k1-wasm` functions (e.g., private keys, public keys, message hashes, signatures) are expected to be `Uint8Array` instances. Using other types like plain JavaScript `Array`s or `Buffer`s (without converting them to `Uint8Array` where necessary, though Node.js `Buffer`s are `Uint8Array` subclasses) can lead to unexpected behavior or errors.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Configure your bundler or environment to correctly handle and serve `.wasm` files. This often involves using file-loader or asset modules in Webpack, or ensuring the `.wasm` file is correctly copied to the output directory and served by the web server or application.","message":"When integrating `secp256k1-wasm` into bundlers like Webpack, Rollup, or specific environments like Electron or React Native, you might encounter issues with the WASM file not being correctly located or served. This is often due to the bundler's default asset handling not being configured for `.wasm` files, leading to 'Module not found' or 'Failed to load WebAssembly module' errors.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Adhere to best practices for cryptographic key management. When accepting public keys from untrusted sources, implement additional validation steps to confirm they lie on the secp256k1 curve and are not low-order points, if the high-level API does not guarantee this implicitly during `pubkeyParse` or similar operations.","message":"Proper public key validation is a critical security consideration in secp256k1 cryptography. While `libsecp256k1` itself is robust, misusing high-level APIs or introducing invalid curve points can lead to vulnerabilities like small subgroup attacks or invalid public key exploits. Always ensure that public keys are derived from valid private keys or are properly validated when received from external sources.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Ensure you `await` the result of `initSecp256k1()` to get the resolved API object before using its methods. Example: `const secp256k1 = await initSecp256k1();`","cause":"The WASM module was not fully loaded and initialized before attempting to call a cryptographic function. The initial `initSecp256k1()` call returns a Promise, not the API object itself.","error":"TypeError: secp256k1.sign is not a function"},{"fix":"Verify that the `.wasm` file is located at the expected path relative to your JavaScript entry point or that your build tools (e.g., Webpack, Rollup) are correctly bundling and serving the `.wasm` asset. Check network requests in browser developer tools for the exact path being attempted.","cause":"The browser or Node.js environment could not find or fetch the `.wasm` binary file, typically because of an incorrect path, server configuration, or bundling issue.","error":"Error: Failed to load WebAssembly module: NetworkError when attempting to fetch resource."},{"fix":"Ensure that WebAssembly compilation is handled asynchronously, which is typically the default behavior when using `WebAssembly.instantiateStreaming` or `WebAssembly.compileStreaming` (used by modern Emscripten glue code). If you are manually loading, use streaming compilation or `WebAssembly.instantiate(source, importObject)`. The `secp256k1-wasm` library handles this internally via its promise-based initialization.","cause":"This browser-specific error occurs when attempting to synchronously compile a large WebAssembly module (over 4KB) on the main thread, which can block the UI.","error":"WebAssembly.Compile is disallowed on the main thread, if the buffer size is larger than 4KB."},{"fix":"Convert your input data to a `Uint8Array` before passing it to the `secp256k1-wasm` function. For example, `const messageHash = new Uint8Array(myArray);` or `const messageHash = Buffer.from('hexstring', 'hex');` if starting from a hex string in Node.js, ensuring `Buffer` is compatible.","cause":"A function expected a `Uint8Array` but received another type, such as a plain JavaScript `Array`, `Buffer` (in older Node.js versions or specific contexts), or a string.","error":"Argument must be a Uint8Array"}],"ecosystem":"npm"}