Research
Security News
Threat Actor Exposes Playbook for Exploiting npm to Build Blockchain-Powered Botnets
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
noble-secp256k1
Advanced tools
Noble secp256k1. High-security, easily auditable, 0-dep, 1-file pubkey & ECDSA.
secp256k1, an elliptic curve that could be used for assymetric encryption, ECDH key agreement protocol and deterministic ECDSA signature scheme from RFC 6939.
Algorithmically resistant to timing attacks. Tested against thousands of vectors from tiny-secp256k1. Faster than indutny/elliptic, ecdsa.js and sjcl.
noble-crypto — high-security, easily auditable set of contained cryptographic libraries and tools.
npm install noble-secp256k1
import * as secp256k1 from "noble-secp256k1";
// You can also pass Uint8Array and BigInt.
const privateKey = "00000000000000000000000000000000000000a665a45920422f9d417e4867ef";
const messageHash = "9c1185a5c5e9fc54612808977ee8f548b2258d31";
const publicKey = secp256k1.getPublicKey(privateKey);
const signature = secp256k1.sign(messageHash, privateKey);
const isMessageSigned = secp256k1.verify(signature, messageHash, publicKey);
// Or:
// const privateKey = Uint8Array.from([
// 0xa6, 0x65, 0xa4, 0x59, 0x20, 0x42, 0x2f,
// 0x9d, 0x41, 0x7e, 0x48, 0x67, 0xef
// ]);
// const privateKey = 0xa665a45920422f9d417e4867efn;
getPublicKey(privateKey)
getSharedSecret(privateKeyA, publicKeyB)
sign(hash, privateKey)
verify(signature, hash, publicKey)
recoverPublicKey(hash, signature, recovery)
getPublicKey(privateKey)
function getPublicKey(privateKey: Uint8Array, isCompressed?: false): Uint8Array;
function getPublicKey(privateKey: string, isCompressed?: false): string;
function 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)
function getSharedSecret(privateKeyA: Uint8Array, publicKeyB: Uint8Array): Uint8Array;
function getSharedSecret(privateKeyA: string, publicKeyB: string): string;
function 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)
function sign(msgHash: Uint8Array, privateKey: Uint8Array, opts?: Options): Promise<Uint8Array>;
function sign(msgHash: string, privateKey: string, opts?: Options): Promise<string>;
function sign(msgHash: Uint8Array, privateKey: Uint8Array, opts?: Options): Promise<[Uint8Array | string, number]>;
Generates deterministic ECDSA signature as per RFC6979. Asynchronous, so use await
.
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
- determines 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
- determines whether a signature s
should be no more than 1/2 prime orderoptions.recovered == true
.verify(signature, hash, publicKey)
function verify(signature: Uint8Array, msgHash: Uint8Array, publicKey: Uint8Array): boolean
function 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)
export declare function recoverPublicKey(msgHash: string, signature: string, recovery: number): string | undefined;
export declare function recoverPublicKey(msgHash: Uint8Array, signature: Uint8Array, recovery: number): Uint8Array | 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)
.
utils.generateRandomPrivateKey(): Uint8Array
Returns Uint8Array
of 32 cryptographically secure random bytes. You can use it as private key.
utils.precompute(W = 4, 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.
The precomputation window is variable. For example, we increase W to 8 for tests, to speed-up tests 2x.
You may want to precompute values for your own point.
secp256k1.CURVE_PARAMS.P // 2 ** 256 - 2 ** 32 - 977
secp256k1.CURVE_PARAMS.n // 2 ** 256 - 432420386565659656852420866394968145599
secp256k1.Point.BASE_POINT // new secp256k1.Point(x, y) where
// x = 55066263022277343669578718895168534326250603453777594175500187360389116729240n
// y = 32670510020758816978083085130507043184471273380659243275938904335757337482424n;
// Elliptic curve point
secp256k1.Point {
constructor(x: bigint, y: bigint);
// Supports compressed and non-compressed hex
static fromHex(hex: Uint8Array | string);
static fromPrivateKey(privateKey: Uint8Array | string | number | bigint);
static fromSignature(
msgHash: Hex,
signature: Signature,
recovery: number | bigint
): Point | undefined {
toHex(): string;
add(other: Point): Point;
// Constant-time scalar multiplication.
multiply(scalar: bigint | Uint8Array): Point;
}
secp256k1.SignResult {
constructor(r: bigint, s: bigint);
// DER encoded ECDSA signature
static fromHex(hex: Uint8Array | string);
toHex(): string;
}
Measured with 2.9Ghz Coffee Lake. getPublicKey and signatures are faster than indutny/elliptic, ecdsa.js, sjcl.
getPublicKey x 2309 ops/sec @ 432μs/op
sign x 1815 ops/sec @ 550μs/op
verify x 235 ops/sec @ 4ms/op
recoverPublicKey x 123 ops/sec @ 8ms/op
getSharedSecret aka ecdh x 278 ops/sec @ 3ms/op
getSharedSecret (precomputed) x 2593 ops/sec @ 385μs/op
generateRandomPrivateKey x 339328 ops/sec @ 2μs/op
Custom window=16 (takes 11sec to initialize):
getPublicKey x 6010 ops/sec @ 166μs/op
sign x 3451 ops/sec @ 289μs/op
verify x 246 ops/sec @ 4ms/op
recoverPublicKey x 125 ops/sec @ 7ms/op
getSharedSecret aka ecdh x 273 ops/sec @ 3ms/op
getSharedSecret (precomputed) x 5066 ops/sec @ 197μs/op
generateRandomPrivateKey x 339328 ops/sec @ 2μs/op
Noble is production-ready & secure. Our goal is to have it audited by a good security expert.
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:
npm install
. Our goal is to minimize this attack vector.npm install
to install build dependencies like TypeScriptnpm run compile
to compile TypeScript codenpm run test
to run jest on test/index.ts
MIT (c) Paul Miller (https://paulmillr.com), see LICENSE file.
FAQs
Fastest JS implementation of secp256k1. Independently audited, high-security, 0-dependency ECDSA & Schnorr signatures
The npm package noble-secp256k1 receives a total of 1,110 weekly downloads. As such, noble-secp256k1 popularity was classified as popular.
We found that noble-secp256k1 demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
Security News
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
Security News
Research
A malicious npm package disguised as a WhatsApp client is exploiting authentication flows with a remote kill switch to exfiltrate data and destroy files.