Socket
Socket
Sign inDemoInstall

@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 1.3.4 to 1.4.0

218

lib/esm/index.js

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

if (recovery !== 0 && recovery !== 1) {
throw new Error('Cannot recover signature: invalid yParity bit');
throw new Error('Cannot recover signature: invalid recovery bit');
}

@@ -355,5 +355,33 @@ const prefix = 2 + (recovery & 1);

Point.ZERO = new Point(_0n, _0n);
function sliceDer(s) {
function sliceDER(s) {
return Number.parseInt(s[0], 16) >= 8 ? '00' + s : s;
}
function parseDERInt(data) {
if (data.length < 2 || data[0] !== 0x02) {
throw new Error(`Invalid signature integer tag: ${bytesToHex(data)}`);
}
const len = data[1];
const res = data.subarray(2, len + 2);
if (!len || res.length !== len) {
throw new Error(`Invalid signature integer: wrong length`);
}
if (res[0] === 0x00 && res[1] <= 0x7f) {
throw new Error('Invalid signature integer: trailing length');
}
return { data: bytesToNumber(res), left: data.subarray(len + 2) };
}
function parseDERSignature(data) {
if (data.length < 2 || data[0] != 0x30) {
throw new Error(`Invalid signature tag: ${bytesToHex(data)}`);
}
if (data[1] !== data.length - 2) {
throw new Error('Invalid signature: incorrect length');
}
const { data: r, left: sBytes } = parseDERInt(data.subarray(2));
const { data: s, left: rBytesLeft } = parseDERInt(sBytes);
if (rBytesLeft.length) {
throw new Error(`Invalid signature: left bytes after parsing: ${bytesToHex(rBytesLeft)}`);
}
return { r, s };
}
export class Signature {

@@ -363,52 +391,20 @@ constructor(r, s) {

this.s = s;
this.assertValidity();
}
static fromCompact(hex) {
if (typeof hex !== 'string' && !(hex instanceof Uint8Array)) {
throw new TypeError(`Signature.fromCompact: Expected string or Uint8Array`);
}
const str = hex instanceof Uint8Array ? bytesToHex(hex) : hex;
const arr = hex instanceof Uint8Array;
const name = 'Signature.fromCompact';
if (typeof hex !== 'string' && !arr)
throw new TypeError(`${name}: Expected string or Uint8Array`);
const str = arr ? bytesToHex(hex) : hex;
if (str.length !== 128)
throw new Error('Signature.fromCompact: Expected 64-byte hex');
const sig = new Signature(hexToNumber(str.slice(0, 64)), hexToNumber(str.slice(64, 128)));
sig.assertValidity();
return sig;
throw new Error(`${name}: Expected 64-byte hex`);
return new Signature(hexToNumber(str.slice(0, 64)), hexToNumber(str.slice(64, 128)));
}
static fromDER(hex) {
const fn = 'Signature.fromDER';
if (typeof hex !== 'string' && !(hex instanceof Uint8Array)) {
throw new TypeError(`${fn}: Expected string or Uint8Array`);
}
const str = hex instanceof Uint8Array ? bytesToHex(hex) : hex;
const length = parseByte(str.slice(2, 4));
if (str.slice(0, 2) !== '30' || length !== str.length - 4 || str.slice(4, 6) !== '02') {
throw new Error(`${fn}: Invalid signature ${str}`);
}
const rLen = parseByte(str.slice(6, 8));
const rEnd = 8 + rLen;
const rr = str.slice(8, rEnd);
if (rr.startsWith('00') && parseByte(rr.slice(2, 4)) <= 0x7f) {
throw new Error(`${fn}: Invalid r with trailing length`);
}
const r = hexToNumber(rr);
const separator = str.slice(rEnd, rEnd + 2);
if (separator !== '02') {
throw new Error(`${fn}: Invalid r-s separator`);
}
const sLen = parseByte(str.slice(rEnd + 2, rEnd + 4));
const diff = length - sLen - rLen - 10;
if (diff > 0 || diff === -4) {
throw new Error(`${fn}: Invalid total length`);
}
if (sLen > length - rLen - 4) {
throw new Error(`${fn}: Invalid s`);
}
const sStart = rEnd + 4;
const ss = str.slice(sStart, sStart + sLen);
if (ss.startsWith('00') && parseByte(ss.slice(2, 4)) <= 0x7f) {
throw new Error(`${fn}: Invalid s with trailing length`);
}
const s = hexToNumber(ss);
const sig = new Signature(r, s);
sig.assertValidity();
return sig;
const arr = hex instanceof Uint8Array;
if (typeof hex !== 'string' && !arr)
throw new TypeError(`Signature.fromDER: Expected string or Uint8Array`);
const { r, s } = parseDERSignature(arr ? hex : hexToBytes(hex));
return new Signature(r, s);
}

@@ -425,2 +421,9 @@ static fromHex(hex) {

}
hasHighS() {
const HALF = CURVE.n >> _1n;
return this.s > HALF;
}
normalizeS() {
return this.hasHighS() ? new Signature(this.r, CURVE.n - this.s) : this;
}
toDERRawBytes(isCompressed = false) {

@@ -430,6 +433,6 @@ return hexToBytes(this.toDERHex(isCompressed));

toDERHex(isCompressed = false) {
const sHex = sliceDer(numberToHex(this.s));
const sHex = sliceDER(numberToHex(this.s));
if (isCompressed)
return sHex;
const rHex = sliceDer(numberToHex(this.r));
const rHex = sliceDER(numberToHex(this.r));
const rLen = numberToHex(rHex.length / 2);

@@ -453,3 +456,2 @@ const sLen = numberToHex(sHex.length / 2);

}
export const SignResult = Signature;
function concatBytes(...arrays) {

@@ -467,6 +469,7 @@ if (arrays.length === 1)

}
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
function bytesToHex(uint8a) {
let hex = '';
for (let i = 0; i < uint8a.length; i++) {
hex += uint8a[i].toString(16).padStart(2, '0');
hex += hexes[uint8a[i]];
}

@@ -476,2 +479,4 @@ return hex;

function pad64(num) {
if (num > POW_2_256)
throw new Error('pad64: invalid number');
return num.toString(16).padStart(64, '0');

@@ -492,2 +497,10 @@ }

}
function parseHexByte(hexByte) {
if (hexByte.length !== 2)
throw new Error('Invalid byte sequence');
const byte = Number.parseInt(hexByte, 16);
if (Number.isNaN(byte))
throw new Error('Invalid byte sequence');
return byte;
}
function hexToBytes(hex) {

@@ -502,3 +515,3 @@ if (typeof hex !== 'string') {

const j = i * 2;
array[i] = Number.parseInt(hex.slice(j, j + 2), 16);
array[i] = parseHexByte(hex.slice(j, j + 2));
}

@@ -513,5 +526,2 @@ return array;

}
function parseByte(str) {
return Number.parseInt(str, 16) * 2;
}
function normalizeScalar(num) {

@@ -635,3 +645,3 @@ if (typeof num === 'number' && num > 0 && Number.isSafeInteger(num))

}
function _abc6979(msgHash, privateKey) {
function _abc6979(msgHash, privateKey, extraEntropy) {
if (msgHash == null)

@@ -647,15 +657,22 @@ throw new Error(`sign: expected valid msgHash, not "${msgHash}"`);

const b1 = Uint8Array.from([0x01]);
return { h1, h1n, x, v, k, b0, b1 };
let xh1 = concatBytes(x, h1);
if (extraEntropy != null) {
const e = pad32b(typeof extraEntropy === 'string' ? hexToNumber(extraEntropy) : bytesToNumber(extraEntropy));
if (e.length !== 32)
throw new Error('secp256k1: Expected 32 bytes of extra data');
xh1 = concatBytes(xh1, e);
}
return { xh1, h1n, v, k, b0, b1 };
}
async function getQRSrfc6979(msgHash, privateKey) {
async function getQRSrfc6979(msgHash, privateKey, extraEntropy) {
const privKey = normalizePrivateKey(privateKey);
let { h1, h1n, x, v, k, b0, b1 } = _abc6979(msgHash, privKey);
let { xh1, h1n, v, k, b0, b1 } = _abc6979(msgHash, privKey, extraEntropy);
const hmac = utils.hmacSha256;
k = await hmac(k, v, b0, x, h1);
k = await hmac(k, v, b0, xh1);
v = await hmac(k, v);
k = await hmac(k, v, b1, x, h1);
k = await hmac(k, v, b1, xh1);
v = await hmac(k, v);
for (let i = 0; i < 1000; i++) {
v = await hmac(k, v);
let qrs = calcQRSFromK(v, h1n, privKey);
const qrs = calcQRSFromK(v, h1n, privKey);
if (qrs)

@@ -668,17 +685,17 @@ return qrs;

}
function getQRSrfc6979Sync(msgHash, privateKey) {
function getQRSrfc6979Sync(msgHash, privateKey, extraEntropy) {
const privKey = normalizePrivateKey(privateKey);
let { h1, h1n, x, v, k, b0, b1 } = _abc6979(msgHash, privKey);
let { xh1, h1n, v, k, b0, b1 } = _abc6979(msgHash, privKey, extraEntropy);
const hmac = utils.hmacSha256Sync;
if (!hmac)
throw new Error('utils.hmacSha256Sync is undefined, you need to set it');
k = hmac(k, v, b0, x, h1);
k = hmac(k, v, b0, xh1);
if (k instanceof Promise)
throw new Error('To use sync sign(), ensure utils.hmacSha256 is sync');
v = hmac(k, v);
k = hmac(k, v, b1, x, h1);
k = hmac(k, v, b1, xh1);
v = hmac(k, v);
for (let i = 0; i < 1000; i++) {
v = hmac(k, v);
let qrs = calcQRSFromK(v, h1n, privKey);
const qrs = calcQRSFromK(v, h1n, privKey);
if (qrs)

@@ -704,3 +721,3 @@ return qrs;

return;
return [q, r, s];
return { q, r, s };
}

@@ -746,16 +763,14 @@ function normalizePrivateKey(key) {

}
else {
try {
return Signature.fromDER(signature);
}
catch (error) {
return Signature.fromCompact(signature);
}
}
export function getPublicKey(privateKey, isCompressed = false) {
const point = Point.fromPrivateKey(privateKey);
if (typeof privateKey === 'string') {
return point.toHex(isCompressed);
}
return point.toRawBytes(isCompressed);
return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed);
}
export function recoverPublicKey(msgHash, signature, recovery) {
const point = Point.fromSignature(msgHash, signature, recovery);
return typeof msgHash === 'string' ? point.toHex() : point.toRawBytes();
return Point.fromSignature(msgHash, signature, recovery).toRawBytes();
}

@@ -781,32 +796,26 @@ function isPub(item) {

b.assertValidity();
const shared = b.multiply(normalizePrivateKey(privateA));
return typeof privateA === 'string'
? shared.toHex(isCompressed)
: shared.toRawBytes(isCompressed);
return b.multiply(normalizePrivateKey(privateA)).toRawBytes(isCompressed);
}
function QRSToSig(qrs, opts, str = false) {
const [q, r, s] = qrs;
let { canonical, der, recovered } = opts;
function QRSToSig(qrs, opts) {
const { q, r, s } = qrs;
const defaultOpts = { canonical: true, der: true };
let { canonical, der, recovered } = Object.assign(defaultOpts, opts);
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n);
let adjustedS = s;
const HIGH_NUMBER = CURVE.n >> _1n;
if (s > HIGH_NUMBER && canonical) {
adjustedS = CURVE.n - s;
let sig = new Signature(r, s);
if (canonical && sig.hasHighS()) {
sig = sig.normalizeS();
recovery ^= 1;
}
const sig = new Signature(r, adjustedS);
sig.assertValidity();
const hex = der === false ? sig.toCompactHex() : sig.toDERHex();
const hashed = str ? hex : hexToBytes(hex);
const hashed = der ? sig.toDERRawBytes() : sig.toCompactRawBytes();
return recovered ? [hashed, recovery] : hashed;
}
async function sign(msgHash, privKey, opts = {}) {
return QRSToSig(await getQRSrfc6979(msgHash, privKey), opts, typeof msgHash === 'string');
return QRSToSig(await getQRSrfc6979(msgHash, privKey, opts.extraEntropy), opts);
}
function signSync(msgHash, privKey, opts = {}) {
return QRSToSig(getQRSrfc6979Sync(msgHash, privKey), opts, typeof msgHash === 'string');
return QRSToSig(getQRSrfc6979Sync(msgHash, privKey, opts.extraEntropy), opts);
}
export { sign, signSync };
export function verify(signature, msgHash, publicKey) {
const { n } = CURVE;
const vopts = { strict: true };
export function verify(signature, msgHash, publicKey, opts = vopts) {
let sig;

@@ -820,6 +829,15 @@ try {

const { r, s } = sig;
if (opts.strict && sig.hasHighS())
return false;
const h = truncateHash(msgHash);
if (h === _0n)
return false;
const pubKey = JacobianPoint.fromAffine(normalizePublicKey(publicKey));
let pubKey;
try {
pubKey = JacobianPoint.fromAffine(normalizePublicKey(publicKey));
}
catch (error) {
return false;
}
const { n } = CURVE;
const s1 = invert(s, n);

@@ -872,4 +890,3 @@ const u1 = mod(h * s1, n);

function schnorrGetPublicKey(privateKey) {
const P = Point.fromPrivateKey(privateKey);
return typeof privateKey === 'string' ? P.toHexX() : P.toRawX();
return Point.fromPrivateKey(privateKey).toRawX();
}

@@ -902,3 +919,3 @@ async function schnorrSign(msgHash, privateKey, auxRand = utils.randomBytes()) {

throw new Error('sign: Invalid signature produced');
return typeof msgHash === 'string' ? sig.toHex() : sig.toRawBytes();
return sig.toRawBytes();
}

@@ -960,2 +977,3 @@ async function schnorrVerify(signature, msgHash, publicKey) {

},
bytesToHex,
sha256: async (message) => {

@@ -984,3 +1002,3 @@ if (crypto.web) {

const hash = createHmac('sha256', key);
for (let message of messages) {
for (const message of messages) {
hash.update(message);

@@ -987,0 +1005,0 @@ }

@@ -18,4 +18,4 @@ /*! noble-secp256k1 - MIT License (c) Paul Miller (paulmillr.com) */

export declare class Point {
x: bigint;
y: bigint;
readonly x: bigint;
readonly y: bigint;
static BASE: Point;

@@ -44,4 +44,4 @@ static ZERO: Point;

export declare class Signature {
r: bigint;
s: bigint;
readonly r: bigint;
readonly s: bigint;
constructor(r: bigint, s: bigint);

@@ -52,2 +52,4 @@ static fromCompact(hex: Hex): Signature;

assertValidity(): void;
hasHighS(): boolean;
normalizeS(): Signature;
toDERRawBytes(isCompressed?: boolean): Uint8Array;

@@ -60,31 +62,28 @@ toDERHex(isCompressed?: boolean): string;

}
export declare const SignResult: typeof Signature;
declare function bytesToHex(uint8a: Uint8Array): string;
declare type U8A = Uint8Array;
export declare function getPublicKey(privateKey: Uint8Array | number | bigint, isCompressed?: boolean): Uint8Array;
export declare function getPublicKey(privateKey: string, isCompressed?: boolean): string;
export declare function recoverPublicKey(msgHash: string, signature: string, recovery: number): string | undefined;
export declare function recoverPublicKey(msgHash: Uint8Array, signature: Uint8Array, recovery: number): Uint8Array | undefined;
export declare function getSharedSecret(privateA: PrivKey, publicB: PubKey, isCompressed?: boolean): Hex;
export declare function getPublicKey(privateKey: PrivKey, isCompressed?: boolean): Uint8Array;
export declare function recoverPublicKey(msgHash: Hex, signature: Sig, recovery: number): Uint8Array | undefined;
export declare function getSharedSecret(privateA: PrivKey, publicB: PubKey, isCompressed?: boolean): Uint8Array;
declare type OptsRecov = {
recovered: true;
canonical?: true;
canonical?: boolean;
der?: boolean;
extraEntropy?: Hex;
};
declare type OptsNoRecov = {
recovered?: false;
canonical?: true;
canonical?: boolean;
der?: boolean;
extraEntropy?: Hex;
};
declare function sign(msgHash: U8A, privKey: PrivKey, opts: OptsRecov): Promise<[U8A, number]>;
declare function sign(msgHash: string, privKey: PrivKey, opts: OptsRecov): Promise<[string, number]>;
declare function sign(msgHash: U8A, privKey: PrivKey, opts?: OptsNoRecov): Promise<U8A>;
declare function sign(msgHash: string, privKey: PrivKey, opts?: OptsNoRecov): Promise<string>;
declare function sign(msgHash: string, privKey: PrivKey, opts?: OptsNoRecov): Promise<string>;
declare function signSync(msgHash: U8A, privKey: PrivKey, opts: OptsRecov): [U8A, number];
declare function signSync(msgHash: string, privKey: PrivKey, opts: OptsRecov): [string, number];
declare function signSync(msgHash: U8A, privKey: PrivKey, opts?: OptsNoRecov): U8A;
declare function signSync(msgHash: string, privKey: PrivKey, opts?: OptsNoRecov): string;
declare function signSync(msgHash: string, privKey: PrivKey, opts?: OptsNoRecov): string;
declare function sign(msgHash: Hex, privKey: PrivKey, opts: OptsRecov): Promise<[U8A, number]>;
declare function sign(msgHash: Hex, privKey: PrivKey, opts?: OptsNoRecov): Promise<U8A>;
declare function signSync(msgHash: Hex, privKey: PrivKey, opts: OptsRecov): [U8A, number];
declare function signSync(msgHash: Hex, privKey: PrivKey, opts?: OptsNoRecov): U8A;
export { sign, signSync };
export declare function verify(signature: Sig, msgHash: Hex, publicKey: PubKey): boolean;
declare type VOpts = {
strict?: boolean;
};
export declare function verify(signature: Sig, msgHash: Hex, publicKey: PubKey, opts?: VOpts): boolean;
declare class SchnorrSignature {

@@ -98,6 +97,4 @@ readonly r: bigint;

}
declare function schnorrGetPublicKey(privateKey: Uint8Array): Uint8Array;
declare function schnorrGetPublicKey(privateKey: string): string;
declare function schnorrSign(msgHash: string, privateKey: string, auxRand?: Hex): Promise<string>;
declare function schnorrSign(msgHash: Uint8Array, privateKey: Uint8Array, auxRand?: Hex): Promise<Uint8Array>;
declare function schnorrGetPublicKey(privateKey: PrivKey): Uint8Array;
declare function schnorrSign(msgHash: Hex, privateKey: PrivKey, auxRand?: Hex): Promise<Uint8Array>;
declare function schnorrVerify(signature: Hex, msgHash: Hex, publicKey: Hex): Promise<boolean>;

@@ -116,2 +113,3 @@ export declare const schnorr: {

randomPrivateKey: () => Uint8Array;
bytesToHex: typeof bytesToHex;
sha256: (message: Uint8Array) => Promise<Uint8Array>;

@@ -118,0 +116,0 @@ hmacSha256: (key: Uint8Array, ...messages: Uint8Array[]) => Promise<Uint8Array>;

@@ -7,3 +7,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.utils = exports.schnorr = exports.verify = exports.signSync = exports.sign = exports.getSharedSecret = exports.recoverPublicKey = exports.getPublicKey = exports.SignResult = exports.Signature = exports.Point = exports.CURVE = void 0;
exports.utils = exports.schnorr = exports.verify = exports.signSync = exports.sign = exports.getSharedSecret = exports.recoverPublicKey = exports.getPublicKey = exports.Signature = exports.Point = exports.CURVE = void 0;
const crypto_1 = __importDefault(require("crypto"));

@@ -299,3 +299,3 @@ const _0n = BigInt(0);

if (recovery !== 0 && recovery !== 1) {
throw new Error('Cannot recover signature: invalid yParity bit');
throw new Error('Cannot recover signature: invalid recovery bit');
}

@@ -363,5 +363,33 @@ const prefix = 2 + (recovery & 1);

Point.ZERO = new Point(_0n, _0n);
function sliceDer(s) {
function sliceDER(s) {
return Number.parseInt(s[0], 16) >= 8 ? '00' + s : s;
}
function parseDERInt(data) {
if (data.length < 2 || data[0] !== 0x02) {
throw new Error(`Invalid signature integer tag: ${bytesToHex(data)}`);
}
const len = data[1];
const res = data.subarray(2, len + 2);
if (!len || res.length !== len) {
throw new Error(`Invalid signature integer: wrong length`);
}
if (res[0] === 0x00 && res[1] <= 0x7f) {
throw new Error('Invalid signature integer: trailing length');
}
return { data: bytesToNumber(res), left: data.subarray(len + 2) };
}
function parseDERSignature(data) {
if (data.length < 2 || data[0] != 0x30) {
throw new Error(`Invalid signature tag: ${bytesToHex(data)}`);
}
if (data[1] !== data.length - 2) {
throw new Error('Invalid signature: incorrect length');
}
const { data: r, left: sBytes } = parseDERInt(data.subarray(2));
const { data: s, left: rBytesLeft } = parseDERInt(sBytes);
if (rBytesLeft.length) {
throw new Error(`Invalid signature: left bytes after parsing: ${bytesToHex(rBytesLeft)}`);
}
return { r, s };
}
class Signature {

@@ -371,52 +399,20 @@ constructor(r, s) {

this.s = s;
this.assertValidity();
}
static fromCompact(hex) {
if (typeof hex !== 'string' && !(hex instanceof Uint8Array)) {
throw new TypeError(`Signature.fromCompact: Expected string or Uint8Array`);
}
const str = hex instanceof Uint8Array ? bytesToHex(hex) : hex;
const arr = hex instanceof Uint8Array;
const name = 'Signature.fromCompact';
if (typeof hex !== 'string' && !arr)
throw new TypeError(`${name}: Expected string or Uint8Array`);
const str = arr ? bytesToHex(hex) : hex;
if (str.length !== 128)
throw new Error('Signature.fromCompact: Expected 64-byte hex');
const sig = new Signature(hexToNumber(str.slice(0, 64)), hexToNumber(str.slice(64, 128)));
sig.assertValidity();
return sig;
throw new Error(`${name}: Expected 64-byte hex`);
return new Signature(hexToNumber(str.slice(0, 64)), hexToNumber(str.slice(64, 128)));
}
static fromDER(hex) {
const fn = 'Signature.fromDER';
if (typeof hex !== 'string' && !(hex instanceof Uint8Array)) {
throw new TypeError(`${fn}: Expected string or Uint8Array`);
}
const str = hex instanceof Uint8Array ? bytesToHex(hex) : hex;
const length = parseByte(str.slice(2, 4));
if (str.slice(0, 2) !== '30' || length !== str.length - 4 || str.slice(4, 6) !== '02') {
throw new Error(`${fn}: Invalid signature ${str}`);
}
const rLen = parseByte(str.slice(6, 8));
const rEnd = 8 + rLen;
const rr = str.slice(8, rEnd);
if (rr.startsWith('00') && parseByte(rr.slice(2, 4)) <= 0x7f) {
throw new Error(`${fn}: Invalid r with trailing length`);
}
const r = hexToNumber(rr);
const separator = str.slice(rEnd, rEnd + 2);
if (separator !== '02') {
throw new Error(`${fn}: Invalid r-s separator`);
}
const sLen = parseByte(str.slice(rEnd + 2, rEnd + 4));
const diff = length - sLen - rLen - 10;
if (diff > 0 || diff === -4) {
throw new Error(`${fn}: Invalid total length`);
}
if (sLen > length - rLen - 4) {
throw new Error(`${fn}: Invalid s`);
}
const sStart = rEnd + 4;
const ss = str.slice(sStart, sStart + sLen);
if (ss.startsWith('00') && parseByte(ss.slice(2, 4)) <= 0x7f) {
throw new Error(`${fn}: Invalid s with trailing length`);
}
const s = hexToNumber(ss);
const sig = new Signature(r, s);
sig.assertValidity();
return sig;
const arr = hex instanceof Uint8Array;
if (typeof hex !== 'string' && !arr)
throw new TypeError(`Signature.fromDER: Expected string or Uint8Array`);
const { r, s } = parseDERSignature(arr ? hex : hexToBytes(hex));
return new Signature(r, s);
}

@@ -433,2 +429,9 @@ static fromHex(hex) {

}
hasHighS() {
const HALF = CURVE.n >> _1n;
return this.s > HALF;
}
normalizeS() {
return this.hasHighS() ? new Signature(this.r, CURVE.n - this.s) : this;
}
toDERRawBytes(isCompressed = false) {

@@ -438,6 +441,6 @@ return hexToBytes(this.toDERHex(isCompressed));

toDERHex(isCompressed = false) {
const sHex = sliceDer(numberToHex(this.s));
const sHex = sliceDER(numberToHex(this.s));
if (isCompressed)
return sHex;
const rHex = sliceDer(numberToHex(this.r));
const rHex = sliceDER(numberToHex(this.r));
const rLen = numberToHex(rHex.length / 2);

@@ -462,3 +465,2 @@ const sLen = numberToHex(sHex.length / 2);

exports.Signature = Signature;
exports.SignResult = Signature;
function concatBytes(...arrays) {

@@ -476,6 +478,7 @@ if (arrays.length === 1)

}
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
function bytesToHex(uint8a) {
let hex = '';
for (let i = 0; i < uint8a.length; i++) {
hex += uint8a[i].toString(16).padStart(2, '0');
hex += hexes[uint8a[i]];
}

@@ -485,2 +488,4 @@ return hex;

function pad64(num) {
if (num > POW_2_256)
throw new Error('pad64: invalid number');
return num.toString(16).padStart(64, '0');

@@ -501,2 +506,10 @@ }

}
function parseHexByte(hexByte) {
if (hexByte.length !== 2)
throw new Error('Invalid byte sequence');
const byte = Number.parseInt(hexByte, 16);
if (Number.isNaN(byte))
throw new Error('Invalid byte sequence');
return byte;
}
function hexToBytes(hex) {

@@ -511,3 +524,3 @@ if (typeof hex !== 'string') {

const j = i * 2;
array[i] = Number.parseInt(hex.slice(j, j + 2), 16);
array[i] = parseHexByte(hex.slice(j, j + 2));
}

@@ -522,5 +535,2 @@ return array;

}
function parseByte(str) {
return Number.parseInt(str, 16) * 2;
}
function normalizeScalar(num) {

@@ -644,3 +654,3 @@ if (typeof num === 'number' && num > 0 && Number.isSafeInteger(num))

}
function _abc6979(msgHash, privateKey) {
function _abc6979(msgHash, privateKey, extraEntropy) {
if (msgHash == null)

@@ -656,15 +666,22 @@ throw new Error(`sign: expected valid msgHash, not "${msgHash}"`);

const b1 = Uint8Array.from([0x01]);
return { h1, h1n, x, v, k, b0, b1 };
let xh1 = concatBytes(x, h1);
if (extraEntropy != null) {
const e = pad32b(typeof extraEntropy === 'string' ? hexToNumber(extraEntropy) : bytesToNumber(extraEntropy));
if (e.length !== 32)
throw new Error('secp256k1: Expected 32 bytes of extra data');
xh1 = concatBytes(xh1, e);
}
return { xh1, h1n, v, k, b0, b1 };
}
async function getQRSrfc6979(msgHash, privateKey) {
async function getQRSrfc6979(msgHash, privateKey, extraEntropy) {
const privKey = normalizePrivateKey(privateKey);
let { h1, h1n, x, v, k, b0, b1 } = _abc6979(msgHash, privKey);
let { xh1, h1n, v, k, b0, b1 } = _abc6979(msgHash, privKey, extraEntropy);
const hmac = exports.utils.hmacSha256;
k = await hmac(k, v, b0, x, h1);
k = await hmac(k, v, b0, xh1);
v = await hmac(k, v);
k = await hmac(k, v, b1, x, h1);
k = await hmac(k, v, b1, xh1);
v = await hmac(k, v);
for (let i = 0; i < 1000; i++) {
v = await hmac(k, v);
let qrs = calcQRSFromK(v, h1n, privKey);
const qrs = calcQRSFromK(v, h1n, privKey);
if (qrs)

@@ -677,17 +694,17 @@ return qrs;

}
function getQRSrfc6979Sync(msgHash, privateKey) {
function getQRSrfc6979Sync(msgHash, privateKey, extraEntropy) {
const privKey = normalizePrivateKey(privateKey);
let { h1, h1n, x, v, k, b0, b1 } = _abc6979(msgHash, privKey);
let { xh1, h1n, v, k, b0, b1 } = _abc6979(msgHash, privKey, extraEntropy);
const hmac = exports.utils.hmacSha256Sync;
if (!hmac)
throw new Error('utils.hmacSha256Sync is undefined, you need to set it');
k = hmac(k, v, b0, x, h1);
k = hmac(k, v, b0, xh1);
if (k instanceof Promise)
throw new Error('To use sync sign(), ensure utils.hmacSha256 is sync');
v = hmac(k, v);
k = hmac(k, v, b1, x, h1);
k = hmac(k, v, b1, xh1);
v = hmac(k, v);
for (let i = 0; i < 1000; i++) {
v = hmac(k, v);
let qrs = calcQRSFromK(v, h1n, privKey);
const qrs = calcQRSFromK(v, h1n, privKey);
if (qrs)

@@ -713,3 +730,3 @@ return qrs;

return;
return [q, r, s];
return { q, r, s };
}

@@ -755,17 +772,15 @@ function normalizePrivateKey(key) {

}
else {
try {
return Signature.fromDER(signature);
}
catch (error) {
return Signature.fromCompact(signature);
}
}
function getPublicKey(privateKey, isCompressed = false) {
const point = Point.fromPrivateKey(privateKey);
if (typeof privateKey === 'string') {
return point.toHex(isCompressed);
}
return point.toRawBytes(isCompressed);
return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed);
}
exports.getPublicKey = getPublicKey;
function recoverPublicKey(msgHash, signature, recovery) {
const point = Point.fromSignature(msgHash, signature, recovery);
return typeof msgHash === 'string' ? point.toHex() : point.toRawBytes();
return Point.fromSignature(msgHash, signature, recovery).toRawBytes();
}

@@ -792,34 +807,28 @@ exports.recoverPublicKey = recoverPublicKey;

b.assertValidity();
const shared = b.multiply(normalizePrivateKey(privateA));
return typeof privateA === 'string'
? shared.toHex(isCompressed)
: shared.toRawBytes(isCompressed);
return b.multiply(normalizePrivateKey(privateA)).toRawBytes(isCompressed);
}
exports.getSharedSecret = getSharedSecret;
function QRSToSig(qrs, opts, str = false) {
const [q, r, s] = qrs;
let { canonical, der, recovered } = opts;
function QRSToSig(qrs, opts) {
const { q, r, s } = qrs;
const defaultOpts = { canonical: true, der: true };
let { canonical, der, recovered } = Object.assign(defaultOpts, opts);
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n);
let adjustedS = s;
const HIGH_NUMBER = CURVE.n >> _1n;
if (s > HIGH_NUMBER && canonical) {
adjustedS = CURVE.n - s;
let sig = new Signature(r, s);
if (canonical && sig.hasHighS()) {
sig = sig.normalizeS();
recovery ^= 1;
}
const sig = new Signature(r, adjustedS);
sig.assertValidity();
const hex = der === false ? sig.toCompactHex() : sig.toDERHex();
const hashed = str ? hex : hexToBytes(hex);
const hashed = der ? sig.toDERRawBytes() : sig.toCompactRawBytes();
return recovered ? [hashed, recovery] : hashed;
}
async function sign(msgHash, privKey, opts = {}) {
return QRSToSig(await getQRSrfc6979(msgHash, privKey), opts, typeof msgHash === 'string');
return QRSToSig(await getQRSrfc6979(msgHash, privKey, opts.extraEntropy), opts);
}
exports.sign = sign;
function signSync(msgHash, privKey, opts = {}) {
return QRSToSig(getQRSrfc6979Sync(msgHash, privKey), opts, typeof msgHash === 'string');
return QRSToSig(getQRSrfc6979Sync(msgHash, privKey, opts.extraEntropy), opts);
}
exports.signSync = signSync;
function verify(signature, msgHash, publicKey) {
const { n } = CURVE;
const vopts = { strict: true };
function verify(signature, msgHash, publicKey, opts = vopts) {
let sig;

@@ -833,6 +842,15 @@ try {

const { r, s } = sig;
if (opts.strict && sig.hasHighS())
return false;
const h = truncateHash(msgHash);
if (h === _0n)
return false;
const pubKey = JacobianPoint.fromAffine(normalizePublicKey(publicKey));
let pubKey;
try {
pubKey = JacobianPoint.fromAffine(normalizePublicKey(publicKey));
}
catch (error) {
return false;
}
const { n } = CURVE;
const s1 = invert(s, n);

@@ -886,4 +904,3 @@ const u1 = mod(h * s1, n);

function schnorrGetPublicKey(privateKey) {
const P = Point.fromPrivateKey(privateKey);
return typeof privateKey === 'string' ? P.toHexX() : P.toRawX();
return Point.fromPrivateKey(privateKey).toRawX();
}

@@ -916,3 +933,3 @@ async function schnorrSign(msgHash, privateKey, auxRand = exports.utils.randomBytes()) {

throw new Error('sign: Invalid signature produced');
return typeof msgHash === 'string' ? sig.toHex() : sig.toRawBytes();
return sig.toRawBytes();
}

@@ -974,2 +991,3 @@ async function schnorrVerify(signature, msgHash, publicKey) {

},
bytesToHex,
sha256: async (message) => {

@@ -998,3 +1016,3 @@ if (crypto.web) {

const hash = createHmac('sha256', key);
for (let message of messages) {
for (const message of messages) {
hash.update(message);

@@ -1001,0 +1019,0 @@ }

{
"name": "@noble/secp256k1",
"version": "1.3.4",
"version": "1.4.0",
"description": "Fastest JS implementation of secp256k1. Independently audited, high-security, 0-dependency ECDSA & Schnorr signatures",

@@ -19,10 +19,4 @@ "files": [

},
"jest": {
"testRegex": "/test/.*?\\.ts",
"transform": {
"^.+\\.ts$": "ts-jest"
}
},
"author": "Paul Miller (https://paulmillr.com)",
"homepage": "https://paulmillr.com/posts/noble-secp256k1-fast-ecc/",
"homepage": "https://paulmillr.com/noble/",
"repository": {

@@ -37,13 +31,14 @@ "type": "git",

"devDependencies": {
"@noble/hashes": "^0.5.6",
"@rollup/plugin-commonjs": "^21.0.0",
"@rollup/plugin-node-resolve": "^13.0.0",
"@types/jest": "^27",
"@types/node": "^16.3.3",
"@types/node": "^16",
"fast-check": "^2.14.0",
"jest": "^27",
"jest": "^27.4.5",
"micro-bmark": "^0.1.3",
"noble-hashes": "^0.2.0",
"prettier": "^2.2.1",
"rollup": "^2.53.2",
"ts-jest": "^27",
"typescript": "~4.3.5"
"prettier": "^2.5.1",
"rollup": "^2.62.0",
"ts-jest": "^27.1.2",
"typescript": "4.5.4"
},

@@ -76,3 +71,9 @@ "keywords": [

"./index.d.ts": "./lib/index.d.ts"
},
"jest": {
"testRegex": "/test/.*?\\.ts",
"transform": {
"^.+\\.ts$": "ts-jest"
}
}
}

@@ -17,3 +17,3 @@ # noble-secp256k1 ![Node CI](https://github.com/paulmillr/noble-secp256k1/workflows/Node%20CI/badge.svg) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)

- All releases are signed with PGP keys
- Check out all libraries:
- Check out [homepage](https://paulmillr.com/noble/) & all libraries:
[secp256k1](https://github.com/paulmillr/noble-secp256k1),

@@ -45,4 +45,4 @@ [ed25519](https://github.com/paulmillr/noble-ed25519),

// Canonical signatures
const signatureC = await secp.sign(messageHash, privateKey, { canonical: true });
// Signatures compatible with openssl
const signatureS = await secp.sign(messageHash, privateKey, { canonical: false });

@@ -56,9 +56,24 @@ // Supports Schnorr signatures

Deno:
To use the module with [Deno](https://deno.land),
you will need [import map](https://deno.land/manual/linking_to_external_code/import_maps):
```typescript
import * as secp from "https://deno.land/x/secp256k1/mod.ts";
const publicKey = secp.getPublicKey("6b911fd37cdf5c81d4c0adb1ab7fa822ed253ab0ad9aa18d77257c88b29b718e");
```
- `deno run --import-map=imports.json app.ts`
- `app.ts`
```typescript
import * as secp from "https://deno.land/x/secp256k1/mod.ts";
const publicKey = secp.getPublicKey(secp.utils.randomPrivateKey());
console.log(publicKey);
```
- `imports.json`
```json
{
"imports": {
"crypto": "https://deno.land/std@0.119.0/node/crypto.ts"
}
}
```
## API

@@ -68,4 +83,4 @@

- [`getSharedSecret(privateKeyA, publicKeyB)`](#getsharedsecretprivatekeya-publickeyb)
- [`sign(hash, privateKey)`](#signhash-privatekey)
- [`verify(signature, hash, publicKey)`](#verifysignature-hash-publickey)
- [`sign(msgHash, privateKey)`](#signmsghash-privatekey)
- [`verify(signature, msgHash, publicKey)`](#verifysignature-msghash-publickey)
- [`recoverPublicKey(hash, signature, recovery)`](#recoverpublickeyhash-signature-recovery)

@@ -79,5 +94,3 @@ - [`schnorr.getPublicKey(privateKey)`](#schnorrgetpublickeyprivatekey)

```typescript
function getPublicKey(privateKey: Uint8Array, isCompressed?: false): Uint8Array;
function getPublicKey(privateKey: string, isCompressed?: false): string;
function getPublicKey(privateKey: bigint): Uint8Array;
function getPublicKey(privateKey: Uint8Array | string | bigint, isCompressed = false): Uint8Array;
```

@@ -93,5 +106,3 @@ `privateKey` will be used to generate public key.

```typescript
function getSharedSecret(privateKeyA: Uint8Array, publicKeyB: Uint8Array): Uint8Array;
function getSharedSecret(privateKeyA: string, publicKeyB: string): string;
function getSharedSecret(privateKeyA: bigint, publicKeyB: Point): Uint8Array;
function getSharedSecret(privateKeyA: Uint8Array | string | bigint, publicKeyB: Uint8Array | string | Point): Uint8Array;
```

@@ -107,10 +118,9 @@

##### `sign(hash, privateKey)`
##### `sign(msgHash, privateKey)`
```typescript
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]>;
function sign(msgHash: Uint8Array | string, privateKey: Uint8Array | string, opts?: Options): Promise<Uint8Array>;
function sign(msgHash: Uint8Array | string, privateKey: Uint8Array | string, opts?: Options): Promise<[Uint8Array, number]>;
```
Generates deterministic ECDSA signature as per RFC6979.
Generates low-s deterministic ECDSA signature as per RFC6979.

@@ -121,3 +131,6 @@ - `msgHash: Uint8Array | string` - message hash which would be signed

- `options?.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 order
- `options?.canonical: boolean = true` - whether a signature `s` should be no more than 1/2 prime order.
`true` makes signatures compatible with libsecp256k1,
`false` makes signatures compatible with openssl
- `options?.extraEntropy: Uint8Array | string` - additional entropy `k'` for deterministic signature, follows section 3.6 of RFC6979. [Could be reused](https://crypto.stackexchange.com/questions/97911/reusing-additional-data-k-nonce-from-rfc6979-ecdsa).
- `options?.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)

@@ -130,4 +143,4 @@

```ts
const { hmac } = require('noble-hashes/lib/hmac');
const { sha256 } = require('noble-hashes/lib/sha256');
const { hmac } = require('@noble/hashes/hmac');
const { sha256 } = require('@noble/hashes/sha256');
secp256k1.utils.hmacSha256Sync = (key: Uint8Array, ...msgs: Uint8Array[]) => {

@@ -143,6 +156,6 @@ const h = hmac.create(sha256, key);

##### `verify(signature, hash, publicKey)`
##### `verify(signature, msgHash, publicKey)`
```typescript
function verify(signature: Uint8Array, msgHash: Uint8Array, publicKey: Uint8Array): boolean
function verify(signature: string, msgHash: string, publicKey: string): boolean
function verify(signature: Uint8Array | string, msgHash: Uint8Array | string, publicKey: Uint8Array | string): boolean
function verify(signature: Signature, msgHash: Uint8Array | string, publicKey: Point): boolean
```

@@ -152,2 +165,6 @@ - `signature: Uint8Array | string | { r: bigint, s: bigint }` - object returned by the `sign` function

- `publicKey: Uint8Array | string | Point` - e.g. that was generated from `privateKey` by `getPublicKey`
- `options?: Options` - *optional* object related to signature value and format
- `options?.strict: boolean = true` - whether a signature `s` should be no more than 1/2 prime order.
`true` makes signatures compatible with libsecp256k1,
`false` makes signatures compatible with openssl
- Returns `boolean`: `true` if `signature == hash`; otherwise `false`

@@ -157,4 +174,3 @@

```typescript
function recoverPublicKey(msgHash: Uint8Array, signature: Uint8Array, recovery: number): Uint8Array | undefined;
function recoverPublicKey(msgHash: string, signature: string, recovery: number): string | undefined;
function recoverPublicKey(msgHash: Uint8Array | string, signature: Uint8Array | string, recovery: number): Uint8Array | undefined;
```

@@ -172,4 +188,3 @@ - `msgHash: Uint8Array | string` - message hash which would be signed

```typescript
function schnorrGetPublicKey(privateKey: Uint8Array): Uint8Array;
function schnorrGetPublicKey(privateKey: string): string;
function schnorrGetPublicKey(privateKey: Uint8Array | string): Uint8Array;
```

@@ -179,8 +194,7 @@

Specifically, its *y* coordinate may be flipped. See BIP0340 for clarification.
Specifically, its *y* coordinate may be flipped. See BIP340 for clarification.
##### `schnorr.sign(hash, privateKey)`
```typescript
function schnorrSign(msgHash: Uint8Array, privateKey: Uint8Array, auxilaryRandom?: Uint8Array): Promise<Uint8Array>;
function schnorrSign(msgHash: string, privateKey: string, auxilaryRandom?: string): Promise<string>;
function schnorrSign(msgHash: Uint8Array | string, privateKey: Uint8Array | string, auxilaryRandom?: Uint8Array): Promise<Uint8Array>;
```

@@ -216,6 +230,14 @@

###### `utils.hmacSha256Sync`
###### `utils.bytesToHex(bytes: Uint8Array): string`
The function is not defined by default, but could be used to implement `signSync` method (see above).
Converts a byte array to hex string.
###### `utils.sha256` and `utils.hmacSha256`
Asynchronous methods that calculate `SHA256` and `HMAC-SHA256`. Use browser built-ins by default.
###### `utils.sha256Sync` and `utils.hmacSha256Sync`
The functions are not defined by default, but could be used to implement `signSync` method (see above).
###### `utils.precompute(W = 8, point = BASE_POINT): Point`

@@ -269,2 +291,4 @@

static fromCompact(hex: Uint8Array | string);
assertValidity(): void;
hasHighS(): boolean; // high-S sigs cannot be produced using { canonical: true }
toDERRawBytes(): Uint8Array;

@@ -290,9 +314,9 @@ toDERHex(): string;

Benchmarks measured with Apple M1.
Benchmarks measured with Apple M1 on MacOS 12.
getPublicKey(utils.randomPrivateKey()) x 6,121 ops/sec @ 163μs/op
sign x 4,679 ops/sec @ 213μs/op
sign x 4,789 ops/sec @ 208μ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 aka ecdh x 558 ops/sec @ 1790μs/op
getSharedSecret (precomputed) x 7,105 ops/sec @ 140μs/op

@@ -299,0 +323,0 @@ Point.fromHex (decompression) x 12,171 ops/sec @ 82μs/op

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