Gathering detailed insights and metrics for @polkadot/x-noble-secp256k1
Gathering detailed insights and metrics for @polkadot/x-noble-secp256k1
Gathering detailed insights and metrics for @polkadot/x-noble-secp256k1
Gathering detailed insights and metrics for @polkadot/x-noble-secp256k1
Utilities and base libraries for use across polkadot-js for Polkadot and Substrate. Includes base libraries, crypto helpers and cross-environment helpers.
npm install @polkadot/x-noble-secp256k1
Typescript
Module System
Min. Node Version
Node Version
NPM Version
TypeScript (99.73%)
JavaScript (0.16%)
HTML (0.11%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
Apache-2.0 License
257 Stars
3,596 Commits
151 Forks
9 Watchers
6 Branches
76 Contributors
Updated on Jul 10, 2025
Latest Version
8.1.2
Package Id
@polkadot/x-noble-secp256k1@8.1.2
Unpacked Size
101.05 kB
Size
30.23 kB
File Count
9
NPM Version
8.1.0
Node Version
16.13.0
Published on
Dec 05, 2021
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
1
Fastest JS implementation of secp256k1, an elliptic curve that could be used for asymmetric encryption, ECDH key agreement protocol and signature schemes. Supports deterministic ECDSA from RFC6979 and Schnorr signatures from BIP0340.
Audited with crowdfunding by an independent security firm. Tested against thousands of test vectors from a different library. Check out the online demo and blog post: Learning fast elliptic-curve cryptography in JS
noble-crypto — high-security, easily auditable set of contained cryptographic libraries and tools.
Use NPM in node.js / browser, or include single file from GitHub's releases page:
npm install @noble/secp256k1
1import * as secp from "@noble/secp256k1"; 2// if you're using single file, use global variable nobleSecp256k1 instead 3 4(async () => { 5 // You pass either a hex string, or Uint8Array 6 const privateKey = "6b911fd37cdf5c81d4c0adb1ab7fa822ed253ab0ad9aa18d77257c88b29b718e"; 7 const messageHash = "a33321f98e4ff1c283c76998f14f57447545d339b3db534c6d886decb4209f28"; 8 const publicKey = secp.getPublicKey(privateKey); 9 const signature = await secp.sign(messageHash, privateKey); 10 const isSigned = secp.verify(signature, messageHash, publicKey); 11 12 // Supports Schnorr signatures 13 const rpub = secp.schnorr.getPublicKey(privateKey); 14 const rsignature = await secp.schnorr.sign(messageHash, privateKey); 15 const risSigned = await secp.schnorr.verify(rsignature, messageHash, rpub); 16})();
Deno:
1import * as secp from "https://deno.land/x/secp256k1/mod.ts"; 2const publicKey = secp.getPublicKey("6b911fd37cdf5c81d4c0adb1ab7fa822ed253ab0ad9aa18d77257c88b29b718e");
getPublicKey(privateKey)
getSharedSecret(privateKeyA, publicKeyB)
sign(hash, privateKey)
verify(signature, hash, publicKey)
recoverPublicKey(hash, signature, recovery)
schnorr.getPublicKey(privateKey)
schnorr.sign(hash, privateKey)
schnorr.verify(signature, hash, publicKey)
getPublicKey(privateKey)
1function getPublicKey(privateKey: Uint8Array, isCompressed?: false): Uint8Array; 2function getPublicKey(privateKey: string, isCompressed?: false): string; 3function getPublicKey(privateKey: bigint): Uint8Array;
privateKey
will be used to generate public key.
Public key is generated by doing scalar multiplication of a base Point(x, y) by a fixed
integer. The result is another Point(x, y)
which we will by default encode to hex Uint8Array.
isCompressed
(default is false
) determines whether the output should contain y
coordinate of the point.
To get Point instance, use Point.fromPrivateKey(privateKey)
.
getSharedSecret(privateKeyA, publicKeyB)
1function getSharedSecret(privateKeyA: Uint8Array, publicKeyB: Uint8Array): Uint8Array; 2function getSharedSecret(privateKeyA: string, publicKeyB: string): string; 3function getSharedSecret(privateKeyA: bigint, publicKeyB: Point): Uint8Array;
Computes ECDH (Elliptic Curve Diffie-Hellman) shared secret between a private key and a different public key.
To get Point instance, use Point.fromHex(publicKeyB).multiply(privateKeyA)
.
To speed-up the function massively by precomputing EC multiplications,
use getSharedSecret(privateKeyA, secp.utils.precompute(8, publicKeyB))
sign(hash, privateKey)
1function sign(msgHash: Uint8Array, privateKey: Uint8Array, opts?: Options): Promise<Uint8Array>; 2function sign(msgHash: string, privateKey: string, opts?: Options): Promise<string>; 3function sign(msgHash: Uint8Array, privateKey: Uint8Array, opts?: Options): Promise<[Uint8Array | string, number]>;
Generates deterministic ECDSA signature as per RFC6979.
msgHash: Uint8Array | string
- message hash which would be signedprivateKey: Uint8Array | string | bigint
- private key which will sign the hashoptions?: Options
- optional object related to signature value and formatoptions?.recovered: boolean = false
- whether the recovered bit should be included in the result. In this case, the result would be an array of two items.options?.canonical: boolean = false
- whether a signature s
should be no more than 1/2 prime orderoptions?.der: boolean = true
- whether the returned signature should be in DER format. If false
, it would be in Compact format (32-byte r + 32-byte s)The function is asynchronous because we're utilizing built-in HMAC API to not rely on dependencies.
signSync
counterpart could also be used, you need to set utils.hmacSha256Sync
to a function with signature key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array
. Example with noble-hashes
package:
1const { hmac } = require('noble-hashes/lib/hmac'); 2const { sha256 } = require('noble-hashes/lib/sha256'); 3secp256k1.utils.hmacSha256Sync = (key: Uint8Array, ...msgs: Uint8Array[]) => { 4 const h = hmac.create(sha256, key); 5 msgs.forEach(msg => h.update(msg)); 6 return h.digest(); 7}; 8 9// Can be used now 10secp256k1.signSync(msgHash, privateKey)
verify(signature, hash, publicKey)
1function verify(signature: Uint8Array, msgHash: Uint8Array, publicKey: Uint8Array): boolean 2function verify(signature: string, msgHash: string, publicKey: string): boolean
signature: Uint8Array | string | { r: bigint, s: bigint }
- object returned by the sign
functionmsgHash: Uint8Array | string
- message hash that needs to be verifiedpublicKey: Uint8Array | string | Point
- e.g. that was generated from privateKey
by getPublicKey
boolean
: true
if signature == hash
; otherwise false
recoverPublicKey(hash, signature, recovery)
1function recoverPublicKey(msgHash: Uint8Array, signature: Uint8Array, recovery: number): Uint8Array | undefined; 2function recoverPublicKey(msgHash: string, signature: string, recovery: number): string | undefined;
msgHash: Uint8Array | string
- message hash which would be signedsignature: Uint8Array | string | { r: bigint, s: bigint }
- object returned by the sign
functionrecovery: number
- recovery bit returned by sign
with recovered
option
Public key is generated by doing scalar multiplication of a base Point(x, y) by a fixed
integer. The result is another Point(x, y)
which we will by default encode to hex Uint8Array.
If signature is invalid - function will return undefined
as result.To get Point instance, use Point.fromSignature(hash, signature, recovery)
.
schnorr.getPublicKey(privateKey)
1function schnorrGetPublicKey(privateKey: Uint8Array): Uint8Array; 2function schnorrGetPublicKey(privateKey: string): string;
Returns 32-byte public key. Warning: it is incompatible with non-schnorr pubkey.
Specifically, its y coordinate may be flipped. See BIP0340 for clarification.
schnorr.sign(hash, privateKey)
1function schnorrSign(msgHash: Uint8Array, privateKey: Uint8Array, auxilaryRandom?: Uint8Array): Promise<Uint8Array>; 2function schnorrSign(msgHash: string, privateKey: string, auxilaryRandom?: string): Promise<string>;
Generates Schnorr signature as per BIP0340. Asynchronous, so use await
.
msgHash: Uint8Array | string
- message hash which would be signedprivateKey: Uint8Array | string | bigint
- private key which will sign the hashauxilaryRandom?: Uint8Array
— optional 32 random bytes. By default, the method gathers cryptogarphically secure random.schnorr.verify(signature, hash, publicKey)
1function schnorrVerify(signature: Uint8Array | string, msgHash: Uint8Array | string, publicKey: Uint8Array | string): boolean
signature: Uint8Array | string | { r: bigint, s: bigint }
- object returned by the sign
functionmsgHash: Uint8Array | string
- message hash that needs to be verifiedpublicKey: Uint8Array | string | Point
- e.g. that was generated from privateKey
by getPublicKey
boolean
: true
if signature == hash
; otherwise false
utils.randomPrivateKey(): Uint8Array
Returns Uint8Array
of 32 cryptographically secure random bytes that can be used as private key. The signature is:
1(key: Uint8Array, ...msgs: Uint8Array[]): Uint8Array;
utils.hmacSha256Sync
The function is not defined by default, but could be used to implement signSync
method (see above).
utils.precompute(W = 8, point = BASE_POINT): Point
Returns cached point which you can use to pass to getSharedSecret
or to #multiply
by it.
This is done by default, no need to run it unless you want to disable precomputation or change window size.
We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT values.
This slows down first getPublicKey() by milliseconds (see Speed section), but allows to speed-up subsequent getPublicKey() calls up to 20x.
You may want to precompute values for your own point.
1secp256k1.CURVE.P // Field, 2 ** 256 - 2 ** 32 - 977 2secp256k1.CURVE.n // Order, 2 ** 256 - 432420386565659656852420866394968145599 3secp256k1.Point.BASE // new secp256k1.Point(Gx, Gy) where 4// Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240n 5// Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424n; 6 7// Elliptic curve point in Affine (x, y) coordinates. 8secp256k1.Point { 9 constructor(x: bigint, y: bigint); 10 // Supports compressed and non-compressed hex 11 static fromHex(hex: Uint8Array | string); 12 static fromPrivateKey(privateKey: Uint8Array | string | number | bigint); 13 static fromSignature( 14 msgHash: Hex, 15 signature: Signature, 16 recovery: number | bigint 17 ): Point | undefined { 18 toRawBytes(isCompressed = false): Uint8Array; 19 toHex(isCompressed = false): string; 20 equals(other: Point): boolean; 21 negate(): Point; 22 add(other: Point): Point; 23 subtract(other: Point): Point; 24 // Constant-time scalar multiplication. 25 multiply(scalar: bigint | Uint8Array): Point; 26} 27secp256k1.Signature { 28 constructor(r: bigint, s: bigint); 29 // DER encoded ECDSA signature 30 static fromDER(hex: Uint8Array | string); 31 // R, S 32-byte each 32 static fromCompact(hex: Uint8Array | string); 33 toDERRawBytes(): Uint8Array; 34 toDERHex(): string; 35 toCompactRawBytes(): Uint8Array; 36 toCompactHex(): string; 37}
Noble is production-ready.
We're using built-in JS BigInt
, which is "unsuitable for use in cryptography" as per official spec. This means that the lib is potentially vulnerable to timing attacks. But, JIT-compiler and Garbage Collector make "constant time" extremely hard to achieve in a scripting language. Which means any other JS library doesn't use constant-time bigints. Including bn.js or anything else. Even statically typed Rust, a language without GC, makes it harder to achieve constant-time for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages. Nonetheless we've hardened implementation of koblitz curve multiplication to be algorithmically constant time.
We however consider infrastructure attacks like rogue NPM modules very important; that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings. If your app uses 500 dependencies, any dep could get hacked and you'll be downloading rootkits with every npm install
. Our goal is to minimize this attack vector.
Benchmarks measured with Apple M1.
getPublicKey(utils.randomPrivateKey()) x 6,121 ops/sec @ 163μs/op
sign x 4,679 ops/sec @ 213μs/op
verify x 923 ops/sec @ 1ms/op
recoverPublicKey x 491 ops/sec @ 2ms/op
getSharedSecret aka ecdh x 534 ops/sec @ 1ms/op
getSharedSecret (precomputed) x 7,105 ops/sec @ 140μs/op
Point.fromHex (decompression) x 12,171 ops/sec @ 82μs/op
schnorr.sign x 409 ops/sec @ 2ms/op
schnorr.verify x 504 ops/sec @ 1ms/op
Compare to other libraries (openssl
uses native bindings, not JS):
elliptic#getPublicKey x 1,940 ops/sec
sjcl#getPublicKey x 211 ops/sec
elliptic#sign x 1,808 ops/sec
sjcl#sign x 199 ops/sec
openssl#sign x 4,243 ops/sec
ecdsa#sign x 116 ops/sec
bip-schnorr#sign x 60 ops/sec
elliptic#verify x 812 ops/sec
sjcl#verify x 166 ops/sec
openssl#verify x 4,452 ops/sec
ecdsa#verify x 80 ops/sec
bip-schnorr#verify x 56 ops/sec
elliptic#ecdh x 971 ops/sec
Check out a blog post about this library: Learning fast elliptic-curve cryptography in JS.
npm install
to install build dependencies like TypeScriptnpm run compile
to compile TypeScript codenpm run test
to run jest on test/index.ts
Special thanks to Roman Koblov, who have helped to improve scalar multiplication speed.
MIT (c) Paul Miller (https://paulmillr.com), see LICENSE file.
No vulnerabilities found.
Reason
24 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
dependency not pinned by hash detected -- score normalized to 6
Details
Reason
Found 15/30 approved changesets -- score normalized to 5
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
52 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-07-07
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More