{"id":13631025,"url":"https://github.com/paulmillr/noble-secp256k1","last_synced_at":"2025-05-14T18:02:39.131Z","repository":{"id":39042767,"uuid":"192992297","full_name":"paulmillr/noble-secp256k1","owner":"paulmillr","description":"Fastest 4KB JS implementation of secp256k1 signatures and ECDH","archived":false,"fork":false,"pushed_at":"2025-05-14T12:10:11.000Z","size":1739,"stargazers_count":807,"open_issues_count":1,"forks_count":119,"subscribers_count":15,"default_branch":"main","last_synced_at":"2025-05-14T13:34:43.651Z","etag":null,"topics":["bitcoin","cryptography","curve","ecc","ecdsa","elliptic","ethereum","noble","rfc6979","schnorr","secp256k1","signature"],"latest_commit_sha":null,"homepage":"https://paulmillr.com/noble","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paulmillr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/funding.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":"audit/2021-04-22-cure53-pentest-report.pdf","citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"paulmillr"}},"created_at":"2019-06-20T21:59:34.000Z","updated_at":"2025-05-14T12:10:15.000Z","dependencies_parsed_at":"2024-05-12T00:27:49.537Z","dependency_job_id":"a968089b-8e1d-45b5-8900-be104ad9acf6","html_url":"https://github.com/paulmillr/noble-secp256k1","commit_stats":{"total_commits":538,"total_committers":7,"mean_commits":76.85714285714286,"dds":"0.026022304832713727","last_synced_commit":"52e1f994ca74fe1a0f68813f16bc6e1d66bf0d4e"},"previous_names":[],"tags_count":71,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fnoble-secp256k1","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fnoble-secp256k1/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fnoble-secp256k1/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fnoble-secp256k1/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paulmillr","download_url":"https://codeload.github.com/paulmillr/noble-secp256k1/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254179904,"owners_count":22027884,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bitcoin","cryptography","curve","ecc","ecdsa","elliptic","ethereum","noble","rfc6979","schnorr","secp256k1","signature"],"created_at":"2024-08-01T22:02:07.578Z","updated_at":"2025-05-14T18:02:39.112Z","avatar_url":"https://github.com/paulmillr.png","language":"JavaScript","funding_links":["https://github.com/sponsors/paulmillr"],"categories":["JavaScript","JavaScript Libraries","TypeScript"],"sub_categories":[],"readme":"# noble-secp256k1\n\nFastest 4KB JS implementation of secp256k1 signatures \u0026 ECDH.\n\n- ✍️ [ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)\n  signatures compliant with [RFC6979](https://www.rfc-editor.org/rfc/rfc6979)\n- 🤝 Elliptic Curve Diffie-Hellman [ECDH](https://en.wikipedia.org/wiki/Elliptic-curve_Diffie–Hellman)\n- 🔒 Supports [hedged signatures](https://paulmillr.com/posts/deterministic-signatures/) guarding against fault attacks\n- 🪶 4KB gzipped, 530 lines of pure ESM, bundler-less code\n\nThe module is a sister project of [noble-curves](https://github.com/paulmillr/noble-curves),\nfocusing on smaller attack surface \u0026 better auditability.\nCurves are drop-in replacement and have more features:\nSchnorr, MSM, DER encoding, Endomorphism, custom point precomputes, prehashing, common.js.\n\nTo upgrade from v1 to v2, see [Upgrading](#upgrading).\n\n### This library belongs to _noble_ cryptography\n\n\u003e **noble-cryptography** — high-security, easily auditable set of contained cryptographic libraries and tools.\n\n- Zero or minimal dependencies\n- Highly readable TypeScript / JS code\n- PGP-signed releases and transparent NPM builds with provenance\n- Check out [homepage](https://paulmillr.com/noble/) \u0026 all libraries:\n  [ciphers](https://github.com/paulmillr/noble-ciphers),\n  [curves](https://github.com/paulmillr/noble-curves),\n  [hashes](https://github.com/paulmillr/noble-hashes),\n  [post-quantum](https://github.com/paulmillr/noble-post-quantum),\n  4kb [secp256k1](https://github.com/paulmillr/noble-secp256k1) /\n  [ed25519](https://github.com/paulmillr/noble-ed25519)\n\n## Usage\n\n\u003e `npm install @noble/secp256k1`\n\n\u003e `deno add jsr:@noble/secp256k1`\n\n\u003e `deno doc jsr:@noble/secp256k1` # command-line documentation\n\nWe support all major platforms and runtimes. For node.js \u003c= 18 and React Native, additional polyfills are needed: see below.\n\n```js\nimport * as secp from '@noble/secp256k1';\n(async () =\u003e {\n  // Uint8Arrays or hex strings are accepted:\n  // Uint8Array.from([0xde, 0xad, 0xbe, 0xef]) is equal to 'deadbeef'\n  const privKey = secp.utils.randomPrivateKey(); // Secure random private key\n  // sha256 of 'hello world'\n  const msgHash = 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9';\n  const pubKey = secp.getPublicKey(privKey);\n  const signature = await secp.signAsync(msgHash, privKey); // Sync methods below\n  const isValid = secp.verify(signature, msgHash, pubKey);\n\n  const alicesPub = secp.getPublicKey(secp.utils.randomPrivateKey());\n  const shared = secp.getSharedSecret(privKey, alicesPub); // Diffie-Hellman\n  const pub2 = signature.recoverPublicKey(msgHash); // Public key recovery\n})();\n```\n\n### Enabling synchronous methods\n\nOnly async methods are available by default, to keep the library dependency-free.\nTo enable sync methods:\n\n```ts\nimport { hmac } from '@noble/hashes/hmac';\nimport { sha256 } from '@noble/hashes/sha256';\nsecp.etc.hmacSha256Sync = (k, ...m) =\u003e hmac(sha256, k, secp.etc.concatBytes(...m));\n```\n\n### React Native: polyfill getRandomValues and sha512\n\n```ts\nimport 'react-native-get-random-values';\nimport { hmac } from '@noble/hashes/hmac';\nimport { sha256 } from '@noble/hashes/sha256';\nsecp.etc.hmacSha256Sync = (k, ...m) =\u003e hmac(sha256, k, secp.etc.concatBytes(...m));\nsecp.etc.hmacSha256Async = (k, ...m) =\u003e Promise.resolve(secp.etc.hmacSha256Sync(k, ...m));\n```\n\n### nodejs v18 and older: polyfill webcrypto\n\n```ts\nimport { webcrypto } from 'node:crypto';\n// @ts-ignore\nif (!globalThis.crypto) globalThis.crypto = webcrypto;\n```\n\n## API\n\nThere are 3 main methods:\n\n* `getPublicKey(privateKey)`\n* `sign(messageHash, privateKey)` and `signAsync(messageHash, privateKey)`\n* `verify(signature, messageHash, publicKey)`\n\nFunctions generally accept Uint8Array.\nThere are optional utilities which convert hex strings, utf8 strings or bigints to u8a.\n\n### getPublicKey\n\n```ts\nimport { getPublicKey, utils, ProjectivePoint } from '@noble/secp256k1';\nconst privKey = utils.randomPrivateKey();\nconst pubKey33b = getPublicKey(privKey);\n\n// Variants\nconst pubKey65b = getPublicKey(privKey, false);\nconst pubKeyPoint = ProjectivePoint.fromPrivateKey(privKey);\nconst samePoint = ProjectivePoint.fromHex(pubKeyPoint.toHex());\n```\n\nGenerates 33-byte compressed (default) or 65-byte public key from 32-byte private key.\n\n### sign\n\n```ts\nimport * as secp from '@noble/secp256k1';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { utf8ToBytes } from '@noble/hashes/utils';\nconst msg = 'noble cryptography';\nconst msgHash = sha256(utf8ToBytes(msg));\nconst priv = secp.utils.randomPrivateKey();\n\nconst sigA = secp.sign(msgHash, priv);\n\n// Variants\nconst sigB = await secp.signAsync(msgHash, priv);\nconst sigC = secp.sign(msgHash, priv, { extraEntropy: true }); // hedged sig\nconst sigC2 = secp.sign(msgHash, priv, { extraEntropy: Uint8Array.from([0xca, 0xfe]) });\nconst sigD = secp.sign(msgHash, priv, { lowS: false }); // malleable sig\n```\n\nGenerates low-s deterministic-k RFC6979 ECDSA signature. Requries hash of message,\nwhich means you'll need to do something like `sha256(message)` before signing.\n\n`extraEntropy: true` enables hedged signatures. They incorporate\nextra randomness into RFC6979 (described in section 3.6),\nto provide additional protection against fault attacks.\nCheck out blog post [Deterministic signatures are not your friends](https://paulmillr.com/posts/deterministic-signatures/).\nEven if their RNG is broken, they will fall back to determinism.\n\nDefault behavior `lowS: true` prohibits signatures which have (sig.s \u003e= CURVE.n/2n) and is compatible with BTC/ETH.\nSetting `lowS: false` allows to create malleable signatures, which is default openssl behavior.\nNon-malleable signatures can still be successfully verified in openssl.\n\n### verify\n\n```ts\nimport * as secp from '@noble/secp256k1';\nconst hex = secp.etc.hexToBytes;\nconst sig = hex(\n  'ddc633c5b48a1a6725c31201892715dda3058350f7b444e89d32c33c90d9c9e218d7eaf02c2254e88c3b33d755394b08bcc7efd13df02338510b750b64572983'\n);\nconst msgHash = hex('736403f76264eccc1b77ba58dc8fc690e76b2b1532ba82c736a60f3862082db3');\n// const priv = 'd60937c2a1ece169888d4c48717dfcc0e1a7af915505823148cca11859210e9c';\nconst pubKey = hex('020b6d70b68873ff8fd729adf5cf4bf45021b34236f991768249cba06b11136ec6');\n\n// verify\nconst isValid = secp.verify(sig, msgHash, pubKey);\nconst isValidLoose = secp.verify(sig, msgHash, pubKey, { lowS: false });\n```\n\nVerifies ECDSA signature.\nDefault behavior `lowS: true` prohibits malleable signatures which have (`sig.s \u003e= CURVE.n/2n`) and\nis compatible with BTC / ETH.\nSetting `lowS: false` allows to create signatures, which is default openssl behavior.\n\n### getSharedSecret\n\n```ts\nimport * as secp from '@noble/secp256k1';\nconst bobsPriv = secp.utils.randomPrivateKey();\nconst alicesPub = secp.getPublicKey(secp.utils.randomPrivateKey());\n\n// ECDH between Alice and Bob\nconst shared33b = secp.getSharedSecret(bobsPriv, alicesPub);\nconst shared65b = secp.getSharedSecret(bobsPriv, alicesPub, false);\nconst sharedPoint = secp.ProjectivePoint.fromHex(alicesPub).multiply(bobsPriv);\n```\n\nComputes ECDH (Elliptic Curve Diffie-Hellman) shared secret between\nkey A and different key B.\n\n### recoverPublicKey\n\n```ts\nimport * as secp from '@noble/secp256k1';\n\nimport { sha256 } from '@noble/hashes/sha256';\nimport { utf8ToBytes } from '@noble/hashes/utils';\nconst msg = 'noble cryptography';\nconst msgHash = sha256(utf8ToBytes(msg));\nconst priv = secp.utils.randomPrivateKey();\nconst pub1 = secp.getPubkicKey(priv);\nconst sig = secp.sign(msgHash, priv);\n\nconst pub2 = sig.recoverPublicKey(msgHash);\n```\n\nRecover public key from Signature instance with `recovery` bit set.\n\n### utils\n\nA bunch of useful **utilities** are also exposed:\n\n```typescript\ntype Bytes = Uint8Array;\nconst etc: {\n  hexToBytes: (hex: string) =\u003e Bytes;\n  bytesToHex: (b: Bytes) =\u003e string;\n  concatBytes: (...arrs: Bytes[]) =\u003e Bytes;\n  bytesToNumberBE: (b: Bytes) =\u003e bigint;\n  numberToBytesBE: (num: bigint) =\u003e Bytes;\n  mod: (a: bigint, b?: bigint) =\u003e bigint;\n  invert: (num: bigint, md?: bigint) =\u003e bigint;\n  hmacSha256Async: (key: Bytes, ...msgs: Bytes[]) =\u003e Promise\u003cBytes\u003e;\n  hmacSha256Sync: HmacFnSync;\n  hashToPrivateKey: (hash: Hex) =\u003e Bytes;\n  randomBytes: (len: number) =\u003e Bytes;\n};\nconst utils: {\n  normPrivateKeyToScalar: (p: PrivKey) =\u003e bigint;\n  randomPrivateKey: () =\u003e Bytes; // Uses CSPRNG https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues\n  isValidPrivateKey: (key: Hex) =\u003e boolean;\n  precompute(p: ProjectivePoint, windowSize?: number): ProjectivePoint;\n};\nclass ProjectivePoint {\n  constructor(px: bigint, py: bigint, pz: bigint);\n  static readonly BASE: ProjectivePoint;\n  static readonly ZERO: ProjectivePoint;\n  static fromAffine(point: AffinePoint): ProjectivePoint;\n  static fromHex(hex: Hex): ProjectivePoint;\n  static fromPrivateKey(n: PrivKey): ProjectivePoint;\n  get x(): bigint;\n  get y(): bigint;\n  add(other: ProjectivePoint): ProjectivePoint;\n  assertValidity(): void;\n  equals(other: ProjectivePoint): boolean;\n  multiply(n: bigint): ProjectivePoint;\n  negate(): ProjectivePoint;\n  subtract(other: ProjectivePoint): ProjectivePoint;\n  toAffine(): AffinePoint;\n  toHex(isCompressed?: boolean): string;\n  toRawBytes(isCompressed?: boolean): Bytes;\n}\nclass Signature {\n  constructor(r: bigint, s: bigint, recovery?: number | undefined);\n  static fromCompact(hex: Hex): Signature;\n  readonly r: bigint;\n  readonly s: bigint;\n  readonly recovery?: number | undefined;\n  ok(): Signature;\n  hasHighS(): boolean;\n  normalizeS(): Signature;\n  recoverPublicKey(msgh: Hex): Point;\n  toCompactRawBytes(): Bytes;\n  toCompactHex(): string;\n}\nCURVE; // curve prime; order; equation params, generator coordinates\n```\n\n## Security\n\nThe module is production-ready.\n\nWe cross-test against sister project [noble-curves](https://github.com/paulmillr/noble-curves), which was audited and provides improved security.\n\n- The current version has not been independently audited. It is a rewrite of v1, which has been audited by cure53 in Apr 2021:\n  [PDF](https://cure53.de/pentest-report_noble-lib.pdf) (funded by [Umbra.cash](https://umbra.cash) \u0026 community).\n- It's being fuzzed [in a separate repository](https://github.com/paulmillr/fuzzing)\n\n### Constant-timeness\n\nWe're targetting algorithmic constant time. _JIT-compiler_ and _Garbage Collector_ make \"constant time\"\nextremely hard to achieve [timing attack](https://en.wikipedia.org/wiki/Timing_attack) resistance\nin a scripting language. Which means _any other JS library can't have\nconstant-timeness_. Even statically typed Rust, a language without GC,\n[makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security)\nfor some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones.\nUse low-level libraries \u0026 languages.\n\n### Supply chain security\n\n- **Commits** are signed with PGP keys, to prevent forgery. Make sure to verify commit signatures\n- **Releases** are transparent and built on GitHub CI. Make sure to verify [provenance](https://docs.npmjs.com/generating-provenance-statements) logs\n  - Use GitHub CLI to verify single-file builds:\n    `gh attestation verify --owner paulmillr noble-secp256k1.js`\n- **Rare releasing** is followed to ensure less re-audit need for end-users\n- **Dependencies** are minimized and locked-down: any dependency could get hacked and users will be downloading malware with every install.\n  - We make sure to use as few dependencies as possible\n  - Automatic dep updates are prevented by locking-down version ranges; diffs are checked with `npm-diff`\n- **Dev Dependencies** are disabled for end-users; they are only used to develop / build the source code\n\nFor this package, there are 0 dependencies; and a few dev dependencies:\n\n- [noble-hashes](https://github.com/paulmillr/noble-hashes) provides cryptographic hashing functionality\n- micro-bmark, micro-should and jsbt are used for benchmarking / testing / build tooling and developed by the same author\n- prettier, fast-check and typescript are used for code quality / test generation / ts compilation. It's hard to audit their source code thoroughly and fully because of their size\n\n### Randomness\n\nWe're deferring to built-in\n[crypto.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues)\nwhich is considered cryptographically secure (CSPRNG).\n\nIn the past, browsers had bugs that made it weak: it may happen again.\nImplementing a userspace CSPRNG to get resilient to the weakness\nis even worse: there is no reliable userspace source of quality entropy.\n\n### Quantum computers\n\nCryptographically relevant quantum computer, if built, will allow to\nbreak elliptic curve cryptography (both ECDSA / EdDSA \u0026 ECDH) using Shor's algorithm.\n\nConsider switching to newer / hybrid algorithms, such as SPHINCS+. They are available in\n[noble-post-quantum](https://github.com/paulmillr/noble-post-quantum).\n\nNIST prohibits classical cryptography (RSA, DSA, ECDSA, ECDH) [after 2035](https://nvlpubs.nist.gov/nistpubs/ir/2024/NIST.IR.8547.ipd.pdf). Australian ASD prohibits it [after 2030](https://www.cyber.gov.au/resources-business-and-government/essential-cyber-security/ism/cyber-security-guidelines/guidelines-cryptography).\n\n## Speed\n\n    npm run bench\n\nBenchmarks measured with Apple M4. [noble-curves](https://github.com/paulmillr/noble-curves) enable faster performance.\n\n```\ngetPublicKey(utils.randomPrivateKey()) x 8,770 ops/sec @ 114μs/op\nsignAsync x 4,848 ops/sec @ 206μs/op\nsign x 7,261 ops/sec @ 137μs/op\nverify x 817 ops/sec @ 1ms/op\ngetSharedSecret x 688 ops/sec @ 1ms/op\nrecoverPublicKey x 839 ops/sec @ 1ms/op\nPoint.fromHex (decompression) x 12,937 ops/sec @ 77μs/op\n```\n\n## Upgrading\n\nnoble-secp256k1 v2 features improved security and smaller attack surface.\nThe goal of v2 is to provide minimum possible JS library which is safe and fast.\n\nThat means the library was reduced 4x, to just over 400 lines. In order to\nachieve the goal, **some features were moved** to\n[noble-curves](https://github.com/paulmillr/noble-curves), which is\neven safer and faster drop-in replacement library with same API.\nSwitch to curves if you intend to keep using these features:\n\n- DER encoding: toDERHex, toDERRawBytes, signing / verification of DER sigs\n- Schnorr signatures\n- Using `utils.precompute()` for non-base point\n- Support for environments which don't support bigint literals\n- Common.js support\n- Support for node.js 18 and older without [shim](#usage)\n\nOther changes for upgrading from @noble/secp256k1 1.7 to 2.0:\n\n- `getPublicKey`\n  - now produce 33-byte compressed signatures by default\n  - to use old behavior, which produced 65-byte uncompressed keys, set\n    argument `isCompressed` to `false`: `getPublicKey(priv, false)`\n- `sign`\n  - is now sync; use `signAsync` for async version\n  - now returns `Signature` instance with `{ r, s, recovery }` properties\n  - `canonical` option was renamed to `lowS`\n  - `recovered` option has been removed because recovery bit is always returned now\n  - `der` option has been removed. There are 2 options:\n    1. Use compact encoding: `fromCompact`, `toCompactRawBytes`, `toCompactHex`.\n       Compact encoding is simply a concatenation of 32-byte r and 32-byte s.\n    2. If you must use DER encoding, switch to noble-curves (see above).\n- `verify`\n  - `strict` option was renamed to `lowS`\n- `getSharedSecret`\n  - now produce 33-byte compressed signatures by default\n  - to use old behavior, which produced 65-byte uncompressed keys, set\n    argument `isCompressed` to `false`: `getSharedSecret(a, b, false)`\n- `recoverPublicKey(msg, sig, rec)` was changed to `sig.recoverPublicKey(msg)`\n- `number` type for private keys have been removed: use `bigint` instead\n- `Point` (2d xy) has been changed to `ProjectivePoint` (3d xyz)\n- `utils` were split into `utils` (same api as in noble-curves) and\n  `etc` (`hmacSha256Sync` and others)\n\n## Contributing \u0026 testing\n\n- `npm install \u0026\u0026 npm run build \u0026\u0026 npm test` will build the code and run tests.\n- `npm run bench` will run benchmarks, which may need their deps first (`npm run bench:install`)\n- `npm run loc` will count total output size, important to be less than 4KB\n\nCheck out [github.com/paulmillr/guidelines](https://github.com/paulmillr/guidelines)\nfor general coding practices and rules.\n\nSee [paulmillr.com/noble](https://paulmillr.com/noble/)\nfor useful resources, articles, documentation and demos\nrelated to the library.\n\n## License\n\nMIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulmillr%2Fnoble-secp256k1","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaulmillr%2Fnoble-secp256k1","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulmillr%2Fnoble-secp256k1/lists"}