Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@noble/secp256k1

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@noble/secp256k1 - npm Package Compare versions

Comparing version 2.0.0 to 2.1.0

16

index.d.ts

@@ -43,2 +43,5 @@ declare const CURVE: {

declare function getPublicKey(privKey: PrivKey, isCompressed?: boolean): Uint8Array;
type SignatureWithRecovery = Signature & {
recovery: number;
};
declare class Signature {

@@ -51,4 +54,5 @@ readonly r: bigint;

assertValidity(): this;
addRecoveryBit(rec: number): Signature;
addRecoveryBit(rec: number): SignatureWithRecovery;
hasHighS(): boolean;
normalizeS(): Signature;
recoverPublicKey(msgh: Hex): Point;

@@ -59,10 +63,10 @@ toCompactRawBytes(): Uint8Array;

type HmacFnSync = undefined | ((key: Bytes, ...msgs: Bytes[]) => Bytes);
declare function signAsync(msgh: Hex, priv: Hex, opts?: {
declare function signAsync(msgh: Hex, priv: PrivKey, opts?: {
lowS?: boolean | undefined;
extraEntropy?: boolean | Hex | undefined;
}): Promise<Signature>;
declare function sign(msgh: Hex, priv: Hex, opts?: {
}): Promise<SignatureWithRecovery>;
declare function sign(msgh: Hex, priv: PrivKey, opts?: {
lowS?: boolean | undefined;
extraEntropy?: boolean | Hex | undefined;
}): Signature;
}): SignatureWithRecovery;
type SigLike = {

@@ -88,3 +92,3 @@ r: bigint;

hashToPrivateKey: typeof hashToPrivateKey;
randomBytes: (len: number) => Bytes;
randomBytes: (len?: number) => Bytes;
};

@@ -91,0 +95,0 @@ declare const utils: {

@@ -9,3 +9,3 @@ /*! noble-secp256k1 - MIT License (c) 2019 Paul Miller (paulmillr.com) */

const fLen = 32; // field / group byte length
const crv = (x) => mod(mod(x * x) * x + CURVE.b); // x³ + ax + b weierstrass formula; no a
const crv = (x) => mod(mod(x * x) * x + CURVE.b); // x³ + ax + b weierstrass formula; a=0
const err = (m = '') => { throw new Error(m); }; // error helper, messes-up stack trace

@@ -16,10 +16,11 @@ const big = (n) => typeof n === 'bigint'; // is big integer

const ge = (n) => big(n) && 0n < n && n < N; // is group element
const au8 = (a, l) => // is Uint8Array (of specific length)
!(a instanceof Uint8Array) || (typeof l === 'number' && l > 0 && a.length !== l) ?
const isu8 = (a) => (a instanceof Uint8Array ||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array'));
const au8 = (a, l) => // assert is Uint8Array (of specific length)
!isu8(a) || (typeof l === 'number' && l > 0 && a.length !== l) ?
err('Uint8Array expected') : a;
const u8n = (data) => new Uint8Array(data); // creates Uint8Array
const toU8 = (a, len) => au8(str(a) ? h2b(a) : u8n(a), len); // norm(hex/u8a) to u8a
const toU8 = (a, len) => au8(str(a) ? h2b(a) : u8n(au8(a)), len); // norm(hex/u8a) to u8a
const mod = (a, b = P) => { let r = a % b; return r >= 0n ? r : b + r; }; // mod division
const isPoint = (p) => (p instanceof Point ? p : err('Point expected')); // is 3d point
let Gpows = undefined; // precomputes for base point G
class Point {

@@ -31,3 +32,5 @@ constructor(px, py, pz) {

} //3d=less inversions
static fromAffine(p) { return new Point(p.x, p.y, 1n); }
static fromAffine(p) {
return ((p.x === 0n) && (p.y === 0n)) ? Point.ZERO : new Point(p.x, p.y, 1n);
}
static fromHex(hex) {

@@ -216,5 +219,5 @@ hex = toU8(hex); // convert hex string to Uint8Array

const moreThanHalfN = (n) => n > (N >> 1n); // if a number is bigger than CURVE.n/2
function getPublicKey(privKey, isCompressed = true) {
const getPublicKey = (privKey, isCompressed = true) => {
return Point.fromPrivateKey(privKey).toRawBytes(isCompressed); // 33b or 65b output
}
};
class Signature {

@@ -232,4 +235,9 @@ constructor(r, s, recovery) {

assertValidity() { return ge(this.r) && ge(this.s) ? this : err(); } // 0 < r or s < CURVE.n
addRecoveryBit(rec) { return new Signature(this.r, this.s, rec); }
addRecoveryBit(rec) {
return new Signature(this.r, this.s, rec);
}
hasHighS() { return moreThanHalfN(this.s); }
normalizeS() {
return this.hasHighS() ? new Signature(this.r, mod(this.s, N), this.recovery) : this;
}
recoverPublicKey(msgh) {

@@ -239,3 +247,3 @@ const { r, s, recovery: rec } = this; // secg.org/sec1-v2.pdf 4.1.6

err('recovery id invalid'); // check recovery id
const h = bits2int_modN(toU8(msgh, 32)); // Truncate hash
const h = bits2int_modN(toU8(msgh, fLen)); // Truncate hash
const radj = rec === 2 || rec === 3 ? r + N : r; // If rec was 2 or 3, q.x is bigger than n

@@ -268,3 +276,3 @@ if (radj >= P)

const optV = { lowS: true }; // standard opts for verify()
function prepSig(msgh, priv, opts = optS) {
const prepSig = (msgh, priv, opts = optS) => {
if (['der', 'recovered', 'canonical'].some(k => k in opts)) // Ban legacy options

@@ -310,3 +318,3 @@ err('sign() legacy options not supported');

return { seed: concatB(...seed), k2sig };
}
};
function hmacDrbg(asynchronous) {

@@ -377,11 +385,11 @@ let v = u8n(fLen); // Minimal non-full-spec HMAC-DRBG from NIST 800-90 for RFC6979 sigs.

// ECDSA signature generation. via secg.org/sec1-v2.pdf 4.1.2 + RFC6979 deterministic k
async function signAsync(msgh, priv, opts = optS) {
const signAsync = async (msgh, priv, opts = optS) => {
const { seed, k2sig } = prepSig(msgh, priv, opts); // Extract arguments for hmac-drbg
return hmacDrbg(true)(seed, k2sig); // Re-run hmac-drbg until k2sig returns ok
}
function sign(msgh, priv, opts = optS) {
return hmacDrbg(true)(seed, k2sig); // Re-run drbg until k2sig returns ok
};
const sign = (msgh, priv, opts = optS) => {
const { seed, k2sig } = prepSig(msgh, priv, opts); // Extract arguments for hmac-drbg
return hmacDrbg(false)(seed, k2sig); // Re-run hmac-drbg until k2sig returns ok
}
function verify(sig, msgh, pub, opts = optV) {
return hmacDrbg(false)(seed, k2sig); // Re-run drbg until k2sig returns ok
};
const verify = (sig, msgh, pub, opts = optV) => {
let { lowS } = opts; // ECDSA signature verification

@@ -398,3 +406,3 @@ if (lowS == null)

sig_ = rs ? new Signature(sig.r, sig.s).assertValidity() : Signature.fromCompact(sig);
h = bits2int_modN(toU8(msgh, fLen)); // Truncate hash
h = bits2int_modN(toU8(msgh)); // Truncate hash
P = pub instanceof Point ? pub.ok() : Point.fromHex(pub); // Validate public key

@@ -422,9 +430,9 @@ }

return false; // stop if R is identity / zero point
const v = mod(R.x, N); // <== The weird ECDSA part. R.x must be in N's field, not P's
const v = mod(R.x, N); // R.x must be in N's field, not P's
return v === r; // mod(R.x, n) == r
}
function getSharedSecret(privA, pubB, isCompressed = true) {
};
const getSharedSecret = (privA, pubB, isCompressed = true) => {
return Point.fromHex(pubB).mul(toPriv(privA)).toRawBytes(isCompressed); // ECDH
}
function hashToPrivateKey(hash) {
};
const hashToPrivateKey = (hash) => {
hash = toU8(hash); // produces private keys with modulo bias

@@ -436,22 +444,20 @@ const minLen = fLen + 8; // being neglible.

return n2b(num);
}
};
const etc = {
hexToBytes: h2b, bytesToHex: b2h,
hexToBytes: h2b, bytesToHex: b2h, // share API with noble-curves.
concatBytes: concatB, bytesToNumberBE: b2n, numberToBytesBE: n2b,
mod, invert: inv,
mod, invert: inv, // math utilities
hmacSha256Async: async (key, ...msgs) => {
const crypto = cr(); // HMAC-SHA256 async. No sync built-in!
if (!crypto)
return err('etc.hmacSha256Async not set'); // Uses webcrypto: native cryptography.
const s = crypto.subtle;
const c = cr(); // async HMAC-SHA256, no sync built-in!
const s = c && c.subtle; // For React Native support, see README.
if (!s)
return err('etc.hmacSha256Async not set'); // Uses webcrypto built-in cryptography.
const k = await s.importKey('raw', key, { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign']);
return u8n(await s.sign('HMAC', k, concatB(...msgs)));
},
hmacSha256Sync: _hmacSync,
hmacSha256Sync: _hmacSync, // For TypeScript. Actual logic is below
hashToPrivateKey,
randomBytes: (len) => {
const crypto = cr(); // Can be shimmed in node.js <= 18 to prevent error:
// import { webcrypto } from 'node:crypto';
// if (!globalThis.crypto) globalThis.crypto = webcrypto;
if (!crypto)
randomBytes: (len = 32) => {
const crypto = cr(); // Must be shimmed in node.js <= 18 to prevent error. See README.
if (!crypto || !crypto.getRandomValues)
err('crypto.getRandomValues must be defined');

@@ -469,4 +475,4 @@ return crypto.getRandomValues(u8n(len));

} },
randomPrivateKey: () => hashToPrivateKey(etc.randomBytes(fLen + 8)),
precompute(w = 8, p = G) { p.multiply(3n); return p; }, // no-op
randomPrivateKey: () => hashToPrivateKey(etc.randomBytes(fLen + 16)), // FIPS 186 B.4.1.
precompute(w = 8, p = G) { p.multiply(3n); w; return p; }, // no-op
};

@@ -493,2 +499,3 @@ Object.defineProperties(etc, { hmacSha256Sync: {

};
let Gpows = undefined; // precomputes for base point G
const wNAF = (n) => {

@@ -495,0 +502,0 @@ // Compared to other point mult methods,

@@ -7,6 +7,6 @@ /*! noble-secp256k1 - MIT License (c) 2019 Paul Miller (paulmillr.com) */

const Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8n; // base point y
const CURVE = {p: P, n: N, a: 0n, b: 7n, Gx, Gy};// exported variables incl. a, b
const CURVE = {p: P, n: N, a: 0n, b: 7n, Gx, Gy}; // exported variables incl. a, b
const fLen = 32; // field / group byte length
type Bytes = Uint8Array; type Hex = Bytes | string; type PrivKey = Hex | bigint;
const crv = (x: bigint) => mod(mod(x * x) * x + CURVE.b); // x³ + ax + b weierstrass formula; no a
const crv = (x: bigint) => mod(mod(x * x) * x + CURVE.b); // x³ + ax + b weierstrass formula; a=0
const err = (m = ''): never => { throw new Error(m); }; // error helper, messes-up stack trace

@@ -17,10 +17,13 @@ const big = (n: unknown): n is bigint => typeof n === 'bigint'; // is big integer

const ge = (n: bigint) => big(n) && 0n < n && n < N; // is group element
const au8 = (a: unknown, l?: number): Bytes => // is Uint8Array (of specific length)
!(a instanceof Uint8Array) || (typeof l === 'number' && l > 0 && a.length !== l) ?
const isu8 = (a: unknown): a is Uint8Array => (
a instanceof Uint8Array ||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array')
);
const au8 = (a: unknown, l?: number): Bytes => // assert is Uint8Array (of specific length)
!isu8(a) || (typeof l === 'number' && l > 0 && a.length !== l) ?
err('Uint8Array expected') : a;
const u8n = (data?: any) => new Uint8Array(data); // creates Uint8Array
const toU8 = (a: Hex, len?: number) => au8(str(a) ? h2b(a) : u8n(a), len); // norm(hex/u8a) to u8a
const toU8 = (a: Hex, len?: number) => au8(str(a) ? h2b(a) : u8n(au8(a)), len); // norm(hex/u8a) to u8a
const mod = (a: bigint, b = P) => { let r = a % b; return r >= 0n ? r : b + r; }; // mod division
const isPoint = (p: unknown) => (p instanceof Point ? p : err('Point expected')); // is 3d point
let Gpows: Point[] | undefined = undefined; // precomputes for base point G
interface AffinePoint { x: bigint, y: bigint } // Point in 2d xy affine coordinates

@@ -31,3 +34,5 @@ class Point { // Point in 3d xyz projective coordinates

static readonly ZERO = new Point(0n, 1n, 0n); // Identity / zero point
static fromAffine(p: AffinePoint) { return new Point(p.x, p.y, 1n); }
static fromAffine (p: AffinePoint) { // (0, 0) => (0, 1, 0), not (0, 0, 1)
return ((p.x === 0n) && (p.y === 0n)) ? Point.ZERO : new Point(p.x, p.y, 1n);
}
static fromHex(hex: Hex): Point { // Convert Uint8Array or hex string to Point

@@ -65,3 +70,3 @@ hex = toU8(hex); // convert hex string to Uint8Array

const { a, b } = CURVE; // Cost: 12M + 0S + 3*a + 3*b3 + 23add
let X3 = 0n, Y3 = 0n, Z3 = 0n;
let X3 = 0n, Y3 = 0n, Z3 = 0n;
const b3 = mod(b * 3n);

@@ -86,3 +91,3 @@ let t0 = mod(X1 * X2), t1 = mod(Y1 * Y2), t2 = mod(Z1 * Z2), t3 = mod(X1 + Y1); // step 1

}
mul(n: bigint, safe = true) { // Point scalar multiplication.
mul(n: bigint, safe = true) { // Point scalar multiplication.
if (!safe && n === 0n) return I; // in unsafe mode, allow zero

@@ -145,3 +150,3 @@ if (!ge(n)) err('invalid scalar'); // must be 0 < n < CURVE.n

const slcNum = (b: Bytes, from: number, to: number) => b2n(b.slice(from, to)); // slice bytes num
const n2b = (num: bigint): Bytes => { // number to 32bytes. mustbe 0 <= num < B256
const n2b = (num: bigint): Bytes => { // number to 32b. Must be 0 <= num < B256
return big(num) && num >= 0n && num < B256 ? h2b(padh(num, 2 * fLen)) : err('bigint expected');

@@ -178,7 +183,8 @@ };

};
const moreThanHalfN = (n: bigint): boolean => n > (N >> 1n) // if a number is bigger than CURVE.n/2
function getPublicKey(privKey: PrivKey, isCompressed = true) { // Make public key from priv
const moreThanHalfN = (n: bigint): boolean => n > (N >> 1n); // if a number is bigger than CURVE.n/2
const getPublicKey = (privKey: PrivKey, isCompressed = true) => { // Make public key from priv
return Point.fromPrivateKey(privKey).toRawBytes(isCompressed); // 33b or 65b output
}
class Signature { // ECDSA Signature class
type SignatureWithRecovery = Signature & { recovery: number }
class Signature { // ECDSA Signature class
constructor(readonly r: bigint, readonly s: bigint, readonly recovery?: number) {

@@ -192,8 +198,13 @@ this.assertValidity(); // recovery bit is optional when

assertValidity() { return ge(this.r) && ge(this.s) ? this : err(); } // 0 < r or s < CURVE.n
addRecoveryBit(rec: number) { return new Signature(this.r, this.s, rec); }
addRecoveryBit(rec: number): SignatureWithRecovery {
return new Signature(this.r, this.s, rec) as SignatureWithRecovery;
}
hasHighS() { return moreThanHalfN(this.s); }
normalizeS() {
return this.hasHighS() ? new Signature(this.r, mod(this.s, N), this.recovery) : this
}
recoverPublicKey(msgh: Hex): Point { // ECDSA public key recovery
const { r, s, recovery: rec } = this; // secg.org/sec1-v2.pdf 4.1.6
if (![0, 1, 2, 3].includes(rec!)) err('recovery id invalid'); // check recovery id
const h = bits2int_modN(toU8(msgh, 32)); // Truncate hash
const h = bits2int_modN(toU8(msgh, fLen)); // Truncate hash
const radj = rec === 2 || rec === 3 ? r + N : r; // If rec was 2 or 3, q.x is bigger than n

@@ -216,4 +227,4 @@ if (radj >= P) err('q.x invalid'); // ensure q.x is still a field element

};
const bits2int_modN = (bytes: Uint8Array): bigint => { // int2octets can't be used; pads small msgs
return mod(bits2int(bytes), N); // with 0: BAD for trunc as per RFC vectors
const bits2int_modN = (bytes: Uint8Array): bigint => { // int2octets can't be used; pads small msgs
return mod(bits2int(bytes), N); // with 0: BAD for trunc as per RFC vectors
};

@@ -228,4 +239,4 @@ const i2o = (num: bigint): Bytes => n2b(num); // int to octets

const optV: { lowS?: boolean } = { lowS: true }; // standard opts for verify()
type BC = { seed: Bytes, k2sig : (kb: Bytes) => Signature | undefined }; // Bytes+predicate checker
function prepSig(msgh: Hex, priv: Hex, opts = optS): BC { // prepare for RFC6979 sig generation
type BC = { seed: Bytes, k2sig : (kb: Bytes) => SignatureWithRecovery | undefined }; // Bytes+predicate checker
const prepSig = (msgh: Hex, priv: PrivKey, opts=optS): BC => {// prepare for RFC6979 sig generation
if (['der', 'recovered', 'canonical'].some(k => k in opts)) // Ban legacy options

@@ -247,3 +258,3 @@ err('sign() legacy options not supported');

const m = h1i; // convert msg to bigint
const k2sig = (kBytes: Bytes): Signature | undefined => { // Transform k into Signature.
const k2sig = (kBytes: Bytes): SignatureWithRecovery | undefined => { // Transform k => Signature.
const k = bits2int(kBytes); // RFC6979 method.

@@ -263,3 +274,3 @@ if (!ge(k)) return; // Check 0 < k < CURVE.n

}
return new Signature(r, normS, rec); // use normS, not s
return new Signature(r, normS, rec) as SignatureWithRecovery; // use normS, not s
};

@@ -274,3 +285,3 @@ return { seed: concatB(...seed), k2sig }

let k = u8n(fLen); // Steps B, C of RFC6979 3.2: set hashLen, in our case always same
let i = 0; // Iterations counter, will throw when over 1000
let i = 0; // Iterations counter, will throw when over 1000
const reset = () => { v.fill(1); k.fill(0); i = 0; };

@@ -294,4 +305,4 @@ const _e = 'drbg: tried 1000 values';

reset(); // the returned fn, don't, it's: 1. slower (JIT). 2. unsafe (async race conditions)
await reseed(seed); // Steps D-G
let res: T | undefined = undefined; // Step H: grind until k is in [1..n-1]
await reseed(seed); // Steps D-G
let res: T | undefined = undefined; // Step H: grind until k is in [1..n-1]
while (!(res = pred(await gen()))) await reseed();// test predicate until it returns ok

@@ -321,5 +332,5 @@ reset();

reset();
reseed(seed); // Steps D-G
let res: T | undefined = undefined; // Step H: grind until k is in [1..n-1]
while (!(res = pred(gen()))) reseed(); // test predicate until it returns ok
reseed(seed); // Steps D-G
let res: T | undefined = undefined; // Step H: grind until k is in [1..n-1]
while (!(res = pred(gen()))) reseed(); // test predicate until it returns ok
reset();

@@ -331,12 +342,12 @@ return res!;

// ECDSA signature generation. via secg.org/sec1-v2.pdf 4.1.2 + RFC6979 deterministic k
async function signAsync(msgh: Hex, priv: Hex, opts = optS): Promise<Signature> {
const signAsync = async (msgh: Hex, priv: PrivKey, opts = optS): Promise<SignatureWithRecovery> => {
const { seed, k2sig } = prepSig(msgh, priv, opts); // Extract arguments for hmac-drbg
return hmacDrbg<Signature>(true)(seed, k2sig); // Re-run hmac-drbg until k2sig returns ok
return hmacDrbg<SignatureWithRecovery>(true)(seed, k2sig); // Re-run drbg until k2sig returns ok
}
function sign(msgh: Hex, priv: Hex, opts = optS): Signature {
const sign = (msgh: Hex, priv: PrivKey, opts = optS): SignatureWithRecovery => {
const { seed, k2sig } = prepSig(msgh, priv, opts); // Extract arguments for hmac-drbg
return hmacDrbg<Signature>(false)(seed, k2sig); // Re-run hmac-drbg until k2sig returns ok
return hmacDrbg<SignatureWithRecovery>(false)(seed, k2sig); // Re-run drbg until k2sig returns ok
}
type SigLike = { r: bigint, s: bigint };
function verify(sig: Hex | SigLike, msgh: Hex, pub: Hex, opts = optV): boolean {
const verify = (sig: Hex | SigLike, msgh: Hex, pub: Hex, opts = optV): boolean => {
let { lowS } = opts; // ECDSA signature verification

@@ -351,3 +362,3 @@ if (lowS == null) lowS = true; // Default lowS=true

sig_ = rs ? new Signature(sig.r, sig.s).assertValidity() : Signature.fromCompact(sig);
h = bits2int_modN(toU8(msgh, fLen)); // Truncate hash
h = bits2int_modN(toU8(msgh)); // Truncate hash
P = pub instanceof Point ? pub.ok() : Point.fromHex(pub); // Validate public key

@@ -366,9 +377,9 @@ } catch (e) { return false; } // Check sig for validity in both cases

if (!R) return false; // stop if R is identity / zero point
const v = mod(R.x, N); // <== The weird ECDSA part. R.x must be in N's field, not P's
const v = mod(R.x, N); // R.x must be in N's field, not P's
return v === r; // mod(R.x, n) == r
}
function getSharedSecret(privA: Hex, pubB: Hex, isCompressed = true): Bytes {
const getSharedSecret = (privA: Hex, pubB: Hex, isCompressed = true): Bytes => {
return Point.fromHex(pubB).mul(toPriv(privA)).toRawBytes(isCompressed); // ECDH
}
function hashToPrivateKey(hash: Hex): Bytes { // FIPS 186 B.4.1 compliant key generation
const hashToPrivateKey = (hash: Hex): Bytes => { // FIPS 186 B.4.1 compliant key generation
hash = toU8(hash); // produces private keys with modulo bias

@@ -380,3 +391,3 @@ const minLen = fLen + 8; // being neglible.

}
const etc = { // Not placed in utils because they
const etc = { // Not placed in utils because they
hexToBytes: h2b, bytesToHex: b2h, // share API with noble-curves.

@@ -386,5 +397,5 @@ concatBytes: concatB, bytesToNumberBE: b2n, numberToBytesBE: n2b,

hmacSha256Async: async (key: Bytes, ...msgs: Bytes[]): Promise<Bytes> => {
const crypto = cr(); // HMAC-SHA256 async. No sync built-in!
if (!crypto) return err('etc.hmacSha256Async not set'); // Uses webcrypto: native cryptography.
const s = crypto.subtle;
const c = cr(); // async HMAC-SHA256, no sync built-in!
const s = c && c.subtle; // For React Native support, see README.
if (!s) return err('etc.hmacSha256Async not set'); // Uses webcrypto built-in cryptography.
const k = await s.importKey('raw', key, {name:'HMAC',hash:{name:'SHA-256'}}, false, ['sign']);

@@ -395,17 +406,15 @@ return u8n(await s.sign('HMAC', k, concatB(...msgs)));

hashToPrivateKey,
randomBytes: (len: number): Bytes => { // CSPRNG (random number generator)
const crypto = cr(); // Can be shimmed in node.js <= 18 to prevent error:
// import { webcrypto } from 'node:crypto';
// if (!globalThis.crypto) globalThis.crypto = webcrypto;
if (!crypto) err('crypto.getRandomValues must be defined');
randomBytes: (len = 32): Bytes => { // CSPRNG (random number generator)
const crypto = cr(); // Must be shimmed in node.js <= 18 to prevent error. See README.
if (!crypto || !crypto.getRandomValues) err('crypto.getRandomValues must be defined');
return crypto.getRandomValues(u8n(len));
},
}
const utils = { // utilities
const utils = { // utilities
normPrivateKeyToScalar: toPriv,
isValidPrivateKey: (key: Hex) => { try { return !!toPriv(key); } catch (e) { return false; } },
randomPrivateKey: (): Bytes => hashToPrivateKey(etc.randomBytes(fLen + 8)), // FIPS 186 B.4.1.
precompute(w=8, p: Point = G) { p.multiply(3n); return p; }, // no-op
randomPrivateKey: (): Bytes => hashToPrivateKey(etc.randomBytes(fLen + 16)), // FIPS 186 B.4.1.
precompute(w=8, p: Point = G) { p.multiply(3n); w; return p; }, // no-op
};
Object.defineProperties(etc, { hmacSha256Sync: { // Allow setting it once, ignore then
Object.defineProperties(etc, { hmacSha256Sync: { // Allow setting it once, ignore then
configurable: false, get() { return _hmacSync; }, set(f) { if (!_hmacSync) _hmacSync = f; },

@@ -426,2 +435,3 @@ } });

}
let Gpows: Point[] | undefined = undefined; // precomputes for base point G
const wNAF = (n: bigint): { p: Point; f: Point } => { // w-ary non-adjacent form (wNAF) method.

@@ -428,0 +438,0 @@ // Compared to other point mult methods,

{
"name": "@noble/secp256k1",
"version": "2.0.0",
"description": "Fastest 4KB JS implementation of secp256k1 elliptic curve. Auditable, high-security, 0-dependency ECDH & ECDSA signatures compliant with RFC6979",
"version": "2.1.0",
"description": "Fastest 4KB JS implementation of secp256k1 ECDH & ECDSA signatures compliant with RFC6979",
"files": [

@@ -14,9 +14,12 @@ "index.js",

"types": "index.d.ts",
"sideEffects": false,
"scripts": {
"build": "tsc",
"build:release": "rollup -c rollup.config.js",
"test": "node test/secp256k1.test.mjs",
"build:min": "cd test/build; npm install; npm run terser",
"build:mingz": "npm run --silent build:min | gzip -c8",
"build:release": "npm run --silent build:min > test/build/noble-secp256k1.min.js; npm run --silent build:mingz > test/build/noble-secp256k1.min.js.gz",
"test": "node test/index.test.js",
"test:webcrypto": "node test/secp256k1.webcrypto.test.js",
"bench": "node test/benchmark.js",
"min": "cd test/build; npm install; npm run terser",
"loc": "echo \"`npm run --silent min | wc -c` symbols `wc -l < index.ts` LOC, `npm run --silent min | gzip -c8 | wc -c`B gzipped\""
"loc": "echo \"`npm run --silent build:min | wc -c` symbols `wc -l < index.ts` LOC, `npm run --silent build:mingz | wc -c`B gzipped\""
},

@@ -27,11 +30,12 @@ "author": "Paul Miller (https://paulmillr.com)",

"type": "git",
"url": "https://github.com/paulmillr/noble-secp256k1.git"
"url": "git+https://github.com/paulmillr/noble-secp256k1.git"
},
"license": "MIT",
"devDependencies": {
"@noble/hashes": "1.3.0",
"@noble/hashes": "1.4.0",
"@paulmillr/jsbt": "0.1.0",
"fast-check": "3.0.0",
"micro-bmark": "0.3.0",
"micro-should": "0.4.0",
"typescript": "5.0.2"
"typescript": "5.3.2"
},

@@ -58,8 +62,3 @@ "keywords": [

},
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
]
"funding": "https://paulmillr.com/funding/"
}
# noble-secp256k1
[Fastest](#speed) 4KB JS implementation of [secp256k1](https://www.secg.org/sec2-v2.pdf)
elliptic curve. Auditable, high-security, 0-dependency ECDH & ECDSA signatures compliant with RFC6979.
Fastest 4KB JS implementation of secp256k1 signatures & ECDH.
The library is a tiny single-feature version of
[noble-curves](https://github.com/paulmillr/noble-curves), with some features
removed. Check out curves as a drop-in replacement with
Schnorr signatures, DER encoding and support for different hash functions.
- ✍️ Deterministic [ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)
signatures compliant with [RFC6979](https://www.rfc-editor.org/rfc/rfc6979)
- 🤝 Elliptic Curve Diffie-Hellman [ECDH](https://en.wikipedia.org/wiki/Elliptic-curve_Diffie–Hellman)
- 📦 Pure ESM, can be imported without transpilers
- 🪶 4KB gzipped, 450 lines of code
Take a look at: [Upgrading](#upgrading) section for v1 to v2 transition instructions,
[the online demo](https://paulmillr.com/noble/) and blog post
[Learning fast elliptic-curve cryptography in JS](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/).
Use larger drop-in replacement [noble-curves](https://github.com/paulmillr/noble-curves) instead,
if you need additional features such as common.js, Schnorr signatures, DER encoding or support for different hash functions. To upgrade from v1 to v2, see [Upgrading](#upgrading).
### This library belongs to _noble_ crypto
### This library belongs to _noble_ cryptography
> **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
> **noble-cryptography** — high-security, easily auditable set of contained cryptographic libraries and tools.
- No dependencies, protection against supply chain attacks
- Auditable TypeScript / JS code
- Supported in all major browsers and stable node.js versions
- All releases are signed with PGP keys
- Zero or minimal dependencies
- Highly readable TypeScript / JS code
- PGP-signed releases and transparent NPM builds with provenance
- Check out [homepage](https://paulmillr.com/noble/) & all libraries:
[curves](https://github.com/paulmillr/noble-curves)
(4kb versions [secp256k1](https://github.com/paulmillr/noble-secp256k1),
[ed25519](https://github.com/paulmillr/noble-ed25519)),
[hashes](https://github.com/paulmillr/noble-hashes)
[ciphers](https://github.com/paulmillr/noble-ciphers),
[curves](https://github.com/paulmillr/noble-curves),
[hashes](https://github.com/paulmillr/noble-hashes),
[post-quantum](https://github.com/paulmillr/noble-post-quantum),
4kb [secp256k1](https://github.com/paulmillr/noble-secp256k1) /
[ed25519](https://github.com/paulmillr/noble-ed25519)
## Usage
Browser, deno, node.js and unpkg are supported:
> npm install @noble/secp256k1
We support all major platforms and runtimes. For node.js <= 18 and React Native, additional polyfills are needed: see below.
```js
import * as secp from '@noble/secp256k1'; // ESM-only. Use bundler for common.js
import * as secp from '@noble/secp256k1';
// import * as secp from "https://deno.land/x/secp256k1/mod.ts"; // Deno

@@ -45,7 +45,7 @@ // import * as secp from "https://unpkg.com/@noble/secp256k1"; // Unpkg

const msgHash = 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9';
const pubKey = secp.getPublicKey(privKey); // Make pubkey from the private key
const signature = await secp.signAsync(msgHash, privKey); // sign
const isValid = secp.verify(signature, msgHash, pubKey); // verify
const pubKey = secp.getPublicKey(privKey);
const signature = await secp.signAsync(msgHash, privKey); // Sync methods below
const isValid = secp.verify(signature, msgHash, pubKey);
const pubKey2 = getPublicKey(secp.utils.randomPrivateKey()); // Key of user 2
const alicesPubkey = secp.getPublicKey(secp.utils.randomPrivateKey());
secp.getSharedSecret(privKey, alicesPubkey); // Elliptic curve diffie-hellman

@@ -56,15 +56,14 @@ signature.recoverPublicKey(msgHash); // Public key recovery

Advanced examples:
Additional polyfills for some environments:
```ts
// 1. Use the shim to enable synchronous methods.
// Only async methods are available by default to keep library dependency-free.
// 1. Enable synchronous methods.
// Only async methods are available by default, to keep the library dependency-free.
import { hmac } from '@noble/hashes/hmac';
import { sha256 } from '@noble/hashes/sha256';
secp.etc.hmacSha256Sync = (k, ...m) => hmac(sha256, k, secp.etc.concatBytes(...m))
const signature2 = secp.sign(msgHash, privKey); // Can be used now
// Sync methods can be used now:
// secp.sign(msgHash, privKey);
// 2. Use the shim only for node.js <= 18 BEFORE importing noble-secp256k1.
// The library depends on global variable crypto to work. It is available in
// all browsers and many environments, but node.js <= 18 don't have it.
// 2. node.js 18 and older, requires polyfilling globalThis.crypto
import { webcrypto } from 'node:crypto';

@@ -74,20 +73,8 @@ // @ts-ignore

// Other stuff
// Malleable signatures, incompatible with BTC/ETH, but compatible with openssl
// `lowS: true` prohibits signatures which have (sig.s >= CURVE.n/2n) because of
// malleability
const signatureMalleable = secp.sign(msgHash, privKey, { lowS: false });
// Signatures with improved security: adds additional entropy `k` for
// deterministic signature, follows section 3.6 of RFC6979. When `true`, it
// would be filled with 32b from CSPRNG. **Strongly recommended** to pass `true`
// to improve security:
// - No disadvantage: if an entropy generator is broken, sigs would be the same
// as they are without the option
// - It would help a lot in case there is an error somewhere in `k` gen.
// Exposing `k` could leak private keys
// - Sigs with extra entropy would have different `r` / `s`, which means they
// would still be valid, but may break some test vectors if you're
// cross-testing against other libs
const signatureImproved = secp.sign(msgHash, privKey, { extraEntropy: true });
// 3. React Native needs crypto.getRandomValues polyfill and sha512
import 'react-native-get-random-values';
import { hmac } from '@noble/hashes/hmac';
import { sha256 } from '@noble/hashes/sha256';
secp.etc.hmacSha256Sync = (k, ...m) => hmac(sha256, k, secp.etc.concatBytes(...m));
secp.etc.hmacSha256Async = (k, ...m) => Promise.resolve(secp.etc.hmacSha256Sync(k, ...m));
```

@@ -100,15 +87,23 @@

`verify(signature, messageHash, publicKey)`.
We accept Hex type everywhere:
```typescript
type Hex = Uint8Array | string;
```ts
type Hex = Uint8Array | string
```
// Generates public key from 32-byte private key.
// isCompressed=true by default, meaning 33-byte output. Set to false for 65b.
### getPublicKey
```ts
function getPublicKey(privateKey: Hex, isCompressed?: boolean): Uint8Array;
// Use:
// - `ProjectivePoint.fromPrivateKey(privateKey)` for Point instance
// - `ProjectivePoint.fromHex(publicKey)` to convert hex / bytes into Point.
```
// Generates low-s deterministic-k RFC6979 ECDSA signature.
// Use with `extraEntropy: true` to improve security.
Generates 33-byte compressed public key from 32-byte private key.
- If you need uncompressed 65-byte public key, set second argument to `false`.
- Use `ProjectivePoint.fromPrivateKey(privateKey)` for Point instance.
- Use `ProjectivePoint.fromHex(publicKey)` to convert Hex / Uint8Array into Point.
### sign
```ts
function sign(

@@ -125,6 +120,23 @@ messageHash: Hex, // message hash (not message) which would be signed

// Verifies ECDSA signature.
// lowS option Ensures a signature.s is in the lower-half of CURVE.n.
// Used in BTC, ETH.
// `{ lowS: false }` should only be used if you need OpenSSL-compatible signatures
sign(msgHash, privKey, { lowS: false }); // Malleable signature
sign(msgHash, privKey, { extraEntropy: true }); // Improved security
```
Generates low-s deterministic-k RFC6979 ECDSA signature. Assumes hash of message,
which means you'll need to do something like `sha256(message)` before signing.
1. `lowS: false` allows to create malleable signatures, for compatibility with openssl.
Default `lowS: true` prohibits signatures which have (sig.s >= CURVE.n/2n) and is compatible with BTC/ETH.
2. `extraEntropy: true` improves security by adding entropy, follows section 3.6 of RFC6979:
- No disadvantage: if an entropy generator is broken, sigs would be the same
as they are without the option
- It would help a lot in case there is an error somewhere in `k` gen.
Exposing `k` could leak private keys
- Sigs with extra entropy would have different `r` / `s`, which means they
would still be valid, but may break some test vectors if you're
cross-testing against other libs
### verify
```ts
function verify(

@@ -136,5 +148,10 @@ signature: Hex | Signature, // returned by the `sign` function

): boolean;
```
// Computes ECDH (Elliptic Curve Diffie-Hellman) shared secret between
// key A and different key B.
Verifies ECDSA signature and ensures it has lowS (compatible with BTC/ETH).
`lowS: false` turns off malleability check, but makes it OpenSSL-compatible.
### getSharedSecret
```ts
function getSharedSecret(

@@ -145,5 +162,12 @@ privateKeyA: Uint8Array | string, // Alices's private key

): Uint8Array;
// Use `ProjectivePoint.fromHex(publicKeyB).multiply(privateKeyA)` for Point instance
```
// Recover public key from Signature instance with `recovery` bit set
Computes ECDH (Elliptic Curve Diffie-Hellman) shared secret between
key A and different key B.
Use `ProjectivePoint.fromHex(publicKeyB).multiply(privateKeyA)` for Point instance
### recoverPublicKey
```ts
signature.recoverPublicKey(

@@ -154,2 +178,6 @@ msgHash: Uint8Array | string

Recover public key from Signature instance with `recovery` bit set.
### utils
A bunch of useful **utilities** are also exposed:

@@ -159,6 +187,6 @@

type Bytes = Uint8Array;
export declare const etc: {
const etc: {
hexToBytes: (hex: string) => Bytes;
bytesToHex: (b: Bytes) => string;
concatBytes: (...arrs: Bytes[]) => Uint8Array;
concatBytes: (...arrs: Bytes[]) => Bytes;
bytesToNumberBE: (b: Bytes) => bigint;

@@ -173,38 +201,38 @@ numberToBytesBE: (num: bigint) => Bytes;

};
export declare const utils: {
const utils: {
normPrivateKeyToScalar: (p: PrivKey) => bigint;
randomPrivateKey: () => Bytes;
randomPrivateKey: () => Bytes; // Uses CSPRNG https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
isValidPrivateKey: (key: Hex) => boolean;
precompute(p: Point, windowSize?: number): Point;
precompute(p: ProjectivePoint, windowSize?: number): ProjectivePoint;
};
class ProjectivePoint {
readonly px: bigint;
readonly py: bigint;
readonly pz: bigint;
constructor(px: bigint, py: bigint, pz: bigint);
static readonly BASE: Point;
static readonly ZERO: Point;
static fromHex(hex: Hex): Point;
static fromPrivateKey(n: PrivKey): Point;
static readonly BASE: ProjectivePoint;
static readonly ZERO: ProjectivePoint;
static fromAffine(point: AffinePoint): ProjectivePoint;
static fromHex(hex: Hex): ProjectivePoint;
static fromPrivateKey(n: PrivKey): ProjectivePoint;
get x(): bigint;
get y(): bigint;
equals(other: Point): boolean;
add(other: Point): Point;
multiply(n: bigint): Point;
negate(): Point;
add(other: ProjectivePoint): ProjectivePoint;
assertValidity(): void;
equals(other: ProjectivePoint): boolean;
multiply(n: bigint): ProjectivePoint;
negate(): ProjectivePoint;
subtract(other: ProjectivePoint): ProjectivePoint;
toAffine(): AffinePoint;
assertValidity(): Point;
toHex(isCompressed?: boolean): string;
toRawBytes(isCompressed?: boolean): Uint8Array;
toRawBytes(isCompressed?: boolean): Bytes;
}
class Signature {
constructor(r: bigint, s: bigint, recovery?: number | undefined);
static fromCompact(hex: Hex): Signature;
readonly r: bigint;
readonly s: bigint;
readonly recovery?: number | undefined;
constructor(r: bigint, s: bigint, recovery?: number | undefined);
ok(): Signature;
static fromCompact(hex: Hex): Signature;
hasHighS(): boolean;
normalizeS(): Signature;
recoverPublicKey(msgh: Hex): Point;
toCompactRawBytes(): Uint8Array;
toCompactRawBytes(): Bytes;
toCompactHex(): string;

@@ -243,2 +271,6 @@ }

As for key generation, we're deferring to built-in
[crypto.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues)
which is considered cryptographically secure (CSPRNG).
## Speed

@@ -248,10 +280,10 @@

Benchmarks measured with Apple M2 on MacOS 13 with node.js 19.
Benchmarks measured with Apple M2 on MacOS 13 with node.js 20.
getPublicKey(utils.randomPrivateKey()) x 5,540 ops/sec @ 180μs/op
sign x 3,301 ops/sec @ 302μs/op
verify x 517 ops/sec @ 1ms/op
getSharedSecret x 433 ops/sec @ 2ms/op
recoverPublicKey x 526 ops/sec @ 1ms/op
Point.fromHex (decompression) x 8,415 ops/sec @ 118μs/op
getPublicKey(utils.randomPrivateKey()) x 6,430 ops/sec @ 155μs/op
sign x 3,367 ops/sec @ 296μs/op
verify x 600 ops/sec @ 1ms/op
getSharedSecret x 505 ops/sec @ 1ms/op
recoverPublicKey x 612 ops/sec @ 1ms/op
Point.fromHex (decompression) x 9,185 ops/sec @ 108μs/op

@@ -267,3 +299,2 @@ Compare to other libraries on M1 (`openssl` uses native bindings, not JS):

ecdsa#sign x 116 ops/sec
bip-schnorr#sign x 60 ops/sec

@@ -274,3 +305,2 @@ elliptic#verify x 812 ops/sec

ecdsa#verify x 80 ops/sec
bip-schnorr#verify x 56 ops/sec

@@ -277,0 +307,0 @@ elliptic#ecdh x 971 ops/sec

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc