Socket
Socket
Sign inDemoInstall

@noble/curves

Package Overview
Dependencies
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@noble/curves - npm Package Compare versions

Comparing version 0.3.2 to 0.4.0

lib/bls.d.ts

16

lib/edwards.d.ts
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import * as mod from './modular.js';
import { BasicCurve, Hex, PrivKey } from './utils.js';

@@ -10,7 +11,7 @@ import { Group, GroupConstructor } from './group.js';

};
export declare type CurveType = BasicCurve & {
export declare type CurveType = BasicCurve<bigint> & {
a: bigint;
d: bigint;
hash: CHash;
randomBytes?: (bytesLength?: number) => Uint8Array;
randomBytes: (bytesLength?: number) => Uint8Array;
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array;

@@ -27,11 +28,14 @@ domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array;

readonly nByteLength: number;
readonly P: bigint;
readonly Fp: mod.Field<bigint>;
readonly n: bigint;
readonly h: bigint;
readonly hEff?: bigint | undefined;
readonly Gx: bigint;
readonly Gy: bigint;
readonly wrapPrivateKey?: boolean | undefined;
readonly allowInfinityPoint?: boolean | undefined;
readonly a: bigint;
readonly d: bigint;
readonly hash: CHash;
randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly adjustScalarBytes?: ((bytes: Uint8Array) => Uint8Array) | undefined;

@@ -97,4 +101,4 @@ readonly domain?: ((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array) | undefined;

utils: {
mod: (a: bigint, b?: bigint) => bigint;
invert: (number: bigint, modulo?: bigint) => bigint;
mod: (a: bigint) => bigint;
invert: (number: bigint) => bigint;
randomPrivateKey: () => Uint8Array;

@@ -101,0 +105,0 @@ getExtendedPublicKey: (key: PrivKey) => {

@@ -0,3 +1,6 @@

"use strict";
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// Implementation of Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
Object.defineProperty(exports, "__esModule", { value: true });
exports.twistedEdwards = void 0;
// Differences from @noble/ed25519 1.7:

@@ -10,5 +13,5 @@ // 1. Different field element lengths in ed448:

// 5. Domain function was no-op for ed25519, but adds some data even with empty context for ed448
import * as mod from './modular.js';
import { bytesToHex, concatBytes, ensureBytes, numberToBytesLE, bytesToNumberLE, hashToPrivateScalar, validateOpts as utilOpts, randomBytes as utilRandomBytes, } from './utils.js'; // TODO: import * as u from './utils.js'?
import { wNAF } from './group.js';
const mod = require("./modular.js");
const utils_js_1 = require("./utils.js"); // TODO: import * as u from './utils.js'?
const group_js_1 = require("./group.js");
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n

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

function validateOpts(curve) {
const opts = utilOpts(curve);
const opts = (0, utils_js_1.validateOpts)(curve);
if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))

@@ -29,3 +32,7 @@ throw new Error('Invalid hash function');

}
for (const fn of ['adjustScalarBytes', 'domain', 'randomBytes', 'uvRatio']) {
for (const fn of ['randomBytes']) {
if (typeof opts[fn] !== 'function')
throw new Error(`Invalid ${fn} function`);
}
for (const fn of ['adjustScalarBytes', 'domain', 'uvRatio']) {
if (opts[fn] === undefined)

@@ -37,9 +44,10 @@ continue; // Optional

// Set defaults
return Object.freeze({ randomBytes: utilRandomBytes, ...opts });
return Object.freeze({ ...opts });
}
// NOTE: it is not generic twisted curve for now, but ed25519/ed448 generic implementation
export function twistedEdwards(curveDef) {
function twistedEdwards(curveDef) {
const CURVE = validateOpts(curveDef);
const Fp = CURVE.Fp;
const CURVE_ORDER = CURVE.n;
const fieldLen = CURVE.nByteLength; // 32 (length of one field element)
const fieldLen = Fp.BYTES; // 32 (length of one field element)
if (fieldLen > 2048)

@@ -51,8 +59,8 @@ throw new Error('Field lengths over 2048 are not supported');

// Function overrides
const { P, randomBytes } = CURVE;
const modP = (a) => mod.mod(a, P);
const { randomBytes } = CURVE;
const modP = Fp.create;
// sqrt(u/v)
function _uvRatio(u, v) {
try {
const value = mod.sqrt(u * mod.invert(v, P), P);
const value = Fp.sqrt(u * Fp.invert(v));
return { isValid: true, value };

@@ -97,3 +105,3 @@ }

static toAffineBatch(points) {
const toInv = mod.invertBatch(points.map((p) => p.z), P);
const toInv = Fp.invertBatch(points.map((p) => p.z));
return points.map((p, i) => p.toAffine(toInv[i]));

@@ -238,3 +246,3 @@ }

if (invZ == null)
invZ = is0 ? _8n : mod.invert(z, P); // 8 was chosen arbitrarily
invZ = is0 ? _8n : Fp.invert(z); // 8 was chosen arbitrarily
const ax = modP(x * invZ);

@@ -252,3 +260,3 @@ const ay = modP(y * invZ);

ExtendedPoint.ZERO = new ExtendedPoint(_0n, _1n, _1n, _0n);
const wnaf = wNAF(ExtendedPoint, groupLen * 8);
const wnaf = (0, group_js_1.wNAF)(ExtendedPoint, groupLen * 8);
function assertExtPoint(other) {

@@ -276,4 +284,4 @@ if (!(other instanceof ExtendedPoint))

static fromHex(hex, strict = true) {
const { d, P, a } = CURVE;
hex = ensureBytes(hex, fieldLen);
const { d, a } = CURVE;
hex = (0, utils_js_1.ensureBytes)(hex, fieldLen);
// 1. First, interpret the string as an integer in little-endian

@@ -287,4 +295,4 @@ // representation. Bit 255 of this number is the least significant

normed[fieldLen - 1] = lastByte & ~0x80;
const y = bytesToNumberLE(normed);
if (strict && y >= P)
const y = (0, utils_js_1.bytesToNumberLE)(normed);
if (strict && y >= Fp.ORDER)
throw new Error('Expected 0 < hex < P');

@@ -324,3 +332,3 @@ if (!strict && y >= maxGroupElement)

toRawBytes() {
const bytes = numberToBytesLE(this.y, fieldLen);
const bytes = (0, utils_js_1.numberToBytesLE)(this.y, fieldLen);
bytes[fieldLen - 1] |= this.x & _1n ? 0x80 : 0;

@@ -331,3 +339,3 @@ return bytes;

toHex() {
return bytesToHex(this.toRawBytes());
return (0, utils_js_1.bytesToHex)(this.toRawBytes());
}

@@ -379,5 +387,5 @@ isTorsionFree() {

static fromHex(hex) {
const bytes = ensureBytes(hex, 2 * fieldLen);
const bytes = (0, utils_js_1.ensureBytes)(hex, 2 * fieldLen);
const r = Point.fromHex(bytes.slice(0, fieldLen), false);
const s = bytesToNumberLE(bytes.slice(fieldLen, 2 * fieldLen));
const s = (0, utils_js_1.bytesToNumberLE)(bytes.slice(fieldLen, 2 * fieldLen));
return new Signature(r, s);

@@ -394,6 +402,6 @@ }

toRawBytes() {
return concatBytes(this.r.toRawBytes(), numberToBytesLE(this.s, fieldLen));
return (0, utils_js_1.concatBytes)(this.r.toRawBytes(), (0, utils_js_1.numberToBytesLE)(this.s, fieldLen));
}
toHex() {
return bytesToHex(this.toRawBytes());
return (0, utils_js_1.bytesToHex)(this.toRawBytes());
}

@@ -403,3 +411,3 @@ }

function modlLE(hash) {
return mod.mod(bytesToNumberLE(hash), CURVE_ORDER);
return mod.mod((0, utils_js_1.bytesToNumberLE)(hash), CURVE_ORDER);
}

@@ -433,4 +441,4 @@ /**

typeof key === 'bigint' || typeof key === 'number'
? numberToBytesLE(normalizeScalar(key, maxGroupElement), groupLen)
: ensureBytes(key);
? (0, utils_js_1.numberToBytesLE)(normalizeScalar(key, maxGroupElement), groupLen)
: (0, utils_js_1.ensureBytes)(key);
if (key.length !== groupLen)

@@ -468,3 +476,3 @@ throw new Error(`Expected ${groupLen} bytes, got ${key.length}`);

function hashDomainToScalar(message, context = EMPTY) {
context = ensureBytes(context);
context = (0, utils_js_1.ensureBytes)(context);
return modlLE(CURVE.hash(domain(message, context, !!CURVE.preHash)));

@@ -474,9 +482,9 @@ }

function sign(message, privateKey, context) {
message = ensureBytes(message);
message = (0, utils_js_1.ensureBytes)(message);
if (CURVE.preHash)
message = CURVE.preHash(message);
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privateKey);
const r = hashDomainToScalar(concatBytes(prefix, message), context);
const r = hashDomainToScalar((0, utils_js_1.concatBytes)(prefix, message), context);
const R = Point.BASE.multiply(r); // R = rG
const k = hashDomainToScalar(concatBytes(R.toRawBytes(), pointBytes, message), context); // k = hash(R+P+msg)
const k = hashDomainToScalar((0, utils_js_1.concatBytes)(R.toRawBytes(), pointBytes, message), context); // k = hash(R+P+msg)
const s = mod.mod(r + k * scalar, CURVE_ORDER); // s = r + kp

@@ -495,3 +503,3 @@ return new Signature(R, s).toRawBytes();

function verify(sig, message, publicKey, context) {
message = ensureBytes(message);
message = (0, utils_js_1.ensureBytes)(message);
if (CURVE.preHash)

@@ -521,3 +529,3 @@ message = CURVE.preHash(message);

const SB = ExtendedPoint.BASE.multiplyUnsafe(s);
const k = hashDomainToScalar(concatBytes(r.toRawBytes(), publicKey.toRawBytes(), message), context);
const k = hashDomainToScalar((0, utils_js_1.concatBytes)(r.toRawBytes(), publicKey.toRawBytes(), message), context);
const kA = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(k);

@@ -533,7 +541,7 @@ const RkA = ExtendedPoint.fromAffine(r).add(kA);

mod: modP,
invert: (a, m = CURVE.P) => mod.invert(a, m),
invert: Fp.invert,
/**
* Not needed for ed25519 private keys. Needed if you use scalars directly (rare).
*/
hashToPrivateScalar: (hash) => hashToPrivateScalar(hash, CURVE_ORDER, true),
hashToPrivateScalar: (hash) => (0, utils_js_1.hashToPrivateScalar)(hash, CURVE_ORDER, true),
/**

@@ -568,1 +576,2 @@ * ed25519 private keys are uniform 32-bit strings. We do not need to check for

}
exports.twistedEdwards = twistedEdwards;

@@ -0,1 +1,4 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.wNAF = void 0;
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

@@ -6,3 +9,3 @@ // Default group related functions

// Not big, but pretty complex and it is easy to break stuff. To avoid too much copy paste
export function wNAF(c, bits) {
function wNAF(c, bits) {
const constTimeNegate = (condition, item) => {

@@ -13,4 +16,2 @@ const neg = item.negate();

const opts = (W) => {
if (256 % W)
throw new Error('Invalid precomputation window, must be power of 2');
const windows = Math.ceil(bits / W) + 1; // +1, because

@@ -64,2 +65,4 @@ const windowSize = 2 ** (W - 1); // -1 because we skip zero

wNAF(W, precomputes, n) {
// TODO: maybe check that scalar is less than group order? wNAF will fail otherwise
// But need to carefully remove other checks before wNAF. ORDER == bits here
const { windows, windowSize } = opts(W);

@@ -111,1 +114,2 @@ let p = c.ZERO;

}
exports.wNAF = wNAF;

@@ -1,2 +0,1 @@

/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
export declare function mod(a: bigint, b: bigint): bigint;

@@ -13,17 +12,2 @@ /**

/**
* Division over finite field.
* `a/b mod p == a * invert(b) mod p`
*/
export declare function div(numerator: bigint, denominator: bigint, modulo: bigint): bigint;
/**
* Takes a list of numbers, efficiently inverts all of them.
* @param nums list of bigints
* @param p modulo
* @returns list of inverted bigints
* @example
* invertBatch([1n, 2n, 4n], 21n);
* // => [1n, 11n, 16n]
*/
export declare function invertBatch(nums: bigint[], modulo: bigint): bigint[];
/**
* Calculates Legendre symbol (a | p), which denotes the value of a^((p-1)/2) (mod p).

@@ -34,3 +18,3 @@ * * (a | p) ≡ 1 if a is a square (mod p)

*/
export declare function legendre(num: bigint, P: bigint): bigint;
export declare function legendre(num: bigint, fieldPrime: bigint): bigint;
/**

@@ -41,1 +25,37 @@ * Calculates square root of a number in a finite field.

export declare const isNegativeLE: (num: bigint, modulo: bigint) => boolean;
export interface Field<T> {
ORDER: bigint;
BYTES: number;
BITS: number;
MASK: bigint;
ZERO: T;
ONE: T;
create: (num: T) => T;
isValid: (num: T) => boolean;
isZero: (num: T) => boolean;
negate(num: T): T;
invert(num: T): T;
sqrt(num: T): T;
square(num: T): T;
equals(lhs: T, rhs: T): boolean;
add(lhs: T, rhs: T): T;
subtract(lhs: T, rhs: T): T;
multiply(lhs: T, rhs: T | bigint): T;
pow(lhs: T, power: bigint): T;
div(lhs: T, rhs: T | bigint): T;
addN(lhs: T, rhs: T): T;
subtractN(lhs: T, rhs: T): T;
multiplyN(lhs: T, rhs: T | bigint): T;
squareN(num: T): T;
isOdd?(num: T): boolean;
legendre?(num: T): T;
pow(lhs: T, power: bigint): T;
invertBatch: (lst: T[]) => T[];
toBytes(num: T): Uint8Array;
fromBytes(bytes: Uint8Array): T;
}
export declare function validateField<T>(field: Field<T>): void;
export declare function FpPow<T>(f: Field<T>, num: T, power: bigint): T;
export declare function FpInvertBatch<T>(f: Field<T>, nums: T[]): T[];
export declare function FpDiv<T>(f: Field<T>, lhs: T, rhs: T | bigint): T;
export declare function Fp(ORDER: bigint, bitLen?: number, isLE?: boolean, redef?: Partial<Field<bigint>>): Readonly<Field<bigint>>;

@@ -0,2 +1,6 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Fp = exports.FpDiv = exports.FpInvertBatch = exports.FpPow = exports.validateField = exports.isNegativeLE = exports.sqrt = exports.legendre = exports.invert = exports.pow2 = exports.pow = exports.mod = void 0;
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
const utils = require("./utils.js");
// Utilities for modular arithmetics

@@ -7,6 +11,7 @@ const _0n = BigInt(0);

// Calculates a modulo b
export function mod(a, b) {
function mod(a, b) {
const result = a % b;
return result >= _0n ? result : b + result;
}
exports.mod = mod;
/**

@@ -18,3 +23,4 @@ * Efficiently exponentiate num to power and do modular division.

*/
export function pow(num, power, modulo) {
// TODO: use field version && remove
function pow(num, power, modulo) {
if (modulo <= _0n || power < _0n)

@@ -33,4 +39,6 @@ throw new Error('Expected power/modulo > 0');

}
exports.pow = pow;
// Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
export function pow2(x, power, modulo) {
// TODO: Fp version?
function pow2(x, power, modulo) {
let res = x;

@@ -43,4 +51,5 @@ while (power-- > _0n) {

}
exports.pow2 = pow2;
// Inverses number over modulo
export function invert(number, modulo) {
function invert(number, modulo) {
if (number === _0n || modulo <= _0n) {

@@ -67,41 +76,4 @@ throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);

}
exports.invert = invert;
/**
* Division over finite field.
* `a/b mod p == a * invert(b) mod p`
*/
export function div(numerator, denominator, modulo) {
const num = mod(numerator, modulo);
const iden = invert(denominator, modulo);
return mod(num * iden, modulo);
}
/**
* Takes a list of numbers, efficiently inverts all of them.
* @param nums list of bigints
* @param p modulo
* @returns list of inverted bigints
* @example
* invertBatch([1n, 2n, 4n], 21n);
* // => [1n, 11n, 16n]
*/
export function invertBatch(nums, modulo) {
const scratch = new Array(nums.length);
// Walk from first to last, multiply them by each other MOD p
const lastMultiplied = nums.reduce((acc, num, i) => {
if (num === _0n)
return acc;
scratch[i] = acc;
return mod(acc * num, modulo);
}, _1n);
// Invert last element
const inverted = invert(lastMultiplied, modulo);
// Walk from last to first, multiply them by inverted each other MOD p
nums.reduceRight((acc, num, i) => {
if (num === _0n)
return acc;
scratch[i] = mod(acc * scratch[i], modulo);
return mod(acc * num, modulo);
}, inverted);
return scratch;
}
/**
* Calculates Legendre symbol (a | p), which denotes the value of a^((p-1)/2) (mod p).

@@ -112,9 +84,11 @@ * * (a | p) ≡ 1 if a is a square (mod p)

*/
export function legendre(num, P) {
return pow(num, (P - _1n) / _2n, P);
function legendre(num, fieldPrime) {
return pow(num, (fieldPrime - _1n) / _2n, fieldPrime);
}
exports.legendre = legendre;
/**
* Calculates square root of a number in a finite field.
*/
export function sqrt(number, modulo) {
// TODO: rewrite as generic Fp function && remove bls versions
function sqrt(number, modulo) {
// prettier-ignore

@@ -127,4 +101,13 @@ const _3n = BigInt(3), _4n = BigInt(4), _5n = BigInt(5), _8n = BigInt(8);

// sqrt n = n^((P+1)/4)
if (P % _4n === _3n)
return pow(n, p1div4, P);
if (P % _4n === _3n) {
// Not all roots possible!
// const ORDER =
// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
// const NUM = 72057594037927816n;
// TODO: fix sqrtMod in secp256k1
const root = pow(n, p1div4, P);
if (mod(root * root, modulo) !== number)
throw new Error('Cannot find square root');
return root;
}
// P ≡ 5 (mod 8)

@@ -140,3 +123,2 @@ if (P % _8n === _5n) {

// Other cases: Tonelli-Shanks algorithm
// Check whether n is square
if (legendre(n, P) !== _1n)

@@ -171,10 +153,124 @@ throw new Error('Cannot find square root');

}
exports.sqrt = sqrt;
// Little-endian check for first LE bit (last BE bit);
export const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
// An idea on modular arithmetic for bls12-381:
// const FIELD = {add, pow, sqrt, mul};
// Functions will take field elements, no need for an additional class
// Could be faster. 1 bigint field will just do operations and mod later:
// instead of 'r = mod(r * b, P)' we will write r = mul(r, b);
// Could be insecure without shape check, so it needs to be done.
// Functions could be inlined by JIT.
const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
exports.isNegativeLE = isNegativeLE;
// prettier-ignore
const FIELD_FIELDS = [
'create', 'isValid', 'isZero', 'negate', 'invert', 'sqrt', 'square',
'equals', 'add', 'subtract', 'multiply', 'pow', 'div',
'addN', 'subtractN', 'multiplyN', 'squareN'
];
function validateField(field) {
for (const i of ['ORDER', 'MASK']) {
if (typeof field[i] !== 'bigint')
throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
}
for (const i of ['BYTES', 'BITS']) {
if (typeof field[i] !== 'number')
throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
}
for (const i of FIELD_FIELDS) {
if (typeof field[i] !== 'function')
throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
}
}
exports.validateField = validateField;
// Generic field functions
function FpPow(f, num, power) {
// Should have same speed as pow for bigints
// TODO: benchmark!
if (power < _0n)
throw new Error('Expected power > 0');
if (power === _0n)
return f.ONE;
if (power === _1n)
return num;
let p = f.ONE;
let d = num;
while (power > _0n) {
if (power & _1n)
p = f.multiply(p, d);
d = f.square(d);
power >>= 1n;
}
return p;
}
exports.FpPow = FpPow;
function FpInvertBatch(f, nums) {
const tmp = new Array(nums.length);
// Walk from first to last, multiply them by each other MOD p
const lastMultiplied = nums.reduce((acc, num, i) => {
if (f.isZero(num))
return acc;
tmp[i] = acc;
return f.multiply(acc, num);
}, f.ONE);
// Invert last element
const inverted = f.invert(lastMultiplied);
// Walk from last to first, multiply them by inverted each other MOD p
nums.reduceRight((acc, num, i) => {
if (f.isZero(num))
return acc;
tmp[i] = f.multiply(acc, tmp[i]);
return f.multiply(acc, num);
}, inverted);
return tmp;
}
exports.FpInvertBatch = FpInvertBatch;
function FpDiv(f, lhs, rhs) {
return f.multiply(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.invert(rhs));
}
exports.FpDiv = FpDiv;
// NOTE: very fragile, always bench. Major performance points:
// - NonNormalized ops
// - Object.freeze
// - same shape of object (don't add/remove keys)
function Fp(ORDER, bitLen, isLE = false, redef = {}) {
if (ORDER <= _0n)
throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
const { nBitLength: BITS, nByteLength: BYTES } = utils.nLength(ORDER, bitLen);
if (BYTES > 2048)
throw new Error('Field lengths over 2048 bytes are not supported');
const sqrtP = (num) => sqrt(num, ORDER);
const f = Object.freeze({
ORDER,
BITS,
BYTES,
MASK: utils.bitMask(BITS),
ZERO: _0n,
ONE: _1n,
create: (num) => mod(num, ORDER),
isValid: (num) => {
if (typeof num !== 'bigint')
throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
return _0n <= num && num < ORDER;
},
isZero: (num) => num === _0n,
isOdd: (num) => (num & _1n) === _1n,
negate: (num) => mod(-num, ORDER),
equals: (lhs, rhs) => lhs === rhs,
square: (num) => mod(num * num, ORDER),
add: (lhs, rhs) => mod(lhs + rhs, ORDER),
subtract: (lhs, rhs) => mod(lhs - rhs, ORDER),
multiply: (lhs, rhs) => mod(lhs * rhs, ORDER),
pow: (num, power) => FpPow(f, num, power),
div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
// Same as above, but doesn't normalize
squareN: (num) => num * num,
addN: (lhs, rhs) => lhs + rhs,
subtractN: (lhs, rhs) => lhs - rhs,
multiplyN: (lhs, rhs) => lhs * rhs,
invert: (num) => invert(num, ORDER),
sqrt: redef.sqrt || sqrtP,
invertBatch: (lst) => FpInvertBatch(f, lst),
toBytes: (num) => isLE ? utils.numberToBytesLE(num, BYTES) : utils.numberToBytesBE(num, BYTES),
fromBytes: (bytes) => {
if (bytes.length !== BYTES)
throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`);
return isLE ? utils.bytesToNumberLE(bytes) : utils.bytesToNumberBE(bytes);
},
});
return Object.freeze(f);
}
exports.Fp = Fp;

@@ -1,5 +0,6 @@

import * as mod from './modular.js';
import { ensureBytes, numberToBytesLE, bytesToNumberLE,
// nLength,
} from './utils.js';
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.montgomery = void 0;
const mod = require("./modular.js");
const utils_js_1 = require("./utils.js");
const _0n = BigInt(0);

@@ -36,3 +37,3 @@ const _1n = BigInt(1);

// Uses only one coordinate instead of two
export function montgomery(curveDef) {
function montgomery(curveDef) {
const CURVE = validateOpts(curveDef);

@@ -148,6 +149,6 @@ const { P } = CURVE;

function encodeUCoordinate(u) {
return numberToBytesLE(modP(u), montgomeryBytes);
return (0, utils_js_1.numberToBytesLE)(modP(u), montgomeryBytes);
}
function decodeUCoordinate(uEnc) {
const u = ensureBytes(uEnc, montgomeryBytes);
const u = (0, utils_js_1.ensureBytes)(uEnc, montgomeryBytes);
// Section 5: When receiving such an array, implementations of X25519

@@ -158,9 +159,9 @@ // MUST mask the most significant bit in the final byte.

u[fieldLen - 1] &= 127; // 0b0111_1111
return bytesToNumberLE(u);
return (0, utils_js_1.bytesToNumberLE)(u);
}
function decodeScalar(n) {
const bytes = ensureBytes(n);
const bytes = (0, utils_js_1.ensureBytes)(n);
if (bytes.length !== montgomeryBytes && bytes.length !== fieldLen)
throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${bytes.length}`);
return bytesToNumberLE(adjustScalarBytes(bytes));
return (0, utils_js_1.bytesToNumberLE)(adjustScalarBytes(bytes));
}

@@ -193,1 +194,2 @@ // Multiply point u by scalar

}
exports.montgomery = montgomery;
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import * as mod from './modular.js';
export declare type Hex = Uint8Array | string;
export declare type PrivKey = Hex | bigint | number;
export declare type BasicCurve = {
P: bigint;
export declare type CHash = {
(message: Uint8Array | string): Uint8Array;
blockLen: number;
outputLen: number;
create(): any;
};
export declare type BasicCurve<T> = {
Fp: mod.Field<T>;
n: bigint;

@@ -10,9 +17,12 @@ nBitLength?: number;

h: bigint;
Gx: bigint;
Gy: bigint;
hEff?: bigint;
Gx: T;
Gy: T;
wrapPrivateKey?: boolean;
allowInfinityPoint?: boolean;
};
export declare function validateOpts<T extends BasicCurve>(curve: T): Readonly<{
export declare function validateOpts<FP, T>(curve: BasicCurve<FP> & T): Readonly<{
readonly nBitLength: number;
readonly nByteLength: number;
} & T>;
} & BasicCurve<FP> & T>;
export declare function bytesToHex(uint8a: Uint8Array): string;

@@ -32,7 +42,15 @@ export declare function numberToHexUnpadded(num: number | bigint): string;

};
/**
* Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
* and convert them into private scalar, with the modulo bias being neglible.
* As per FIPS 186 B.4.1.
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
* @param hash hash output from sha512, or a similar function
* @returns valid private scalar
*/
export declare function hashToPrivateScalar(hash: Hex, CURVE_ORDER: bigint, isLE?: boolean): bigint;
export declare function equalBytes(b1: Uint8Array, b2: Uint8Array): boolean;
/**
* Cryptographically secure PRNG
*/
export declare function randomBytes(bytesLength?: number): Uint8Array;
export declare function bitLen(n: bigint): number;
export declare const bitGet: (n: bigint, pos: number) => bigint;
export declare const bitSet: (n: bigint, pos: number, value: boolean) => bigint;
export declare const bitMask: (n: number) => bigint;

@@ -0,10 +1,19 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.bitMask = exports.bitSet = exports.bitGet = exports.bitLen = exports.equalBytes = exports.hashToPrivateScalar = exports.nLength = exports.concatBytes = exports.ensureBytes = exports.numberToBytesLE = exports.numberToBytesBE = exports.bytesToNumberLE = exports.bytesToNumberBE = exports.hexToBytes = exports.hexToNumber = exports.numberToHexUnpadded = exports.bytesToHex = exports.validateOpts = void 0;
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// The import here is via the package name. This is to ensure
// that exports mapping/resolution does fall into place.
import { crypto } from './crypto.js';
export function validateOpts(curve) {
for (const i of ['P', 'n', 'h', 'Gx', 'Gy']) {
const mod = require("./modular.js");
const _0n = BigInt(0);
const _1n = BigInt(1);
const _2n = BigInt(2);
function validateOpts(curve) {
mod.validateField(curve.Fp);
for (const i of ['n', 'h']) {
if (typeof curve[i] !== 'bigint')
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
}
if (!curve.Fp.isValid(curve.Gx))
throw new Error('Invalid generator X coordinate Fp element');
if (!curve.Fp.isValid(curve.Gy))
throw new Error('Invalid generator Y coordinate Fp element');
for (const i of ['nBitLength', 'nByteLength']) {

@@ -19,5 +28,5 @@ if (curve[i] === undefined)

}
import * as mod from './modular.js';
exports.validateOpts = validateOpts;
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
export function bytesToHex(uint8a) {
function bytesToHex(uint8a) {
if (!(uint8a instanceof Uint8Array))

@@ -32,7 +41,9 @@ throw new Error('Expected Uint8Array');

}
export function numberToHexUnpadded(num) {
exports.bytesToHex = bytesToHex;
function numberToHexUnpadded(num) {
const hex = num.toString(16);
return hex.length & 1 ? `0${hex}` : hex;
}
export function hexToNumber(hex) {
exports.numberToHexUnpadded = numberToHexUnpadded;
function hexToNumber(hex) {
if (typeof hex !== 'string') {

@@ -44,4 +55,5 @@ throw new TypeError('hexToNumber: expected string, got ' + typeof hex);

}
exports.hexToNumber = hexToNumber;
// Caching slows it down 2-3x
export function hexToBytes(hex) {
function hexToBytes(hex) {
if (typeof hex !== 'string') {

@@ -63,7 +75,9 @@ throw new TypeError('hexToBytes: expected string, got ' + typeof hex);

}
exports.hexToBytes = hexToBytes;
// Big Endian
export function bytesToNumberBE(bytes) {
function bytesToNumberBE(bytes) {
return hexToNumber(bytesToHex(bytes));
}
export function bytesToNumberLE(uint8a) {
exports.bytesToNumberBE = bytesToNumberBE;
function bytesToNumberLE(uint8a) {
if (!(uint8a instanceof Uint8Array))

@@ -73,5 +87,8 @@ throw new Error('Expected Uint8Array');

}
export const numberToBytesBE = (n, len) => hexToBytes(n.toString(16).padStart(len * 2, '0'));
export const numberToBytesLE = (n, len) => numberToBytesBE(n, len).reverse();
export function ensureBytes(hex, expectedLength) {
exports.bytesToNumberLE = bytesToNumberLE;
const numberToBytesBE = (n, len) => hexToBytes(n.toString(16).padStart(len * 2, '0'));
exports.numberToBytesBE = numberToBytesBE;
const numberToBytesLE = (n, len) => (0, exports.numberToBytesBE)(n, len).reverse();
exports.numberToBytesLE = numberToBytesLE;
function ensureBytes(hex, expectedLength) {
// Uint8Array.from() instead of hash.slice() because node.js Buffer

@@ -84,4 +101,5 @@ // is instance of Uint8Array, and its slice() creates **mutable** copy

}
exports.ensureBytes = ensureBytes;
// Copies several Uint8Arrays into one.
export function concatBytes(...arrays) {
function concatBytes(...arrays) {
if (!arrays.every((b) => b instanceof Uint8Array))

@@ -100,4 +118,5 @@ throw new Error('Uint8Array list expected');

}
exports.concatBytes = concatBytes;
// CURVE.n lengths
export function nLength(n, nBitLength) {
function nLength(n, nBitLength) {
// Bit size, byte size of CURVE.n

@@ -108,2 +127,3 @@ const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;

}
exports.nLength = nLength;
/**

@@ -117,4 +137,3 @@ * Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF

*/
const _1n = BigInt(1);
export function hashToPrivateScalar(hash, CURVE_ORDER, isLE = false) {
function hashToPrivateScalar(hash, CURVE_ORDER, isLE = false) {
hash = ensureBytes(hash);

@@ -128,3 +147,4 @@ const orderLen = nLength(CURVE_ORDER).nByteLength;

}
export function equalBytes(b1, b2) {
exports.hashToPrivateScalar = hashToPrivateScalar;
function equalBytes(b1, b2) {
// We don't care about timing attacks here

@@ -138,15 +158,22 @@ if (b1.length !== b2.length)

}
/**
* Cryptographically secure PRNG
*/
export function randomBytes(bytesLength = 32) {
if (crypto.web) {
return crypto.web.getRandomValues(new Uint8Array(bytesLength));
}
else if (crypto.node) {
return new Uint8Array(crypto.node.randomBytes(bytesLength).buffer);
}
else {
throw new Error("The environment doesn't have randomBytes function");
}
exports.equalBytes = equalBytes;
// Bit operations
// Amount of bits inside bigint (Same as n.toString(2).length)
function bitLen(n) {
let len;
for (len = 0; n > 0n; n >>= _1n, len += 1)
;
return len;
}
exports.bitLen = bitLen;
// Gets single bit at position. NOTE: first bit position is 0 (same as arrays)
// Same as !!+Array.from(n.toString(2)).reverse()[pos]
const bitGet = (n, pos) => (n >> BigInt(pos)) & 1n;
exports.bitGet = bitGet;
// Sets single bit at position
const bitSet = (n, pos, value) => n | ((value ? _1n : _0n) << BigInt(pos));
exports.bitSet = bitSet;
// Return mask for N bits (Same as BigInt(`0b${Array(i).fill('1').join('')}`))
// Not using ** operator with bigints for old engines.
const bitMask = (n) => (_2n << BigInt(n - 1)) - _1n;
exports.bitMask = bitMask;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import { BasicCurve, Hex, PrivKey, randomBytes as utilRandomBytes } from './utils.js';
import * as mod from './modular.js';
import { Hex, PrivKey } from './utils.js';
import * as utils from './utils.js';
import { htfOpts } from './hashToCurve.js';
import { Group, GroupConstructor } from './group.js';
export declare type CHash = {
(message: Uint8Array | string): Uint8Array;
blockLen: number;
outputLen: number;
create(): any;
};
declare type HmacFnSync = (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array;

@@ -20,33 +17,15 @@ declare type EndomorphismOpts = {

};
export declare type CurveType = BasicCurve & {
a: bigint;
b: bigint;
lowS?: boolean;
hash: CHash;
hmac: HmacFnSync;
randomBytes?: (bytesLength?: number) => Uint8Array;
truncateHash?: (hash: Uint8Array, truncateOnly?: boolean) => bigint;
sqrtMod?: (n: bigint) => bigint;
export declare type BasicCurve<T> = utils.BasicCurve<T> & {
a: T;
b: T;
normalizePrivateKey?: (key: PrivKey) => PrivKey;
endo?: EndomorphismOpts;
isTorsionFree?: (c: JacobianConstructor<T>, point: JacobianPointType<T>) => boolean;
clearCofactor?: (c: JacobianConstructor<T>, point: JacobianPointType<T>) => JacobianPointType<T>;
htfDefaults?: htfOpts;
mapToCurve?: (scalar: bigint[]) => {
x: T;
y: T;
};
};
declare function validateOpts(curve: CurveType): Readonly<{
readonly nBitLength: number;
readonly nByteLength: number;
readonly P: bigint;
readonly n: bigint;
readonly h: bigint;
readonly Gx: bigint;
readonly Gy: bigint;
readonly a: bigint;
readonly b: bigint;
lowS: boolean;
readonly hash: CHash;
readonly hmac: HmacFnSync;
randomBytes: typeof utilRandomBytes;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly sqrtMod?: ((n: bigint) => bigint) | undefined;
readonly normalizePrivateKey?: ((key: PrivKey) => PrivKey) | undefined;
readonly endo?: EndomorphismOpts | undefined;
}>;
declare type Entropy = Hex | true;

@@ -78,2 +57,54 @@ declare type SignOpts = {

*/
export interface JacobianPointType<T> extends Group<JacobianPointType<T>> {
readonly x: T;
readonly y: T;
readonly z: T;
multiply(scalar: number | bigint, affinePoint?: PointType<T>): JacobianPointType<T>;
multiplyUnsafe(scalar: bigint): JacobianPointType<T>;
toAffine(invZ?: T): PointType<T>;
}
export interface JacobianConstructor<T> extends GroupConstructor<JacobianPointType<T>> {
new (x: T, y: T, z: T): JacobianPointType<T>;
fromAffine(p: PointType<T>): JacobianPointType<T>;
toAffineBatch(points: JacobianPointType<T>[]): PointType<T>[];
normalizeZ(points: JacobianPointType<T>[]): JacobianPointType<T>[];
}
export interface PointType<T> extends Group<PointType<T>> {
readonly x: T;
readonly y: T;
_setWindowSize(windowSize: number): void;
hasEvenY(): boolean;
toRawBytes(isCompressed?: boolean): Uint8Array;
toHex(isCompressed?: boolean): string;
assertValidity(): void;
multiplyAndAddUnsafe(Q: PointType<T>, a: bigint, b: bigint): PointType<T> | undefined;
}
export interface PointConstructor<T> extends GroupConstructor<PointType<T>> {
new (x: T, y: T): PointType<T>;
fromHex(hex: Hex): PointType<T>;
fromPrivateKey(privateKey: PrivKey): PointType<T>;
hashToCurve(msg: Hex, options?: Partial<htfOpts>): PointType<T>;
encodeToCurve(msg: Hex, options?: Partial<htfOpts>): PointType<T>;
}
export declare type CurvePointsType<T> = BasicCurve<T> & {
fromBytes: (bytes: Uint8Array) => {
x: T;
y: T;
};
toBytes: (c: PointConstructor<T>, point: PointType<T>, compressed: boolean) => Uint8Array;
};
export declare type CurvePointsRes<T> = {
Point: PointConstructor<T>;
JacobianPoint: JacobianConstructor<T>;
normalizePrivateKey: (key: PrivKey) => bigint;
weierstrassEquation: (x: T) => T;
isWithinCurveOrder: (num: bigint) => boolean;
};
export declare function weierstrassPoints<T>(opts: CurvePointsType<T>): {
Point: PointConstructor<T>;
JacobianPoint: JacobianConstructor<T>;
normalizePrivateKey: (key: PrivKey) => bigint;
weierstrassEquation: (x: T) => T;
isWithinCurveOrder: (num: bigint) => boolean;
};
export interface SignatureType {

@@ -87,3 +118,3 @@ readonly r: bigint;

normalizeS(): SignatureType;
recoverPublicKey(msgHash: Hex): PointType;
recoverPublicKey(msgHash: Hex): PointType<bigint>;
toDERRawBytes(isCompressed?: boolean): Uint8Array;

@@ -99,32 +130,38 @@ toDERHex(isCompressed?: boolean): string;

};
export interface JacobianPointType extends Group<JacobianPointType> {
readonly x: bigint;
readonly y: bigint;
readonly z: bigint;
multiply(scalar: number | bigint, affinePoint?: PointType): JacobianPointType;
multiplyUnsafe(scalar: bigint): JacobianPointType;
toAffine(invZ?: bigint): PointType;
}
export interface JacobianPointConstructor extends GroupConstructor<JacobianPointType> {
new (x: bigint, y: bigint, z: bigint): JacobianPointType;
fromAffine(p: PointType): JacobianPointType;
toAffineBatch(points: JacobianPointType[]): PointType[];
normalizeZ(points: JacobianPointType[]): JacobianPointType[];
}
export interface PointType extends Group<PointType> {
readonly x: bigint;
readonly y: bigint;
_setWindowSize(windowSize: number): void;
hasEvenY(): boolean;
toRawBytes(isCompressed?: boolean): Uint8Array;
toHex(isCompressed?: boolean): string;
assertValidity(): void;
multiplyAndAddUnsafe(Q: PointType, a: bigint, b: bigint): PointType | undefined;
}
export interface PointConstructor extends GroupConstructor<PointType> {
new (x: bigint, y: bigint): PointType;
fromHex(hex: Hex): PointType;
fromPrivateKey(privateKey: PrivKey): PointType;
}
export declare type PubKey = Hex | PointType;
export declare type PubKey = Hex | PointType<bigint>;
export declare type CurveType = BasicCurve<bigint> & {
lowS?: boolean;
hash: utils.CHash;
hmac: HmacFnSync;
randomBytes: (bytesLength?: number) => Uint8Array;
truncateHash?: (hash: Uint8Array, truncateOnly?: boolean) => bigint;
};
declare function validateOpts(curve: CurveType): Readonly<{
readonly nBitLength: number;
readonly nByteLength: number;
readonly Fp: mod.Field<bigint>;
readonly n: bigint;
readonly h: bigint;
readonly hEff?: bigint | undefined;
readonly Gx: bigint;
readonly Gy: bigint;
readonly wrapPrivateKey?: boolean | undefined;
readonly allowInfinityPoint?: boolean | undefined;
readonly a: bigint;
readonly b: bigint;
readonly normalizePrivateKey?: ((key: PrivKey) => PrivKey) | undefined;
readonly endo?: EndomorphismOpts | undefined;
readonly isTorsionFree?: ((c: JacobianConstructor<bigint>, point: JacobianPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: JacobianConstructor<bigint>, point: JacobianPointType<bigint>) => JacobianPointType<bigint>) | undefined;
readonly htfDefaults?: htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
lowS: boolean;
readonly hash: utils.CHash;
readonly hmac: HmacFnSync;
readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
}>;
export declare type CurveFn = {

@@ -138,4 +175,4 @@ CURVE: ReturnType<typeof validateOpts>;

}) => boolean;
Point: PointConstructor;
JacobianPoint: JacobianPointConstructor;
Point: PointConstructor<bigint>;
JacobianPoint: JacobianConstructor<bigint>;
Signature: SignatureConstructor;

@@ -148,3 +185,3 @@ utils: {

_normalizePrivateKey: (key: PrivKey) => bigint;
_normalizePublicKey: (publicKey: PubKey) => PointType;
_normalizePublicKey: (publicKey: PubKey) => PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;

@@ -151,0 +188,0 @@ _isValidFieldElement: (num: bigint) => boolean;

@@ -0,3 +1,6 @@

"use strict";
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// Implementation of Short Weierstrass curve. The formula is: y² = x³ + ax + b
Object.defineProperty(exports, "__esModule", { value: true });
exports.weierstrass = exports.weierstrassPoints = void 0;
// TODO: sync vs async naming

@@ -10,39 +13,7 @@ // TODO: default randomBytes

// 4. DRBG supports outputLen bigger than outputLen of hmac
import * as mod from './modular.js';
import { bytesToHex, bytesToNumberBE, concatBytes, ensureBytes, hexToBytes, hexToNumber, numberToHexUnpadded, hashToPrivateScalar, validateOpts as utilOpts, randomBytes as utilRandomBytes, } from './utils.js';
import { wNAF } from './group.js';
// Should be separate from overrides, since overrides can use information about curve (for example nBits)
function validateOpts(curve) {
const opts = utilOpts(curve);
for (const i of ['a', 'b']) {
if (typeof opts[i] !== 'bigint')
throw new Error(`Invalid curve param ${i}=${opts[i]} (${typeof opts[i]})`);
}
for (const fn of ['hash', 'hmac']) {
if (typeof opts[fn] !== 'function')
throw new Error(`Invalid ${fn} function`);
}
for (const fn of ['randomBytes']) {
if (opts[fn] === undefined)
continue; // Optional
if (typeof opts[fn] !== 'function')
throw new Error(`Invalid ${fn} function`);
}
if (!Number.isSafeInteger(opts.hash.outputLen))
throw new Error('Invalid hash function');
const endo = opts.endo;
if (endo) {
if (opts.a !== _0n) {
throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');
}
if (typeof endo !== 'object' ||
typeof endo.beta !== 'bigint' ||
typeof endo.splitScalar !== 'function') {
throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');
}
}
// Set defaults
return Object.freeze({ lowS: true, randomBytes: utilRandomBytes, ...opts });
}
// TODO: convert bits to bytes aligned to 32 bits? (224 for example)
const mod = require("./modular.js");
const utils_js_1 = require("./utils.js");
const utils = require("./utils.js");
const hashToCurve_js_1 = require("./hashToCurve.js");
const group_js_1 = require("./group.js");
// DER encoding utilities

@@ -61,3 +32,3 @@ class DERError extends Error {

if (data.length < 2 || data[0] !== 0x02) {
throw new DERError(`Invalid signature integer tag: ${bytesToHex(data)}`);
throw new DERError(`Invalid signature integer tag: ${(0, utils_js_1.bytesToHex)(data)}`);
}

@@ -73,7 +44,7 @@ const len = data[1];

}
return { data: bytesToNumberBE(res), left: data.subarray(len + 2) };
return { data: (0, utils_js_1.bytesToNumberBE)(res), left: data.subarray(len + 2) };
}
function parseDERSignature(data) {
if (data.length < 2 || data[0] != 0x30) {
throw new DERError(`Invalid signature tag: ${bytesToHex(data)}`);
throw new DERError(`Invalid signature tag: ${(0, utils_js_1.bytesToHex)(data)}`);
}

@@ -86,3 +57,3 @@ if (data[1] !== data.length - 2) {

if (rBytesLeft.length) {
throw new DERError(`Invalid signature: left bytes after parsing: ${bytesToHex(rBytesLeft)}`);
throw new DERError(`Invalid signature: left bytes after parsing: ${(0, utils_js_1.bytesToHex)(rBytesLeft)}`);
}

@@ -97,83 +68,51 @@ return { r, s };

const _8n = BigInt(8);
/**
* Minimal HMAC-DRBG (NIST 800-90) for signatures.
* Used only for RFC6979, does not fully implement DRBG spec.
*/
class HmacDrbg {
constructor(hashLen, qByteLen, hmacFn) {
this.hashLen = hashLen;
this.qByteLen = qByteLen;
this.hmacFn = hmacFn;
if (typeof hashLen !== 'number' || hashLen < 2)
throw new Error('hashLen must be a number');
if (typeof qByteLen !== 'number' || qByteLen < 2)
throw new Error('qByteLen must be a number');
if (typeof hmacFn !== 'function')
throw new Error('hmacFn must be a function');
// Step B, Step C: set hashLen to 8*ceil(hlen/8)
this.v = new Uint8Array(hashLen).fill(1);
this.k = new Uint8Array(hashLen).fill(0);
this.counter = 0;
function validatePointOpts(curve) {
const opts = utils.validateOpts(curve);
const Fp = opts.Fp;
for (const i of ['a', 'b']) {
if (!Fp.isValid(curve[i]))
throw new Error(`Invalid curve param ${i}=${opts[i]} (${typeof opts[i]})`);
}
hmacSync(...values) {
return this.hmacFn(this.k, ...values);
for (const i of ['isTorsionFree', 'clearCofactor', 'mapToCurve']) {
if (curve[i] === undefined)
continue; // Optional
if (typeof curve[i] !== 'function')
throw new Error(`Invalid ${i} function`);
}
incr() {
if (this.counter >= 1000)
throw new Error('Tried 1,000 k values for sign(), all were invalid');
this.counter += 1;
}
reseedSync(seed = new Uint8Array()) {
this.k = this.hmacSync(this.v, Uint8Array.from([0x00]), seed);
this.v = this.hmacSync(this.v);
if (seed.length === 0)
return;
this.k = this.hmacSync(this.v, Uint8Array.from([0x01]), seed);
this.v = this.hmacSync(this.v);
}
// TODO: review
generateSync() {
this.incr();
let len = 0;
const out = [];
while (len < this.qByteLen) {
this.v = this.hmacSync(this.v);
const sl = this.v.slice();
out.push(sl);
len += this.v.length;
const endo = opts.endo;
if (endo) {
if (!Fp.equals(opts.a, Fp.ZERO)) {
throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');
}
return concatBytes(...out);
if (typeof endo !== 'object' ||
typeof endo.beta !== 'bigint' ||
typeof endo.splitScalar !== 'function') {
throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');
}
}
if (typeof opts.fromBytes !== 'function')
throw new Error('Invalid fromBytes function');
if (typeof opts.toBytes !== 'function')
throw new Error('Invalid fromBytes function');
// Requires including hashToCurve file
if (opts.htfDefaults !== undefined)
(0, hashToCurve_js_1.validateHTFOpts)(opts.htfDefaults);
// Set defaults
return Object.freeze({ ...opts });
}
// Use only input from curveOpts!
export function weierstrass(curveDef) {
const CURVE = validateOpts(curveDef);
const CURVE_ORDER = CURVE.n;
function weierstrassPoints(opts) {
const CURVE = validatePointOpts(opts);
const Fp = CURVE.Fp;
// Lengths
// All curves has same field / group length as for now, but it can be different for other curves
const groupLen = CURVE.nByteLength;
const fieldLen = CURVE.nByteLength; // 32 (length of one field element)
if (fieldLen > 2048)
throw new Error('Field lengths over 2048 are not supported');
const compressedLen = fieldLen + 1; // 33
const uncompressedLen = 2 * fieldLen + 1; // 65
const { nByteLength, nBitLength } = CURVE;
const groupLen = nByteLength;
// Not using ** operator with bigints for old engines.
// 2n ** (8n * 32n) == 2n << (8n * 32n - 1n)
const FIELD_MASK = _2n << (_8n * BigInt(fieldLen) - _1n);
function numToFieldStr(num) {
if (typeof num !== 'bigint')
throw new Error('Expected bigint');
if (!(_0n <= num && num < FIELD_MASK))
throw new Error(`Expected number < 2^${fieldLen * 8}`);
return num.toString(16).padStart(2 * fieldLen, '0');
}
function numToField(num) {
const b = hexToBytes(numToFieldStr(num));
if (b.length !== fieldLen)
throw new Error(`Error: expected ${fieldLen} bytes`);
return b;
}
function modP(n, m = CURVE.P) {
return mod.mod(n, m);
}
//const FIELD_MASK = _2n << (_8n * BigInt(fieldLen) - _1n);
// function numToFieldStr(num: bigint): string {
// if (typeof num !== 'bigint') throw new Error('Expected bigint');
// if (!(_0n <= num && num < FIELD_MASK)) throw new Error(`Expected number < 2^${fieldLen * 8}`);
// return num.toString(16).padStart(2 * fieldLen, '0');
// }
/**

@@ -185,5 +124,5 @@ * y² = x³ + ax + b: Short weierstrass curve formula

const { a, b } = CURVE;
const x2 = modP(x * x);
const x3 = modP(x2 * x);
return modP(x3 + a * x + b);
const x2 = Fp.square(x); // x * x
const x3 = Fp.multiply(x2, x); // x2 * x
return Fp.add(Fp.add(x3, Fp.multiply(x, a)), b); // x3 + a * x + b
}

@@ -193,10 +132,7 @@ function isWithinCurveOrder(num) {

}
function isValidFieldElement(num) {
return _0n < num && num < CURVE.P;
}
function normalizePrivateKey(key) {
let num;
if (typeof CURVE.normalizePrivateKey === 'function') {
key = CURVE.normalizePrivateKey(key);
}
let num;
if (typeof key === 'bigint') {

@@ -211,3 +147,3 @@ num = key;

throw new Error(`Expected ${groupLen} bytes of private key`);
num = hexToNumber(key);
num = (0, utils_js_1.hexToNumber)(key);
}

@@ -217,3 +153,3 @@ else if (key instanceof Uint8Array) {

throw new Error(`Expected ${groupLen} bytes of private key`);
num = bytesToNumberBE(key);
num = (0, utils_js_1.bytesToNumberBE)(key);
}

@@ -223,2 +159,4 @@ else {

}
if (CURVE.wrapPrivateKey)
num = mod.mod(num, CURVE.n);
if (!isWithinCurveOrder(num))

@@ -228,24 +166,2 @@ throw new Error('Expected private key: 0 < key < n');

}
/**
* Normalizes hex, bytes, Point to Point. Checks for curve equation.
*/
function normalizePublicKey(publicKey) {
if (publicKey instanceof Point) {
publicKey.assertValidity();
return publicKey;
}
else if (publicKey instanceof Uint8Array || typeof publicKey === 'string') {
return Point.fromHex(publicKey);
// This can happen because PointType can be instance of different class
}
else
throw new Error(`Unknown type of public key: ${publicKey}`);
}
function isBiggerThanHalfOrder(number) {
const HALF = CURVE_ORDER >> _1n;
return number > HALF;
}
function normalizeS(s) {
return isBiggerThanHalfOrder(s) ? mod.mod(-s, CURVE_ORDER) : s;
}
function normalizeScalar(num) {

@@ -258,16 +174,2 @@ if (typeof num === 'number' && Number.isSafeInteger(num) && num > 0)

}
const sqrtModCurve = CURVE.sqrtMod || mod.sqrt;
// Ensures ECDSA message hashes are 32 bytes and < curve order
function _truncateHash(hash, truncateOnly = false) {
const { n, nBitLength } = CURVE;
const byteLength = hash.length;
const delta = byteLength * 8 - nBitLength; // size of curve.n (252 bits)
let h = bytesToNumberBE(hash);
if (delta > 0)
h = h >> BigInt(delta);
if (!truncateOnly && h >= n)
h -= n;
return h;
}
const truncateHash = CURVE.truncateHash || _truncateHash;
/**

@@ -291,3 +193,3 @@ * Jacobian Point works in 3d / jacobi coordinates: (x, y, z) ∋ (x=x/z², y=y/z³)

return JacobianPoint.ZERO;
return new JacobianPoint(p.x, p.y, _1n);
return new JacobianPoint(p.x, p.y, Fp.ONE);
}

@@ -300,3 +202,3 @@ /**

static toAffineBatch(points) {
const toInv = mod.invertBatch(points.map((p) => p.z), CURVE.P);
const toInv = Fp.invertBatch(points.map((p) => p.z));
return points.map((p, i) => p.toAffine(toInv[i]));

@@ -315,9 +217,9 @@ }

const { x: X2, y: Y2, z: Z2 } = other;
const Z1Z1 = modP(Z1 * Z1);
const Z2Z2 = modP(Z2 * Z2);
const U1 = modP(X1 * Z2Z2);
const U2 = modP(X2 * Z1Z1);
const S1 = modP(modP(Y1 * Z2) * Z2Z2);
const S2 = modP(modP(Y2 * Z1) * Z1Z1);
return U1 === U2 && S1 === S2;
const Z1Z1 = Fp.square(Z1); // Z1 * Z1
const Z2Z2 = Fp.square(Z2); // Z2 * Z2
const U1 = Fp.multiply(X1, Z2Z2); // X1 * Z2Z2
const U2 = Fp.multiply(X2, Z1Z1); // X2 * Z1Z1
const S1 = Fp.multiply(Fp.multiply(Y1, Z2), Z2Z2); // Y1 * Z2 * Z2Z2
const S2 = Fp.multiply(Fp.multiply(Y2, Z1), Z1Z1); // Y2 * Z1 * Z1Z1
return Fp.equals(U1, U2) && Fp.equals(S1, S2);
}

@@ -328,3 +230,3 @@ /**

negate() {
return new JacobianPoint(this.x, modP(-this.y), this.z);
return new JacobianPoint(this.x, Fp.negate(this.y), this.z);
}

@@ -340,27 +242,27 @@ // Fast algo for doubling 2 Jacobian Points.

// Cost: 2M + 5S + 6add + 3*2 + 1*3 + 1*8.
if (a === _0n) {
const A = modP(X1 * X1);
const B = modP(Y1 * Y1);
const C = modP(B * B);
const x1b = X1 + B;
const D = modP(_2n * (modP(x1b * x1b) - A - C));
const E = modP(_3n * A);
const F = modP(E * E);
const X3 = modP(F - _2n * D);
const Y3 = modP(E * (D - X3) - _8n * C);
const Z3 = modP(_2n * Y1 * Z1);
if (Fp.isZero(a)) {
const A = Fp.square(X1); // X1 * X1
const B = Fp.square(Y1); // Y1 * Y1
const C = Fp.square(B); // B * B
const x1b = Fp.addN(X1, B); // X1 + B
const D = Fp.multiply(Fp.subtractN(Fp.subtractN(Fp.square(x1b), A), C), _2n); // ((x1b * x1b) - A - C) * 2
const E = Fp.multiply(A, _3n); // A * 3
const F = Fp.square(E); // E * E
const X3 = Fp.subtract(F, Fp.multiplyN(D, _2n)); // F - 2 * D
const Y3 = Fp.subtract(Fp.multiplyN(E, Fp.subtractN(D, X3)), Fp.multiplyN(C, _8n)); // E * (D - X3) - 8 * C;
const Z3 = Fp.multiply(Fp.multiplyN(Y1, _2n), Z1); // 2 * Y1 * Z1
return new JacobianPoint(X3, Y3, Z3);
}
const XX = modP(X1 * X1);
const YY = modP(Y1 * Y1);
const YYYY = modP(YY * YY);
const ZZ = modP(Z1 * Z1);
const tmp1 = modP(X1 + YY);
const S = modP(_2n * (modP(tmp1 * tmp1) - XX - YYYY)); // 2*((X1+YY)^2-XX-YYYY)
const M = modP(_3n * XX + a * modP(ZZ * ZZ));
const T = modP(modP(M * M) - _2n * S); // M^2-2*S
const XX = Fp.square(X1); // X1 * X1
const YY = Fp.square(Y1); // Y1 * Y1
const YYYY = Fp.square(YY); // YY * YY
const ZZ = Fp.square(Z1); // Z1 * Z1
const tmp1 = Fp.add(X1, YY); // X1 + YY
const S = Fp.multiply(Fp.subtractN(Fp.subtractN(Fp.square(tmp1), XX), YYYY), _2n); // 2*((X1+YY)^2-XX-YYYY)
const M = Fp.add(Fp.multiplyN(XX, _3n), Fp.multiplyN(Fp.square(ZZ), a)); // 3 * XX + a * ZZ^2
const T = Fp.subtract(Fp.square(M), Fp.multiplyN(S, _2n)); // M^2-2*S
const X3 = T;
const Y3 = modP(M * (S - T) - _8n * YYYY); // M*(S-T)-8*YYYY
const y1az1 = modP(Y1 + Z1); // (Y1+Z1)
const Z3 = modP(modP(y1az1 * y1az1) - YY - ZZ); // (Y1+Z1)^2-YY-ZZ
const Y3 = Fp.subtract(Fp.multiplyN(M, Fp.subtractN(S, T)), Fp.multiplyN(YYYY, _8n)); // M*(S-T)-8*YYYY
const y1az1 = Fp.add(Y1, Z1); // (Y1+Z1)
const Z3 = Fp.subtract(Fp.subtractN(Fp.square(y1az1), YY), ZZ); // (Y1+Z1)^2-YY-ZZ
return new JacobianPoint(X3, Y3, Z3);

@@ -377,24 +279,24 @@ }

const { x: X2, y: Y2, z: Z2 } = other;
if (X2 === _0n || Y2 === _0n)
if (Fp.isZero(X2) || Fp.isZero(Y2))
return this;
if (X1 === _0n || Y1 === _0n)
if (Fp.isZero(X1) || Fp.isZero(Y1))
return other;
// We're using same code in equals()
const Z1Z1 = modP(Z1 * Z1); // Z1Z1 = Z1^2
const Z2Z2 = modP(Z2 * Z2); // Z2Z2 = Z2^2;
const U1 = modP(X1 * Z2Z2); // X1 * Z2Z2
const U2 = modP(X2 * Z1Z1); // X2 * Z1Z1
const S1 = modP(modP(Y1 * Z2) * Z2Z2); // Y1 * Z2 * Z2Z2
const S2 = modP(modP(Y2 * Z1) * Z1Z1); // Y2 * Z1 * Z1Z1
const H = modP(U2 - U1); // H = U2 - U1
const r = modP(S2 - S1); // S2 - S1
const Z1Z1 = Fp.square(Z1); // Z1Z1 = Z1^2
const Z2Z2 = Fp.square(Z2); // Z2Z2 = Z2^2;
const U1 = Fp.multiply(X1, Z2Z2); // X1 * Z2Z2
const U2 = Fp.multiply(X2, Z1Z1); // X2 * Z1Z1
const S1 = Fp.multiply(Fp.multiply(Y1, Z2), Z2Z2); // Y1 * Z2 * Z2Z2
const S2 = Fp.multiply(Fp.multiply(Y2, Z1), Z1Z1); // Y2 * Z1 * Z1Z1
const H = Fp.subtractN(U2, U1); // H = U2 - U1
const r = Fp.subtractN(S2, S1); // S2 - S1
// H = 0 meaning it's the same point.
if (H === _0n)
return r === _0n ? this.double() : JacobianPoint.ZERO;
const HH = modP(H * H); // HH = H2
const HHH = modP(H * HH); // HHH = H * HH
const V = modP(U1 * HH); // V = U1 * HH
const X3 = modP(r * r - HHH - _2n * V); // X3 = r^2 - HHH - 2 * V;
const Y3 = modP(r * (V - X3) - S1 * HHH); // Y3 = r * (V - X3) - S1 * HHH;
const Z3 = modP(Z1 * Z2 * H); // Z3 = Z1 * Z2 * H;
if (Fp.isZero(H))
return Fp.isZero(r) ? this.double() : JacobianPoint.ZERO;
const HH = Fp.square(H); // HH = H2
const HHH = Fp.multiply(H, HH); // HHH = H * HH
const V = Fp.multiply(U1, HH); // V = U1 * HH
const X3 = Fp.subtract(Fp.subtractN(Fp.squareN(r), HHH), Fp.multiplyN(V, _2n)); // X3 = r^2 - HHH - 2 * V;
const Y3 = Fp.subtract(Fp.multiplyN(r, Fp.subtractN(V, X3)), Fp.multiplyN(S1, HHH)); // Y3 = r * (V - X3) - S1 * HHH;
const Z3 = Fp.multiply(Fp.multiply(Z1, Z2), H); // Z3 = Z1 * Z2 * H;
return new JacobianPoint(X3, Y3, Z3);

@@ -438,3 +340,3 @@ }

k2p = k2p.negate();
k2p = new JacobianPoint(modP(k2p.x * CURVE.endo.beta), k2p.y, k2p.z);
k2p = new JacobianPoint(Fp.multiply(k2p.x, CURVE.endo.beta), k2p.y, k2p.z);
return k1p.add(k2p);

@@ -480,3 +382,3 @@ }

k2p = wnaf.constTimeNegate(k2neg, k2p);
k2p = new JacobianPoint(modP(k2p.x * CURVE.endo.beta), k2p.y, k2p.z);
k2p = new JacobianPoint(Fp.multiply(k2p.x, CURVE.endo.beta), k2p.y, k2p.z);
point = k1p.add(k2p);

@@ -501,21 +403,38 @@ fake = f1p.add(f2p);

// If invZ was 0, we return zero point. However we still want to execute
// all operations, so we replace invZ with a random number, 8.
// all operations, so we replace invZ with a random number, 1.
if (invZ == null)
invZ = is0 ? _8n : mod.invert(z, CURVE.P);
invZ = is0 ? Fp.ONE : Fp.invert(z);
const iz1 = invZ;
const iz2 = modP(iz1 * iz1);
const iz3 = modP(iz2 * iz1);
const ax = modP(x * iz2);
const ay = modP(y * iz3);
const zz = modP(z * iz1);
const iz2 = Fp.square(iz1); // iz1 * iz1
const iz3 = Fp.multiply(iz2, iz1); // iz2 * iz1
const ax = Fp.multiply(x, iz2); // x * iz2
const ay = Fp.multiply(y, iz3); // y * iz3
const zz = Fp.multiply(z, iz1); // z * iz1
if (is0)
return Point.ZERO;
if (zz !== _1n)
if (!Fp.equals(zz, Fp.ONE))
throw new Error('invZ was invalid');
return new Point(ax, ay);
}
isTorsionFree() {
if (CURVE.h === _1n)
return true; // No subgroups, always torsion fee
if (CURVE.isTorsionFree)
return CURVE.isTorsionFree(JacobianPoint, this);
// is multiplyUnsafe(CURVE.n) is always ok, same as for edwards?
throw new Error('Unsupported!');
}
// Clear cofactor of G1
// https://eprint.iacr.org/2019/403
clearCofactor() {
if (CURVE.h === _1n)
return this; // Fast-path
if (CURVE.clearCofactor)
return CURVE.clearCofactor(JacobianPoint, this);
return this.multiplyUnsafe(CURVE.h);
}
}
JacobianPoint.BASE = new JacobianPoint(CURVE.Gx, CURVE.Gy, _1n);
JacobianPoint.ZERO = new JacobianPoint(_0n, _1n, _0n);
const wnaf = wNAF(JacobianPoint, CURVE.endo ? CURVE.nBitLength / 2 : CURVE.nBitLength);
JacobianPoint.BASE = new JacobianPoint(CURVE.Gx, CURVE.Gy, Fp.ONE);
JacobianPoint.ZERO = new JacobianPoint(Fp.ZERO, Fp.ONE, Fp.ZERO);
const wnaf = (0, group_js_1.wNAF)(JacobianPoint, CURVE.endo ? nBitLength / 2 : nBitLength);
// Stores precomputed values for points.

@@ -538,20 +457,12 @@ const pointPrecomputes = new WeakMap();

hasEvenY() {
return this.y % _2n === _0n;
if (Fp.isOdd)
return !Fp.isOdd(this.y);
throw new Error("Field doesn't support isOdd");
}
/**
* Supports compressed ECDSA points
* @returns Point instance
* Converts hash string or Uint8Array to Point.
* @param hex short/long ECDSA hex
*/
static fromCompressedHex(bytes) {
const P = CURVE.P;
const x = bytesToNumberBE(bytes.subarray(1));
if (!isValidFieldElement(x))
throw new Error('Point is not on curve');
const y2 = weierstrassEquation(x); // y² = x³ + ax + b
let y = sqrtModCurve(y2, P); // y = y² ^ (p+1)/4
const isYOdd = (y & _1n) === _1n;
// ECDSA
const isFirstByteOdd = (bytes[0] & 1) === 1;
if (isFirstByteOdd !== isYOdd)
y = modP(-y);
static fromHex(hex) {
const { x, y } = CURVE.fromBytes((0, utils_js_1.ensureBytes)(hex));
const point = new Point(x, y);

@@ -561,24 +472,2 @@ point.assertValidity();

}
static fromUncompressedHex(bytes) {
const x = bytesToNumberBE(bytes.subarray(1, fieldLen + 1));
const y = bytesToNumberBE(bytes.subarray(fieldLen + 1, 2 * fieldLen + 1));
const point = new Point(x, y);
point.assertValidity();
return point;
}
/**
* Converts hash string or Uint8Array to Point.
* @param hex short/long ECDSA hex
*/
static fromHex(hex) {
const bytes = ensureBytes(hex);
const len = bytes.length;
const header = bytes[0];
// this.assertValidity() is done inside of those two functions
if (len === compressedLen && (header === 0x02 || header === 0x03))
return this.fromCompressedHex(bytes);
if (len === uncompressedLen && header === 0x04)
return this.fromUncompressedHex(bytes);
throw new Error(`Point.fromHex: received invalid point. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes, not ${len}`);
}
// Multiplies generator point by privateKey.

@@ -589,25 +478,28 @@ static fromPrivateKey(privateKey) {

toRawBytes(isCompressed = false) {
return hexToBytes(this.toHex(isCompressed));
this.assertValidity();
return CURVE.toBytes(Point, this, isCompressed);
}
toHex(isCompressed = false) {
const x = numToFieldStr(this.x);
if (isCompressed) {
const prefix = this.hasEvenY() ? '02' : '03';
return `${prefix}${x}`;
}
else {
return `04${x}${numToFieldStr(this.y)}`;
}
return (0, utils_js_1.bytesToHex)(this.toRawBytes(isCompressed));
}
// A point on curve is valid if it conforms to equation.
assertValidity() {
// Zero is valid point too!
if (this.equals(Point.ZERO)) {
if (CURVE.allowInfinityPoint)
return;
throw new Error('Point is infinity');
}
// Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
const msg = 'Point is not on elliptic curve';
const { x, y } = this;
if (!isValidFieldElement(x) || !isValidFieldElement(y))
if (!Fp.isValid(x) || !Fp.isValid(y))
throw new Error(msg);
const left = modP(y * y);
const left = Fp.square(y);
const right = weierstrassEquation(x);
if (modP(left - right) !== _0n)
if (!Fp.equals(left, right))
throw new Error(msg);
// TODO: flag to disable this?
if (!this.isTorsionFree())
throw new Error('Point must be of prime-order subgroup');
}

@@ -617,7 +509,7 @@ equals(other) {

throw new TypeError('Point#equals: expected Point');
return this.x === other.x && this.y === other.y;
return Fp.equals(this.x, other.x) && Fp.equals(this.y, other.y);
}
// Returns the same point with inverted `y`
negate() {
return new Point(this.x, modP(-this.y));
return new Point(this.x, Fp.negate(this.y));
}

@@ -639,2 +531,11 @@ // Adds point to itself

}
multiplyUnsafe(scalar) {
return JacobianPoint.fromAffine(this).multiplyUnsafe(scalar).toAffine();
}
clearCofactor() {
return JacobianPoint.fromAffine(this).clearCofactor().toAffine();
}
isTorsionFree() {
return JacobianPoint.fromAffine(this).isTorsionFree();
}
/**

@@ -653,2 +554,23 @@ * Efficiently calculate `aP + bQ`.

}
// Encodes byte string to elliptic curve
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
static hashToCurve(msg, options) {
if (!CURVE.mapToCurve)
throw new Error('No mapToCurve defined for curve');
msg = (0, utils_js_1.ensureBytes)(msg);
const u = (0, hashToCurve_js_1.hash_to_field)(msg, 2, { ...CURVE.htfDefaults, ...options });
const { x: x0, y: y0 } = CURVE.mapToCurve(u[0]);
const { x: x1, y: y1 } = CURVE.mapToCurve(u[1]);
const p = new Point(x0, y0).add(new Point(x1, y1)).clearCofactor();
return p;
}
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
static encodeToCurve(msg, options) {
if (!CURVE.mapToCurve)
throw new Error('No mapToCurve defined for curve');
msg = (0, utils_js_1.ensureBytes)(msg);
const u = (0, hashToCurve_js_1.hash_to_field)(msg, 1, { ...CURVE.htfDefaults, ...options });
const { x, y } = CURVE.mapToCurve(u[0]);
return new Point(x, y).clearCofactor();
}
}

@@ -662,4 +584,165 @@ /**

*/
Point.ZERO = new Point(_0n, _0n);
Point.ZERO = new Point(Fp.ZERO, Fp.ZERO);
return {
Point: Point,
JacobianPoint: JacobianPoint,
normalizePrivateKey,
weierstrassEquation,
isWithinCurveOrder,
};
}
exports.weierstrassPoints = weierstrassPoints;
function validateOpts(curve) {
const opts = utils.validateOpts(curve);
if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
throw new Error('Invalid hash function');
if (typeof opts.hmac !== 'function')
throw new Error('Invalid hmac function');
if (typeof opts.randomBytes !== 'function')
throw new Error('Invalid randomBytes function');
// Set defaults
return Object.freeze({ lowS: true, ...opts });
}
/**
* Minimal HMAC-DRBG (NIST 800-90) for signatures.
* Used only for RFC6979, does not fully implement DRBG spec.
*/
class HmacDrbg {
constructor(hashLen, qByteLen, hmacFn) {
this.hashLen = hashLen;
this.qByteLen = qByteLen;
this.hmacFn = hmacFn;
if (typeof hashLen !== 'number' || hashLen < 2)
throw new Error('hashLen must be a number');
if (typeof qByteLen !== 'number' || qByteLen < 2)
throw new Error('qByteLen must be a number');
if (typeof hmacFn !== 'function')
throw new Error('hmacFn must be a function');
// Step B, Step C: set hashLen to 8*ceil(hlen/8)
this.v = new Uint8Array(hashLen).fill(1);
this.k = new Uint8Array(hashLen).fill(0);
this.counter = 0;
}
hmacSync(...values) {
return this.hmacFn(this.k, ...values);
}
incr() {
if (this.counter >= 1000)
throw new Error('Tried 1,000 k values for sign(), all were invalid');
this.counter += 1;
}
reseedSync(seed = new Uint8Array()) {
this.k = this.hmacSync(this.v, Uint8Array.from([0x00]), seed);
this.v = this.hmacSync(this.v);
if (seed.length === 0)
return;
this.k = this.hmacSync(this.v, Uint8Array.from([0x01]), seed);
this.v = this.hmacSync(this.v);
}
// TODO: review
generateSync() {
this.incr();
let len = 0;
const out = [];
while (len < this.qByteLen) {
this.v = this.hmacSync(this.v);
const sl = this.v.slice();
out.push(sl);
len += this.v.length;
}
return (0, utils_js_1.concatBytes)(...out);
}
}
function weierstrass(curveDef) {
const CURVE = validateOpts(curveDef);
const CURVE_ORDER = CURVE.n;
const Fp = CURVE.Fp;
const compressedLen = Fp.BYTES + 1; // 33
const uncompressedLen = 2 * Fp.BYTES + 1; // 65
function isValidFieldElement(num) {
// 0 is disallowed by arbitrary reasons. Probably because infinity point?
return _0n < num && num < Fp.ORDER;
}
const { Point, JacobianPoint, normalizePrivateKey, weierstrassEquation, isWithinCurveOrder } = weierstrassPoints({
...CURVE,
toBytes(c, point, isCompressed) {
if (isCompressed) {
return (0, utils_js_1.concatBytes)(new Uint8Array([point.hasEvenY() ? 0x02 : 0x03]), Fp.toBytes(point.x));
}
else {
return (0, utils_js_1.concatBytes)(new Uint8Array([0x04]), Fp.toBytes(point.x), Fp.toBytes(point.y));
}
},
fromBytes(bytes) {
const len = bytes.length;
const header = bytes[0];
// this.assertValidity() is done inside of fromHex
if (len === compressedLen && (header === 0x02 || header === 0x03)) {
const x = (0, utils_js_1.bytesToNumberBE)(bytes.subarray(1));
if (!isValidFieldElement(x))
throw new Error('Point is not on curve');
const y2 = weierstrassEquation(x); // y² = x³ + ax + b
let y = Fp.sqrt(y2); // y = y² ^ (p+1)/4
const isYOdd = (y & _1n) === _1n;
// ECDSA
const isFirstByteOdd = (bytes[0] & 1) === 1;
if (isFirstByteOdd !== isYOdd)
y = Fp.negate(y);
return { x, y };
}
else if (len === uncompressedLen && header === 0x04) {
const x = Fp.fromBytes(bytes.subarray(1, Fp.BYTES + 1));
const y = Fp.fromBytes(bytes.subarray(Fp.BYTES + 1, 2 * Fp.BYTES + 1));
return { x, y };
}
else {
throw new Error(`Point.fromHex: received invalid point. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes, not ${len}`);
}
},
});
// Do we need these functions at all?
function numToField(num) {
if (typeof num !== 'bigint')
throw new Error('Expected bigint');
if (!(_0n <= num && num < Fp.MASK))
throw new Error(`Expected number < 2^${Fp.BYTES * 8}`);
return Fp.toBytes(num);
}
const numToFieldStr = (num) => (0, utils_js_1.bytesToHex)(numToField(num));
/**
* Normalizes hex, bytes, Point to Point. Checks for curve equation.
*/
function normalizePublicKey(publicKey) {
if (publicKey instanceof Point) {
publicKey.assertValidity();
return publicKey;
}
else if (publicKey instanceof Uint8Array || typeof publicKey === 'string') {
return Point.fromHex(publicKey);
// This can happen because PointType can be instance of different class
}
else
throw new Error(`Unknown type of public key: ${publicKey}`);
}
function isBiggerThanHalfOrder(number) {
const HALF = CURVE_ORDER >> _1n;
return number > HALF;
}
function normalizeS(s) {
return isBiggerThanHalfOrder(s) ? mod.mod(-s, CURVE_ORDER) : s;
}
// Ensures ECDSA message hashes are 32 bytes and < curve order
function _truncateHash(hash, truncateOnly = false) {
const { n, nBitLength } = CURVE;
const byteLength = hash.length;
const delta = byteLength * 8 - nBitLength; // size of curve.n (252 bits)
let h = (0, utils_js_1.bytesToNumberBE)(hash);
if (delta > 0)
h = h >> BigInt(delta);
if (!truncateOnly && h >= n)
h -= n;
return h;
}
const truncateHash = CURVE.truncateHash || _truncateHash;
/**
* ECDSA signature with its (r, s) properties. Supports DER & compact representations.

@@ -680,6 +763,6 @@ */

throw new TypeError(`${name}: Expected string or Uint8Array`);
const str = arr ? bytesToHex(hex) : hex;
const str = arr ? (0, utils_js_1.bytesToHex)(hex) : hex;
if (str.length !== 128)
throw new Error(`${name}: Expected 64-byte hex`);
return new Signature(hexToNumber(str.slice(0, 64)), hexToNumber(str.slice(64, 128)));
return new Signature((0, utils_js_1.hexToNumber)(str.slice(0, 64)), (0, utils_js_1.hexToNumber)(str.slice(64, 128)));
}

@@ -692,3 +775,3 @@ // DER encoded ECDSA signature

throw new TypeError(`Signature.fromDER: Expected string or Uint8Array`);
const { r, s } = parseDERSignature(arr ? hex : hexToBytes(hex));
const { r, s } = parseDERSignature(arr ? hex : (0, utils_js_1.hexToBytes)(hex));
return new Signature(r, s);

@@ -726,3 +809,3 @@ }

throw new Error('Cannot recover: invalid recovery bit');
const h = truncateHash(ensureBytes(msgHash));
const h = truncateHash((0, utils_js_1.ensureBytes)(msgHash));
const { n } = CURVE;

@@ -756,12 +839,12 @@ const rinv = mod.invert(r, n);

toDERRawBytes(isCompressed = false) {
return hexToBytes(this.toDERHex(isCompressed));
return (0, utils_js_1.hexToBytes)(this.toDERHex(isCompressed));
}
toDERHex(isCompressed = false) {
const sHex = sliceDER(numberToHexUnpadded(this.s));
const sHex = sliceDER((0, utils_js_1.numberToHexUnpadded)(this.s));
if (isCompressed)
return sHex;
const rHex = sliceDER(numberToHexUnpadded(this.r));
const rLen = numberToHexUnpadded(rHex.length / 2);
const sLen = numberToHexUnpadded(sHex.length / 2);
const length = numberToHexUnpadded(rHex.length / 2 + sHex.length / 2 + 4);
const rHex = sliceDER((0, utils_js_1.numberToHexUnpadded)(this.r));
const rLen = (0, utils_js_1.numberToHexUnpadded)(rHex.length / 2);
const sLen = (0, utils_js_1.numberToHexUnpadded)(sHex.length / 2);
const length = (0, utils_js_1.numberToHexUnpadded)(rHex.length / 2 + sHex.length / 2 + 4);
return `30${length}02${rLen}${rHex}02${sLen}${sHex}`;

@@ -771,3 +854,3 @@ }

toCompactRawBytes() {
return hexToBytes(this.toCompactHex());
return (0, utils_js_1.hexToBytes)(this.toCompactHex());
}

@@ -779,4 +862,4 @@ toCompactHex() {

const utils = {
mod: modP,
invert: (n, m = CURVE.P) => mod.invert(n, m),
mod: (n, modulo = Fp.ORDER) => mod.mod(n, modulo),
invert: Fp.invert,
isValidPrivateKey(privateKey) {

@@ -801,3 +884,3 @@ try {

*/
hashToPrivateKey: (hash) => numToField(hashToPrivateScalar(hash, CURVE_ORDER)),
hashToPrivateKey: (hash) => numToField((0, utils_js_1.hashToPrivateScalar)(hash, CURVE_ORDER)),
/**

@@ -807,3 +890,3 @@ * Produces cryptographically secure private key from random of size (nBitLength+64)

*/
randomPrivateKey: () => utils.hashToPrivateKey(CURVE.randomBytes(fieldLen + 8)),
randomPrivateKey: () => utils.hashToPrivateKey(CURVE.randomBytes(Fp.BYTES + 8)),
/**

@@ -868,4 +951,4 @@ * 1. Returns cached point which you can use to pass to `getSharedSecret` or `#multiply` by it.

function bits2int(bytes) {
const slice = bytes.length > fieldLen ? bytes.slice(0, fieldLen) : bytes;
return bytesToNumberBE(slice);
const slice = bytes.length > Fp.BYTES ? bytes.slice(0, Fp.BYTES) : bytes;
return (0, utils_js_1.bytesToNumberBE)(slice);
}

@@ -886,3 +969,3 @@ function bits2octets(bytes) {

// Step A is ignored, since we already provide hash instead of msg
const h1 = numToField(truncateHash(ensureBytes(msgHash)));
const h1 = numToField(truncateHash((0, utils_js_1.ensureBytes)(msgHash)));
const d = normalizePrivateKey(privateKey);

@@ -894,6 +977,6 @@ // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')

if (extraEntropy === true)
extraEntropy = CURVE.randomBytes(fieldLen);
const e = ensureBytes(extraEntropy);
if (e.length !== fieldLen)
throw new Error(`sign: Expected ${fieldLen} bytes of extra data`);
extraEntropy = CURVE.randomBytes(Fp.BYTES);
const e = (0, utils_js_1.ensureBytes)(extraEntropy);
if (e.length !== Fp.BYTES)
throw new Error(`sign: Expected ${Fp.BYTES} bytes of extra data`);
seedArgs.push(e);

@@ -904,3 +987,3 @@ }

// V, 0x00 are done in HmacDRBG constructor.
const seed = concatBytes(...seedArgs);
const seed = (0, utils_js_1.concatBytes)(...seedArgs);
const m = bits2int(h1);

@@ -988,3 +1071,3 @@ return { seed, m, d };

}
msgHash = ensureBytes(msgHash);
msgHash = (0, utils_js_1.ensureBytes)(msgHash);
}

@@ -1030,1 +1113,2 @@ catch (error) {

}
exports.weierstrass = weierstrass;
{
"name": "@noble/curves",
"version": "0.3.2",
"version": "0.4.0",
"description": "Minimal, zero-dependency JS implementation of elliptic curve cryptography",

@@ -11,8 +11,8 @@ "files": [

"scripts": {
"bench": "node benchmark/index.js",
"bench": "node curve-definitions/benchmark/index.js",
"build": "tsc && tsc -p tsconfig.esm.json",
"build:release": "rollup -c rollup.config.js",
"lint": "prettier --check 'src/**/*.{js,ts}'",
"format": "prettier --write 'src/**/*.{js,ts}'",
"test": "node test/index.test.js"
"lint": "prettier --check 'src/**/*.{js,ts}' 'curve-definitions/src/**/*.{js,ts}'",
"format": "prettier --write 'src/**/*.{js,ts}' 'curve-definitions/src/**/*.{js,ts}'",
"test": "cd curve-definitions; node test/index.test.js"
},

@@ -26,24 +26,53 @@ "author": "Paul Miller (https://paulmillr.com)",

"license": "MIT",
"dependencies": {
"@noble/hashes": "1.1.5"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "13.3.0",
"@scure/base": "^1.1.1",
"@scure/bip32": "^1.1.1",
"@scure/bip39": "^1.1.0",
"fast-check": "^3.4.0",
"micro-bmark": "0.2.0",
"micro-should": "^0.2.0",
"prettier": "^2.6.2",
"micro-should": "0.2.0",
"prettier": "2.6.2",
"rollup": "2.75.5",
"typescript": "4.7.3"
},
"main": "lib/index.js",
"module": "lib/index.js",
"browser": {
"crypto": false,
"./crypto": "./lib/cryptoBrowser.js"
"main": "index.js",
"exports": {
"./edwards": {
"types": "./lib/edwards.d.ts",
"import": "./lib/esm/edwards.js",
"default": "./lib/edwards.js"
},
"./modular": {
"types": "./lib/modular.d.ts",
"import": "./lib/esm/modular.js",
"default": "./lib/modular.js"
},
"./montgomery": {
"types": "./lib/montgomery.d.ts",
"import": "./lib/esm/montgomery.js",
"default": "./lib/montgomery.js"
},
"./weierstrass": {
"types": "./lib/weierstrass.d.ts",
"import": "./lib/esm/weierstrass.js",
"default": "./lib/weierstrass.js"
},
"./bls": {
"types": "./lib/bls.d.ts",
"import": "./lib/esm/bls.js",
"default": "./lib/bls.js"
},
"./hashToCurve": {
"types": "./lib/hashToCurve.d.ts",
"import": "./lib/esm/hashToCurve.js",
"default": "./lib/hashToCurve.js"
},
"./group": {
"types": "./lib/group.d.ts",
"import": "./lib/esm/group.js",
"default": "./lib/group.js"
},
"./utils": {
"types": "./lib/utils.d.ts",
"import": "./lib/esm/utils.js",
"default": "./lib/utils.js"
}
},
"type": "module",
"keywords": [

@@ -54,8 +83,2 @@ "elliptic",

"hyperelliptic",
"weierstrass",
"edwards",
"montgomery",
"secp256k1",
"ed25519",
"ed448",
"p256",

@@ -76,2 +99,2 @@ "p384",

]
}
}

@@ -48,5 +48,5 @@ # noble-curves

import { weierstrass } from '@noble/curves/weierstrass'; // Short Weierstrass curve
import { concatBytes, randomBytes } from '@noble/curves/utils';
import { sha256 } from '@noble/hashes/sha256';
import { hmac } from '@noble/hashes/hmac';
import { concatBytes, randomBytes } from '@noble/hashes/utils';

@@ -130,2 +130,3 @@ const secp256k1 = weierstrass({

hash: sha512,
randomBytes,
adjustScalarBytes(bytes) { // optional

@@ -132,0 +133,0 @@ bytes[0] &= 248;

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