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.5.2 to 0.6.0

lib/abstract/curve.d.ts

31

lib/_shortw_utils.d.ts

@@ -35,9 +35,4 @@ import { randomBytes } from '@noble/hashes/utils';

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -47,22 +42,16 @@ readonly hash: CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;
getPublicKey: (privateKey: import("./abstract/utils.js").PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
signUnhashed: (msg: Uint8Array, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
verify: (signature: import("./abstract/utils.js").Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
lowS?: boolean | undefined;
} | undefined) => boolean;
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
verify: (signature: import("./abstract/utils.js").Hex | {
r: bigint;
s: bigint;
}, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: import("./abstract/utils.js").PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: import("./abstract/utils.js").PrivKey): boolean;

@@ -69,0 +58,0 @@ hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;

@@ -14,22 +14,27 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

*/
import * as mod from './modular.js';
import * as ut from './utils.js';
import { Hex, PrivKey } from './utils.js';
import { htfOpts, stringToBytes, hash_to_field as hashToField, expand_message_xmd as expandMessageXMD } from './hash-to-curve.js';
import { CurvePointsType, PointType, CurvePointsRes } from './weierstrass.js';
import { AffinePoint } from './curve.js';
import { Field } from './modular.js';
import { Hex, PrivKey, CHash } from './utils.js';
import * as htf from './hash-to-curve.js';
import { CurvePointsType, ProjPointType as ProjPointType, CurvePointsRes } from './weierstrass.js';
declare type Fp = bigint;
export declare type SignatureCoder<Fp2> = {
decode(hex: Hex): PointType<Fp2>;
encode(point: PointType<Fp2>): Uint8Array;
decode(hex: Hex): ProjPointType<Fp2>;
encode(point: ProjPointType<Fp2>): Uint8Array;
};
export declare type CurveType<Fp, Fp2, Fp6, Fp12> = {
r: bigint;
G1: Omit<CurvePointsType<Fp>, 'n'>;
G1: Omit<CurvePointsType<Fp>, 'n'> & {
mapToCurve: htf.MapToCurve<Fp>;
htfDefaults: htf.Opts;
};
G2: Omit<CurvePointsType<Fp2>, 'n'> & {
Signature: SignatureCoder<Fp2>;
mapToCurve: htf.MapToCurve<Fp2>;
htfDefaults: htf.Opts;
};
x: bigint;
Fp: mod.Field<Fp>;
Fr: mod.Field<bigint>;
Fp2: mod.Field<Fp2> & {
Fp: Field<Fp>;
Fr: Field<bigint>;
Fp2: Field<Fp2> & {
reim: (num: Fp2) => {

@@ -42,4 +47,4 @@ re: bigint;

};
Fp6: mod.Field<Fp6>;
Fp12: mod.Field<Fp12> & {
Fp6: Field<Fp6>;
Fp12: Field<Fp12> & {
frobeniusMap(num: Fp12, power: number): Fp12;

@@ -50,4 +55,4 @@ multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;

};
htfDefaults: htfOpts;
hash: ut.CHash;
htfDefaults: htf.Opts;
hash: CHash;
randomBytes: (bytesLength?: number) => Uint8Array;

@@ -57,7 +62,7 @@ };

CURVE: CurveType<Fp, Fp2, Fp6, Fp12>;
Fr: mod.Field<bigint>;
Fp: mod.Field<Fp>;
Fp2: mod.Field<Fp2>;
Fp6: mod.Field<Fp6>;
Fp12: mod.Field<Fp12>;
Fr: Field<bigint>;
Fp: Field<Fp>;
Fp2: Field<Fp2>;
Fp6: Field<Fp6>;
Fp12: Field<Fp12>;
G1: CurvePointsRes<Fp>;

@@ -67,25 +72,27 @@ G2: CurvePointsRes<Fp2>;

millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
calcPairingPrecomputes: (x: Fp2, y: Fp2) => [Fp2, Fp2, Fp2][];
pairing: (P: PointType<Fp>, Q: PointType<Fp2>, withFinalExponent?: boolean) => Fp12;
calcPairingPrecomputes: (p: AffinePoint<Fp2>) => [Fp2, Fp2, Fp2][];
hashToCurve: {
G1: ReturnType<(typeof htf.hashToCurve<Fp>)>;
G2: ReturnType<(typeof htf.hashToCurve<Fp2>)>;
};
pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
getPublicKey: (privateKey: PrivKey) => Uint8Array;
sign: {
(message: Hex, privateKey: PrivKey): Uint8Array;
(message: PointType<Fp2>, privateKey: PrivKey): PointType<Fp2>;
(message: ProjPointType<Fp2>, privateKey: PrivKey): ProjPointType<Fp2>;
};
verify: (signature: Hex | PointType<Fp2>, message: Hex | PointType<Fp2>, publicKey: Hex | PointType<Fp>) => boolean;
verify: (signature: Hex | ProjPointType<Fp2>, message: Hex | ProjPointType<Fp2>, publicKey: Hex | ProjPointType<Fp>) => boolean;
aggregatePublicKeys: {
(publicKeys: Hex[]): Uint8Array;
(publicKeys: PointType<Fp>[]): PointType<Fp>;
(publicKeys: ProjPointType<Fp>[]): ProjPointType<Fp>;
};
aggregateSignatures: {
(signatures: Hex[]): Uint8Array;
(signatures: PointType<Fp2>[]): PointType<Fp2>;
(signatures: ProjPointType<Fp2>[]): ProjPointType<Fp2>;
};
verifyBatch: (signature: Hex | PointType<Fp2>, messages: (Hex | PointType<Fp2>)[], publicKeys: (Hex | PointType<Fp>)[]) => boolean;
verifyBatch: (signature: Hex | ProjPointType<Fp2>, messages: (Hex | ProjPointType<Fp2>)[], publicKeys: (Hex | ProjPointType<Fp>)[]) => boolean;
utils: {
stringToBytes: typeof stringToBytes;
hashToField: typeof hashToField;
expandMessageXMD: typeof expandMessageXMD;
getDSTLabel: () => string;
setDSTLabel(newLabel: string): void;
stringToBytes: typeof htf.stringToBytes;
hashToField: typeof htf.hash_to_field;
expandMessageXMD: typeof htf.expand_message_xmd;
};

@@ -92,0 +99,0 @@ };

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.bls = void 0;
const ut = require("./utils.js");
const hash_to_curve_js_1 = require("./hash-to-curve.js");
const modular_js_1 = require("./modular.js");
const utils_js_1 = require("./utils.js");
const htf = require("./hash-to-curve.js");
const weierstrass_js_1 = require("./weierstrass.js");

@@ -10,7 +11,8 @@ function bls(CURVE) {

const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE;
const BLS_X_LEN = ut.bitLen(CURVE.x);
const BLS_X_LEN = (0, utils_js_1.bitLen)(CURVE.x);
const groupLen = 32; // TODO: calculate; hardcoded for now
// Pre-compute coefficients for sparse multiplication
// Point addition and point double calculations is reused for coefficients
function calcPairingPrecomputes(x, y) {
function calcPairingPrecomputes(p) {
const { x, y } = p;
// prettier-ignore

@@ -23,16 +25,16 @@ const Qx = x, Qy = y, Qz = Fp2.ONE;

// Double
let t0 = Fp2.square(Ry); // Ry²
let t1 = Fp2.square(Rz); // Rz²
let t0 = Fp2.sqr(Ry); // Ry²
let t1 = Fp2.sqr(Rz); // Rz²
let t2 = Fp2.multiplyByB(Fp2.mul(t1, 3n)); // 3 * T1 * B
let t3 = Fp2.mul(t2, 3n); // 3 * T2
let t4 = Fp2.sub(Fp2.sub(Fp2.square(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
let t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
ell_coeff.push([
Fp2.sub(t2, t0),
Fp2.mul(Fp2.square(Rx), 3n),
Fp2.negate(t4), // -T4
Fp2.mul(Fp2.sqr(Rx), 3n),
Fp2.neg(t4), // -T4
]);
Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), 2n); // ((T0 - T3) * Rx * Ry) / 2
Ry = Fp2.sub(Fp2.square(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.square(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.sqr(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
Rz = Fp2.mul(t0, t4); // T0 * T4
if (ut.bitGet(CURVE.x, i)) {
if ((0, utils_js_1.bitGet)(CURVE.x, i)) {
// Addition

@@ -43,9 +45,9 @@ let t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz

Fp2.sub(Fp2.mul(t0, Qx), Fp2.mul(t1, Qy)),
Fp2.negate(t0),
Fp2.neg(t0),
t1, // T1
]);
let t2 = Fp2.square(t1); // T1²
let t2 = Fp2.sqr(t1); // T1²
let t3 = Fp2.mul(t2, t1); // T2 * T1
let t4 = Fp2.mul(t2, Rx); // T2 * Rx
let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.square(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
Rx = Fp2.mul(t1, t5); // T1 * T5

@@ -66,3 +68,3 @@ Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry

f12 = Fp12.multiplyBy014(f12, E[0], Fp2.mul(E[1], Px), Fp2.mul(E[2], Py));
if (ut.bitGet(x, i)) {
if ((0, utils_js_1.bitGet)(x, i)) {
j += 1;

@@ -73,3 +75,3 @@ const F = ell[j];

if (i !== 0)
f12 = Fp12.square(f12);
f12 = Fp12.sqr(f12);
}

@@ -79,19 +81,11 @@ return Fp12.conjugate(f12);

const utils = {
hexToBytes: ut.hexToBytes,
bytesToHex: ut.bytesToHex,
stringToBytes: hash_to_curve_js_1.stringToBytes,
hexToBytes: utils_js_1.hexToBytes,
bytesToHex: utils_js_1.bytesToHex,
stringToBytes: htf.stringToBytes,
// TODO: do we need to export it here?
hashToField: (msg, count, options = {}) => (0, hash_to_curve_js_1.hash_to_field)(msg, count, { ...CURVE.htfDefaults, ...options }),
expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => (0, hash_to_curve_js_1.expand_message_xmd)(msg, DST, lenInBytes, H),
hashToPrivateKey: (hash) => Fr.toBytes(ut.hashToPrivateScalar(hash, CURVE.r)),
hashToField: (msg, count, options = {}) => htf.hash_to_field(msg, count, { ...CURVE.htfDefaults, ...options }),
expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => htf.expand_message_xmd(msg, DST, lenInBytes, H),
hashToPrivateKey: (hash) => Fr.toBytes((0, modular_js_1.hashToPrivateScalar)(hash, CURVE.r)),
randomBytes: (bytesLength = groupLen) => CURVE.randomBytes(bytesLength),
randomPrivateKey: () => utils.hashToPrivateKey(utils.randomBytes(groupLen + 8)),
getDSTLabel: () => CURVE.htfDefaults.DST,
setDSTLabel(newLabel) {
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3.1
if (typeof newLabel !== 'string' || newLabel.length > 2048 || newLabel.length === 0) {
throw new TypeError('Invalid DST');
}
CURVE.htfDefaults.DST = newLabel;
},
};

@@ -103,2 +97,6 @@ // Point on G1 curve: (x, y)

});
const G1HashToCurve = htf.hashToCurve(G1.ProjectivePoint, CURVE.G1.mapToCurve, {
...CURVE.htfDefaults,
...CURVE.G1.htfDefaults,
});
function pairingPrecomputes(point) {

@@ -108,13 +106,10 @@ const p = point;

return p._PPRECOMPUTES;
p._PPRECOMPUTES = calcPairingPrecomputes(p.x, p.y);
p._PPRECOMPUTES = calcPairingPrecomputes(point.toAffine());
return p._PPRECOMPUTES;
}
function clearPairingPrecomputes(point) {
const p = point;
p._PPRECOMPUTES = undefined;
}
clearPairingPrecomputes;
function millerLoopG1(Q, P) {
return millerLoop(pairingPrecomputes(P), [Q.x, Q.y]);
}
// TODO: export
// function clearPairingPrecomputes(point: G2) {
// const p = point as G2 & withPairingPrecomputes;
// p._PPRECOMPUTES = undefined;
// }
// Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)

@@ -125,21 +120,29 @@ const G2 = (0, weierstrass_js_1.weierstrassPoints)({

});
const C = G2.ProjectivePoint; // TODO: fix
const G2HashToCurve = htf.hashToCurve(C, CURVE.G2.mapToCurve, {
...CURVE.htfDefaults,
...CURVE.G2.htfDefaults,
});
const { Signature } = CURVE.G2;
// Calculates bilinear pairing
function pairing(P, Q, withFinalExponent = true) {
if (P.equals(G1.Point.ZERO) || Q.equals(G2.Point.ZERO))
throw new Error('No pairings at point of Infinity');
function pairing(Q, P, withFinalExponent = true) {
if (Q.equals(G1.ProjectivePoint.ZERO) || P.equals(G2.ProjectivePoint.ZERO))
throw new Error('pairing is not available for ZERO point');
Q.assertValidity();
P.assertValidity();
Q.assertValidity();
// Performance: 9ms for millerLoop and ~14ms for exp.
const looped = millerLoopG1(P, Q);
const Qa = Q.toAffine();
const looped = millerLoop(pairingPrecomputes(P), [Qa.x, Qa.y]);
return withFinalExponent ? Fp12.finalExponentiate(looped) : looped;
}
function normP1(point) {
return point instanceof G1.Point ? point : G1.Point.fromHex(point);
return point instanceof G1.ProjectivePoint ? point : G1.ProjectivePoint.fromHex(point);
}
function normP2(point) {
return point instanceof G2.Point ? point : Signature.decode(point);
return point instanceof G2.ProjectivePoint ? point : Signature.decode(point);
}
function normP2Hash(point) {
return point instanceof G2.Point ? point : G2.Point.hashToCurve(point);
function normP2Hash(point, htfOpts) {
return point instanceof G2.ProjectivePoint
? point
: G2HashToCurve.hashToCurve(point, htfOpts);
}

@@ -149,9 +152,9 @@ // Multiplies generator by private key.

function getPublicKey(privateKey) {
return G1.Point.fromPrivateKey(privateKey).toRawBytes(true);
return G1.ProjectivePoint.fromPrivateKey(privateKey).toRawBytes(true);
}
function sign(message, privateKey) {
const msgPoint = normP2Hash(message);
function sign(message, privateKey, htfOpts) {
const msgPoint = normP2Hash(message, htfOpts);
msgPoint.assertValidity();
const sigPoint = msgPoint.multiply(G1.normalizePrivateKey(privateKey));
if (message instanceof G2.Point)
if (message instanceof G2.ProjectivePoint)
return sigPoint;

@@ -162,6 +165,6 @@ return Signature.encode(sigPoint);

// e(P, H(m)) == e(G, S)
function verify(signature, message, publicKey) {
function verify(signature, message, publicKey, htfOpts) {
const P = normP1(publicKey);
const Hm = normP2Hash(message);
const G = G1.Point.BASE;
const Hm = normP2Hash(message, htfOpts);
const G = G1.ProjectivePoint.BASE;
const S = normP2(signature);

@@ -173,3 +176,3 @@ // Instead of doing 2 exponentiations, we use property of billinear maps

const exp = Fp12.finalExponentiate(Fp12.mul(eGS, ePHm));
return Fp12.equals(exp, Fp12.ONE);
return Fp12.eql(exp, Fp12.ONE);
}

@@ -179,7 +182,5 @@ function aggregatePublicKeys(publicKeys) {

throw new Error('Expected non-empty array');
const agg = publicKeys
.map(normP1)
.reduce((sum, p) => sum.add(G1.ProjectivePoint.fromAffine(p)), G1.ProjectivePoint.ZERO);
const aggAffine = agg.toAffine();
if (publicKeys[0] instanceof G1.Point) {
const agg = publicKeys.map(normP1).reduce((sum, p) => sum.add(p), G1.ProjectivePoint.ZERO);
const aggAffine = agg; //.toAffine();
if (publicKeys[0] instanceof G1.ProjectivePoint) {
aggAffine.assertValidity();

@@ -194,7 +195,5 @@ return aggAffine;

throw new Error('Expected non-empty array');
const agg = signatures
.map(normP2)
.reduce((sum, s) => sum.add(G2.ProjectivePoint.fromAffine(s)), G2.ProjectivePoint.ZERO);
const aggAffine = agg.toAffine();
if (signatures[0] instanceof G2.Point) {
const agg = signatures.map(normP2).reduce((sum, s) => sum.add(s), G2.ProjectivePoint.ZERO);
const aggAffine = agg; //.toAffine();
if (signatures[0] instanceof G2.ProjectivePoint) {
aggAffine.assertValidity();

@@ -207,3 +206,5 @@ return aggAffine;

// e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
function verifyBatch(signature, messages, publicKeys) {
function verifyBatch(signature, messages, publicKeys, htfOpts) {
// @ts-ignore
// console.log('verifyBatch', bytesToHex(signature as any), messages, publicKeys.map(bytesToHex));
if (!messages.length)

@@ -214,3 +215,3 @@ throw new Error('Expected non-empty messages array');

const sig = normP2(signature);
const nMessages = messages.map(normP2Hash);
const nMessages = messages.map((i) => normP2Hash(i, htfOpts));
const nPublicKeys = publicKeys.map(normP1);

@@ -220,3 +221,3 @@ try {

for (const message of new Set(nMessages)) {
const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.Point.ZERO);
const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.ProjectivePoint.ZERO);
// const msg = message instanceof PointG2 ? message : await PointG2.hashToCurve(message);

@@ -226,6 +227,6 @@ // Possible to batch pairing for same msg with different groupPublicKey here

}
paired.push(pairing(G1.Point.BASE.negate(), sig, false));
paired.push(pairing(G1.ProjectivePoint.BASE.negate(), sig, false));
const product = paired.reduce((a, b) => Fp12.mul(a, b), Fp12.ONE);
const exp = Fp12.finalExponentiate(product);
return Fp12.equals(exp, Fp12.ONE);
return Fp12.eql(exp, Fp12.ONE);
}

@@ -236,4 +237,3 @@ catch {

}
// Pre-compute points. Refer to README.
G1.Point.BASE._setWindowSize(4);
G1.ProjectivePoint.BASE._setWindowSize(4);
return {

@@ -251,2 +251,3 @@ CURVE,

calcPairingPrecomputes,
hashToCurve: { G1: G1HashToCurve, G2: G2HashToCurve },
pairing,

@@ -253,0 +254,0 @@ getPublicKey,

@@ -1,11 +0,7 @@

/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import * as mod from './modular.js';
import * as ut from './utils.js';
import { Hex, PrivKey } from './utils.js';
import { Group, GroupConstructor } from './group.js';
import { htfOpts } from './hash-to-curve.js';
export declare type CurveType = ut.BasicCurve<bigint> & {
import { FHash, Hex } from './utils.js';
import { Group, GroupConstructor, AbstractCurve, AffinePoint } from './curve.js';
export declare type CurveType = AbstractCurve<bigint> & {
a: bigint;
d: bigint;
hash: ut.CHash;
hash: FHash;
randomBytes: (bytesLength?: number) => Uint8Array;

@@ -18,8 +14,4 @@ adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array;

};
preHash?: ut.CHash;
htfDefaults?: htfOpts;
mapToCurve?: (scalar: bigint[]) => {
x: bigint;
y: bigint;
};
preHash?: FHash;
mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>;
};

@@ -29,3 +21,3 @@ declare function validateOpts(curve: CurveType): Readonly<{

readonly nByteLength: number;
readonly Fp: mod.Field<bigint>;
readonly Fp: import("./modular.js").Field<bigint>;
readonly n: bigint;

@@ -40,3 +32,3 @@ readonly h: bigint;

readonly d: bigint;
readonly hash: ut.CHash;
readonly hash: FHash;
readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;

@@ -49,71 +41,37 @@ readonly adjustScalarBytes?: ((bytes: Uint8Array) => Uint8Array) | undefined;

}) | undefined;
readonly preHash?: ut.CHash | undefined;
readonly htfDefaults?: htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly preHash?: FHash | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => AffinePoint<bigint>) | undefined;
}>;
export interface SignatureType {
readonly r: PointType;
readonly s: bigint;
assertValidity(): SignatureType;
toRawBytes(): Uint8Array;
toHex(): string;
}
export declare type SignatureConstructor = {
new (r: PointType, s: bigint): SignatureType;
fromHex(hex: Hex): SignatureType;
};
export interface ExtendedPointType extends Group<ExtendedPointType> {
readonly x: bigint;
readonly y: bigint;
readonly z: bigint;
readonly t: bigint;
multiply(scalar: number | bigint, affinePoint?: PointType): ExtendedPointType;
multiplyUnsafe(scalar: number | bigint): ExtendedPointType;
export interface ExtPointType extends Group<ExtPointType> {
readonly ex: bigint;
readonly ey: bigint;
readonly ez: bigint;
readonly et: bigint;
assertValidity(): void;
multiply(scalar: bigint): ExtPointType;
multiplyUnsafe(scalar: bigint): ExtPointType;
isSmallOrder(): boolean;
isTorsionFree(): boolean;
toAffine(invZ?: bigint): PointType;
clearCofactor(): ExtendedPointType;
clearCofactor(): ExtPointType;
toAffine(iz?: bigint): AffinePoint<bigint>;
}
export interface ExtendedPointConstructor extends GroupConstructor<ExtendedPointType> {
new (x: bigint, y: bigint, z: bigint, t: bigint): ExtendedPointType;
fromAffine(p: PointType): ExtendedPointType;
toAffineBatch(points: ExtendedPointType[]): PointType[];
normalizeZ(points: ExtendedPointType[]): ExtendedPointType[];
export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType;
fromAffine(p: AffinePoint<bigint>): ExtPointType;
fromHex(hex: Hex): ExtPointType;
fromPrivateKey(privateKey: Hex): ExtPointType;
}
export interface PointType extends Group<PointType> {
readonly x: bigint;
readonly y: bigint;
_setWindowSize(windowSize: number): void;
toRawBytes(isCompressed?: boolean): Uint8Array;
toHex(isCompressed?: boolean): string;
isTorsionFree(): boolean;
clearCofactor(): PointType;
}
export interface PointConstructor extends GroupConstructor<PointType> {
new (x: bigint, y: bigint): PointType;
fromHex(hex: Hex): PointType;
fromPrivateKey(privateKey: PrivKey): PointType;
hashToCurve(msg: Hex, options?: Partial<htfOpts>): PointType;
encodeToCurve(msg: Hex, options?: Partial<htfOpts>): PointType;
}
export declare type PubKey = Hex | PointType;
export declare type SigType = Hex | SignatureType;
export declare type CurveFn = {
CURVE: ReturnType<typeof validateOpts>;
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
getPublicKey: (privateKey: Hex) => Uint8Array;
sign: (message: Hex, privateKey: Hex) => Uint8Array;
verify: (sig: SigType, message: Hex, publicKey: PubKey) => boolean;
Point: PointConstructor;
ExtendedPoint: ExtendedPointConstructor;
Signature: SignatureConstructor;
verify: (sig: Hex, message: Hex, publicKey: Hex) => boolean;
ExtendedPoint: ExtPointConstructor;
utils: {
randomPrivateKey: () => Uint8Array;
getExtendedPublicKey: (key: PrivKey) => {
getExtendedPublicKey: (key: Hex) => {
head: Uint8Array;
prefix: Uint8Array;
scalar: bigint;
point: PointType;
point: ExtPointType;
pointBytes: Uint8Array;

@@ -120,0 +78,0 @@ };

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.twistedEdwards = void 0;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// 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:
// 1. Variable field element lengths between EDDSA/ECDH:
// EDDSA (RFC8032) is 456 bits / 57 bytes, ECDH (RFC7748) is 448 bits / 56 bytes
// 2. Different addition formula (doubling is same)
// 3. uvRatio differs between curves (half-expected, not only pow fn changes)
// 4. Point decompression code is different (unexpected), now using generalized formula
// 5. Domain function was no-op for ed25519, but adds some data even with empty context for ed448
const mod = require("./modular.js");
const ut = require("./utils.js");
const modular_js_1 = require("./modular.js");
const utils_js_1 = require("./utils.js");
const group_js_1 = require("./group.js");
const hash_to_curve_js_1 = require("./hash-to-curve.js");
const curve_js_1 = require("./curve.js");
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n

@@ -24,4 +15,4 @@ const _0n = BigInt(0);

function validateOpts(curve) {
const opts = ut.validateOpts(curve);
if (typeof opts.hash !== 'function' || !ut.isPositiveInt(opts.hash.outputLen))
const opts = (0, curve_js_1.validateAbsOpts)(curve);
if (typeof opts.hash !== 'function')
throw new Error('Invalid hash function');

@@ -43,16 +34,11 @@ for (const i of ['a', 'd']) {

}
if (opts.htfDefaults !== undefined)
(0, hash_to_curve_js_1.validateHTFOpts)(opts.htfDefaults);
// Set defaults
return Object.freeze({ ...opts });
}
// NOTE: it is not generic twisted curve for now, but ed25519/ed448 generic implementation
// It is not generic twisted curve for now, but ed25519/ed448 generic implementation
function twistedEdwards(curveDef) {
const CURVE = validateOpts(curveDef);
const Fp = CURVE.Fp;
const CURVE_ORDER = CURVE.n;
const maxGroupElement = _2n ** BigInt(CURVE.nByteLength * 8);
// Function overrides
const { randomBytes } = CURVE;
const modP = Fp.create;
const { Fp, n: CURVE_ORDER, preHash, hash: cHash, randomBytes, nByteLength, h: cofactor } = CURVE;
const MASK = _2n ** BigInt(nByteLength * 8);
const modP = Fp.create; // Function overrides
// sqrt(u/v)

@@ -62,3 +48,3 @@ const uvRatio = CURVE.uvRatio ||

try {
return { isValid: true, value: Fp.sqrt(u * Fp.invert(v)) };
return { isValid: true, value: Fp.sqrt(u * Fp.inv(v)) };
}

@@ -76,37 +62,66 @@ catch (e) {

}); // NOOP
/**
* Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
* Default Point works in affine coordinates: (x, y)
* https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates
*/
class ExtendedPoint {
constructor(x, y, z, t) {
this.x = x;
this.y = y;
this.z = z;
this.t = t;
const inBig = (n) => typeof n === 'bigint' && 0n < n; // n in [1..]
const inRange = (n, max) => inBig(n) && inBig(max) && n < max; // n in [1..max-1]
const in0MaskRange = (n) => n === _0n || inRange(n, MASK); // n in [0..MASK-1]
function assertInRange(n, max) {
// n in [1..max-1]
if (inRange(n, max))
return n;
throw new Error(`Expected valid scalar < ${max}, got ${typeof n} ${n}`);
}
function assertGE0(n) {
// n in [0..CURVE_ORDER-1]
return n === _0n ? n : assertInRange(n, CURVE_ORDER); // GE = prime subgroup, not full group
}
const pointPrecomputes = new Map();
function isPoint(other) {
if (!(other instanceof Point))
throw new Error('ExtendedPoint expected');
}
// Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
// https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates
class Point {
constructor(ex, ey, ez, et) {
this.ex = ex;
this.ey = ey;
this.ez = ez;
this.et = et;
if (!in0MaskRange(ex))
throw new Error('x required');
if (!in0MaskRange(ey))
throw new Error('y required');
if (!in0MaskRange(ez))
throw new Error('z required');
if (!in0MaskRange(et))
throw new Error('t required');
}
get x() {
return this.toAffine().x;
}
get y() {
return this.toAffine().y;
}
static fromAffine(p) {
if (!(p instanceof Point)) {
throw new TypeError('ExtendedPoint#fromAffine: expected Point');
}
if (p.equals(Point.ZERO))
return ExtendedPoint.ZERO;
return new ExtendedPoint(p.x, p.y, _1n, modP(p.x * p.y));
if (p instanceof Point)
throw new Error('extended point not allowed');
const { x, y } = p || {};
if (!in0MaskRange(x) || !in0MaskRange(y))
throw new Error('invalid affine point');
return new Point(x, y, _1n, modP(x * y));
}
// Takes a bunch of Jacobian Points but executes only one
// invert on all of them. invert is very slow operation,
// so this improves performance massively.
static toAffineBatch(points) {
const toInv = Fp.invertBatch(points.map((p) => p.z));
return points.map((p, i) => p.toAffine(toInv[i]));
}
static normalizeZ(points) {
return this.toAffineBatch(points).map(this.fromAffine);
const toInv = Fp.invertBatch(points.map((p) => p.ez));
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
}
// "Private method", don't use it directly
_setWindowSize(windowSize) {
this._WINDOW_SIZE = windowSize;
pointPrecomputes.delete(this);
}
assertValidity() { }
// Compare one point to another.
equals(other) {
assertExtPoint(other);
const { x: X1, y: Y1, z: Z1 } = this;
const { x: X2, y: Y2, z: Z2 } = other;
isPoint(other);
const { ex: X1, ey: Y1, ez: Z1 } = this;
const { ex: X2, ey: Y2, ez: Z2 } = other;
const X1Z2 = modP(X1 * Z2);

@@ -118,5 +133,8 @@ const X2Z1 = modP(X2 * Z1);

}
// Inverses point to one corresponding to (x, -y) in Affine coordinates.
is0() {
return this.equals(Point.ZERO);
}
negate() {
return new ExtendedPoint(modP(-this.x), this.y, this.z, modP(-this.t));
// Flips point sign to a negative one (-x, y in affine coords)
return new Point(modP(-this.ex), this.ey, this.ez, modP(-this.et));
}

@@ -128,3 +146,3 @@ // Fast algo for doubling Extended Point.

const { a } = CURVE;
const { x: X1, y: Y1, z: Z1 } = this;
const { ex: X1, ey: Y1, ez: Z1 } = this;
const A = modP(X1 * X1); // A = X12

@@ -143,3 +161,3 @@ const B = modP(Y1 * Y1); // B = Y12

const Z3 = modP(F * G); // Z3 = F*G
return new ExtendedPoint(X3, Y3, Z3, T3);
return new Point(X3, Y3, Z3, T3);
}

@@ -150,6 +168,6 @@ // Fast algo for adding 2 Extended Points.

add(other) {
assertExtPoint(other);
isPoint(other);
const { a, d } = CURVE;
const { x: X1, y: Y1, z: Z1, t: T1 } = this;
const { x: X2, y: Y2, z: Z2, t: T2 } = other;
const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
const { ex: X2, ey: Y2, ez: Z2, et: T2 } = other;
// Faster algo for adding 2 Extended Points when curve's a=-1.

@@ -174,3 +192,3 @@ // http://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-4

const Z3 = modP(F * G);
return new ExtendedPoint(X3, Y3, Z3, T3);
return new Point(X3, Y3, Z3, T3);
}

@@ -189,3 +207,3 @@ const A = modP(X1 * X2); // A = X1*X2

const Z3 = modP(F * G); // Z3 = F*G
return new ExtendedPoint(X3, Y3, Z3, T3);
return new Point(X3, Y3, Z3, T3);
}

@@ -195,22 +213,9 @@ subtract(other) {

}
wNAF(n, affinePoint) {
if (!affinePoint && this.equals(ExtendedPoint.BASE))
affinePoint = Point.BASE;
const W = (affinePoint && affinePoint._WINDOW_SIZE) || 1;
let precomputes = affinePoint && pointPrecomputes.get(affinePoint);
if (!precomputes) {
precomputes = wnaf.precomputeWindow(this, W);
if (affinePoint && W !== 1) {
precomputes = ExtendedPoint.normalizeZ(precomputes);
pointPrecomputes.set(affinePoint, precomputes);
}
}
const { p, f } = wnaf.wNAF(W, precomputes, n);
return ExtendedPoint.normalizeZ([p, f])[0];
wNAF(n) {
return wnaf.wNAFCached(this, pointPrecomputes, n, Point.normalizeZ);
}
// Constant time multiplication.
// Uses wNAF method. Windowed method may be 10% faster,
// but takes 2x longer to generate and consumes 2x memory.
multiply(scalar, affinePoint) {
return this.wNAF(normalizeScalar(scalar, CURVE_ORDER), affinePoint);
// Constant-time multiplication.
multiply(scalar) {
const { p, f } = this.wNAF(assertInRange(scalar, CURVE_ORDER));
return Point.normalizeZ([p, f])[0];
}

@@ -221,10 +226,9 @@ // Non-constant-time multiplication. Uses double-and-add algorithm.

multiplyUnsafe(scalar) {
let n = normalizeScalar(scalar, CURVE_ORDER, false);
const P0 = ExtendedPoint.ZERO;
let n = assertGE0(scalar);
if (n === _0n)
return P0;
if (this.equals(P0) || n === _1n)
return I;
if (this.equals(I) || n === _1n)
return this;
if (this.equals(ExtendedPoint.BASE))
return this.wNAF(n);
if (this.equals(G))
return this.wNAF(n).p;
return wnaf.unsafeLadder(this, n);

@@ -237,24 +241,24 @@ }

isSmallOrder() {
return this.multiplyUnsafe(CURVE.h).equals(ExtendedPoint.ZERO);
return this.multiplyUnsafe(cofactor).is0();
}
// Multiplies point by curve order (very big scalar CURVE.n) and checks if the result is 0.
// Multiplies point by curve order and checks if the result is 0.
// Returns `false` is the point is dirty.
isTorsionFree() {
return wnaf.unsafeLadder(this, CURVE_ORDER).equals(ExtendedPoint.ZERO);
return wnaf.unsafeLadder(this, CURVE_ORDER).is0();
}
// Converts Extended point to default (x, y) coordinates.
// Can accept precomputed Z^-1 - for example, from invertBatch.
toAffine(invZ) {
const { x, y, z } = this;
const is0 = this.equals(ExtendedPoint.ZERO);
if (invZ == null)
invZ = is0 ? _8n : Fp.invert(z); // 8 was chosen arbitrarily
const ax = modP(x * invZ);
const ay = modP(y * invZ);
const zz = modP(z * invZ);
toAffine(iz) {
const { ex: x, ey: y, ez: z } = this;
const is0 = this.is0();
if (iz == null)
iz = is0 ? _8n : Fp.inv(z); // 8 was chosen arbitrarily
const ax = modP(x * iz);
const ay = modP(y * iz);
const zz = modP(z * iz);
if (is0)
return Point.ZERO;
return { x: _0n, y: _1n };
if (zz !== _1n)
throw new Error('invZ was invalid');
return new Point(ax, ay);
return { x: ax, y: ay };
}

@@ -267,25 +271,2 @@ clearCofactor() {

}
}
ExtendedPoint.BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
ExtendedPoint.ZERO = new ExtendedPoint(_0n, _1n, _1n, _0n);
const wnaf = (0, group_js_1.wNAF)(ExtendedPoint, CURVE.nByteLength * 8);
function assertExtPoint(other) {
if (!(other instanceof ExtendedPoint))
throw new TypeError('ExtendedPoint expected');
}
// Stores precomputed values for points.
const pointPrecomputes = new WeakMap();
/**
* Default Point works in affine coordinates: (x, y)
*/
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
// "Private method", don't use it directly.
_setWindowSize(windowSize) {
this._WINDOW_SIZE = windowSize;
pointPrecomputes.delete(this);
}
// Converts hash string or Uint8Array to Point.

@@ -296,274 +277,118 @@ // Uses algo from RFC8032 5.1.3.

const len = Fp.BYTES;
hex = (0, utils_js_1.ensureBytes)(hex, len);
// 1. First, interpret the string as an integer in little-endian
// representation. Bit 255 of this number is the least significant
// bit of the x-coordinate and denote this value x_0. The
// y-coordinate is recovered simply by clearing this bit. If the
// resulting value is >= p, decoding fails.
const normed = hex.slice();
const lastByte = hex[len - 1];
normed[len - 1] = lastByte & ~0x80;
const y = ut.bytesToNumberLE(normed);
if (strict && y >= Fp.ORDER)
throw new Error('Expected 0 < hex < P');
if (!strict && y >= maxGroupElement)
throw new Error('Expected 0 < hex < CURVE.n');
// 2. To recover the x-coordinate, the curve equation implies
// Ed25519: x² = (y² - 1) / (d y² + 1) (mod p).
// Ed448: x² = (y² - 1) / (d y² - 1) (mod p).
// For generic case:
// a*x²+y²=1+d*x²*y²
// -> y²-1 = d*x²*y²-a*x²
// -> y²-1 = x² (d*y²-a)
// -> x² = (y²-1) / (d*y²-a)
// The denominator is always non-zero mod p. Let u = y² - 1 and v = d y² + 1.
const y2 = modP(y * y);
const u = modP(y2 - _1n);
const v = modP(d * y2 - a);
let { isValid, value: x } = uvRatio(u, v);
hex = (0, utils_js_1.ensureBytes)(hex, len); // copy hex to a new array
const normed = hex.slice(); // copy again, we'll manipulate it
const lastByte = hex[len - 1]; // select last byte
normed[len - 1] = lastByte & ~0x80; // clear last bit
const y = (0, utils_js_1.bytesToNumberLE)(normed);
if (y === _0n) {
// y=0 is allowed
}
else {
// RFC8032 prohibits >= p, but ZIP215 doesn't
if (strict)
assertInRange(y, Fp.ORDER); // strict=true [1..P-1] (2^255-19-1 for ed25519)
else
assertInRange(y, MASK); // strict=false [1..MASK-1] (2^256-1 for ed25519)
}
// Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:
// ax²+y²=1+dx²y² => y²-1=dx²y²-ax² => y²-1=x²(dy²-a) => x²=(y²-1)/(dy²-a)
const y2 = modP(y * y); // denominator is always non-0 mod p.
const u = modP(y2 - _1n); // u = y² - 1
const v = modP(d * y2 - a); // v = d y² + 1.
let { isValid, value: x } = uvRatio(u, v); // √(u/v)
if (!isValid)
throw new Error('Point.fromHex: invalid y coordinate');
// 4. Finally, use the x_0 bit to select the right square root. If
// x = 0, and x_0 = 1, decoding fails. Otherwise, if x_0 != x mod
// 2, set x <-- p - x. Return the decoded point (x,y).
const isXOdd = (x & _1n) === _1n;
const isLastByteOdd = (lastByte & 0x80) !== 0;
const isXOdd = (x & _1n) === _1n; // There are 2 square roots. Use x_0 bit to select proper
const isLastByteOdd = (lastByte & 0x80) !== 0; // if x=0 and x_0 = 1, fail
if (isLastByteOdd !== isXOdd)
x = modP(-x);
return new Point(x, y);
x = modP(-x); // if x_0 != x mod 2, set x = p-x
return Point.fromAffine({ x, y });
}
static fromPrivateKey(privateKey) {
return getExtendedPublicKey(privateKey).point;
static fromPrivateKey(privKey) {
return getExtendedPublicKey(privKey).point;
}
// There can always be only two x values (x, -x) for any y
// When compressing point, it's enough to only store its y coordinate
// and use the last byte to encode sign of x.
toRawBytes() {
const bytes = ut.numberToBytesLE(this.y, Fp.BYTES);
bytes[Fp.BYTES - 1] |= this.x & _1n ? 0x80 : 0;
return bytes;
const { x, y } = this.toAffine();
const bytes = (0, utils_js_1.numberToBytesLE)(y, Fp.BYTES); // each y has 2 x values (x, -y)
bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y
return bytes; // and use the last byte to encode sign of x
}
// Same as toRawBytes, but returns string.
toHex() {
return ut.bytesToHex(this.toRawBytes());
return (0, utils_js_1.bytesToHex)(this.toRawBytes()); // Same as toRawBytes, but returns string.
}
// Determines if point is in prime-order subgroup.
// Returns `false` is the point is dirty.
isTorsionFree() {
return ExtendedPoint.fromAffine(this).isTorsionFree();
}
equals(other) {
if (!(other instanceof Point))
throw new TypeError('Point#equals: expected Point');
return this.x === other.x && this.y === other.y;
}
negate() {
return new Point(modP(-this.x), this.y);
}
double() {
return ExtendedPoint.fromAffine(this).double().toAffine();
}
add(other) {
return ExtendedPoint.fromAffine(this).add(ExtendedPoint.fromAffine(other)).toAffine();
}
subtract(other) {
return this.add(other.negate());
}
/**
* Constant time multiplication.
* @param scalar Big-Endian number
* @returns new point
*/
multiply(scalar) {
return ExtendedPoint.fromAffine(this).multiply(scalar, this).toAffine();
}
clearCofactor() {
return ExtendedPoint.fromAffine(this).clearCofactor().toAffine();
}
// 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) {
const { mapToCurve, htfDefaults } = CURVE;
if (!mapToCurve)
throw new Error('No mapToCurve defined for curve');
const u = (0, hash_to_curve_js_1.hash_to_field)((0, utils_js_1.ensureBytes)(msg), 2, { ...htfDefaults, ...options });
const { x: x0, y: y0 } = mapToCurve(u[0]);
const { x: x1, y: y1 } = 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) {
const { mapToCurve, htfDefaults } = CURVE;
if (!mapToCurve)
throw new Error('No mapToCurve defined for curve');
const u = (0, hash_to_curve_js_1.hash_to_field)((0, utils_js_1.ensureBytes)(msg), 1, { ...htfDefaults, ...options });
const { x, y } = mapToCurve(u[0]);
return new Point(x, y).clearCofactor();
}
}
// Base point aka generator
// public_key = Point.BASE * private_key
Point.BASE = new Point(CURVE.Gx, CURVE.Gy);
// Identity point aka point at infinity
// point = point + zero_point
Point.ZERO = new Point(_0n, _1n);
/**
* EDDSA signature.
*/
class Signature {
constructor(r, s) {
this.r = r;
this.s = s;
this.assertValidity();
}
static fromHex(hex) {
const len = Fp.BYTES;
const bytes = (0, utils_js_1.ensureBytes)(hex, 2 * len);
const r = Point.fromHex(bytes.slice(0, len), false);
const s = ut.bytesToNumberLE(bytes.slice(len, 2 * len));
return new Signature(r, s);
}
assertValidity() {
const { r, s } = this;
if (!(r instanceof Point))
throw new Error('Expected Point instance');
// 0 <= s < l
normalizeScalar(s, CURVE_ORDER, false);
return this;
}
toRawBytes() {
return ut.concatBytes(this.r.toRawBytes(), ut.numberToBytesLE(this.s, Fp.BYTES));
}
toHex() {
return ut.bytesToHex(this.toRawBytes());
}
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
Point.ZERO = new Point(_0n, _1n, _1n, _0n); // 0, 1, 1, 0
const { BASE: G, ZERO: I } = Point;
const wnaf = (0, curve_js_1.wNAF)(Point, nByteLength * 8);
function modN(a) {
return (0, modular_js_1.mod)(a, CURVE_ORDER);
}
// Little-endian SHA512 with modulo n
function modnLE(hash) {
return mod.mod(ut.bytesToNumberLE(hash), CURVE_ORDER);
function modN_LE(hash) {
return modN((0, utils_js_1.bytesToNumberLE)(hash));
}
/**
* Checks for num to be in range:
* For strict == true: `0 < num < max`.
* For strict == false: `0 <= num < max`.
* Converts non-float safe numbers to bigints.
*/
function normalizeScalar(num, max, strict = true) {
if (!max)
throw new TypeError('Specify max value');
if (ut.isPositiveInt(num))
num = BigInt(num);
if (typeof num === 'bigint' && num < max) {
if (strict) {
if (_0n < num)
return num;
}
else {
if (_0n <= num)
return num;
}
}
throw new TypeError(`Expected valid scalar: 0 < scalar < ${max}`);
function isHex(item, err) {
if (typeof item !== 'string' && !(item instanceof Uint8Array))
throw new Error(`${err} must be hex string or Uint8Array`);
}
/** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */
function getExtendedPublicKey(key) {
const groupLen = CURVE.nByteLength;
// Normalize bigint / number / string to Uint8Array
const keyb = typeof key === 'bigint' || typeof key === 'number'
? ut.numberToBytesLE(normalizeScalar(key, maxGroupElement), groupLen)
: key;
isHex(key, 'private key');
const len = nByteLength;
// Hash private key with curve's hash function to produce uniformingly random input
// We check byte lengths e.g.: ensureBytes(64, hash(ensureBytes(32, key)))
const hashed = (0, utils_js_1.ensureBytes)(CURVE.hash((0, utils_js_1.ensureBytes)(keyb, groupLen)), 2 * groupLen);
// First half's bits are cleared to produce a random field element.
const head = adjustScalarBytes(hashed.slice(0, groupLen));
// Second half is called key prefix (5.1.6)
const prefix = hashed.slice(groupLen, 2 * groupLen);
// The actual private scalar
const scalar = modnLE(head);
// Point on Edwards curve aka public key
const point = Point.BASE.multiply(scalar);
// Uint8Array representation
const pointBytes = point.toRawBytes();
// Check byte lengths: ensure(64, h(ensure(32, key)))
const hashed = (0, utils_js_1.ensureBytes)(cHash((0, utils_js_1.ensureBytes)(key, len)), 2 * len);
const head = adjustScalarBytes(hashed.slice(0, len)); // clear first half bits, produce FE
const prefix = hashed.slice(len, 2 * len); // second half is called key prefix (5.1.6)
const scalar = modN_LE(head); // The actual private scalar
const point = G.multiply(scalar); // Point on Edwards curve aka public key
const pointBytes = point.toRawBytes(); // Uint8Array representation
return { head, prefix, scalar, point, pointBytes };
}
/**
* Calculates ed25519 public key. RFC8032 5.1.5
* 1. private key is hashed with sha512, then first 32 bytes are taken from the hash
* 2. 3 least significant bits of the first byte are cleared
*/
function getPublicKey(privateKey) {
return getExtendedPublicKey(privateKey).pointBytes;
// Calculates EdDSA pub key. RFC8032 5.1.5. Privkey is hashed. Use first half with 3 bits cleared
function getPublicKey(privKey) {
return getExtendedPublicKey(privKey).pointBytes;
}
const EMPTY = new Uint8Array();
function hashDomainToScalar(message, context = EMPTY) {
context = (0, utils_js_1.ensureBytes)(context);
return modnLE(CURVE.hash(domain(message, context, !!CURVE.preHash)));
// int('LE', SHA512(dom2(F, C) || msgs)) mod N
function hashDomainToScalar(context = new Uint8Array(), ...msgs) {
const msg = (0, utils_js_1.concatBytes)(...msgs);
return modN_LE(cHash(domain(msg, (0, utils_js_1.ensureBytes)(context), !!preHash)));
}
/** Signs message with privateKey. RFC8032 5.1.6 */
function sign(message, privateKey, context) {
message = (0, utils_js_1.ensureBytes)(message);
if (CURVE.preHash)
message = CURVE.preHash(message);
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privateKey);
const r = hashDomainToScalar(ut.concatBytes(prefix, message), context);
const R = Point.BASE.multiply(r); // R = rG
const k = hashDomainToScalar(ut.concatBytes(R.toRawBytes(), pointBytes, message), context); // k = hash(R+P+msg)
const s = mod.mod(r + k * scalar, CURVE_ORDER); // s = r + kp
return new Signature(R, s).toRawBytes();
function sign(msg, privKey, context) {
isHex(msg, 'message');
msg = (0, utils_js_1.ensureBytes)(msg);
if (preHash)
msg = preHash(msg); // for ed25519ph etc.
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
const r = hashDomainToScalar(context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
const R = G.multiply(r).toRawBytes(); // R = rG
const k = hashDomainToScalar(context, R, pointBytes, msg); // R || A || PH(M)
const s = modN(r + k * scalar); // S = (r + k * s) mod L
assertGE0(s); // 0 <= s < l
const res = (0, utils_js_1.concatBytes)(R, (0, utils_js_1.numberToBytesLE)(s, Fp.BYTES));
return (0, utils_js_1.ensureBytes)(res, nByteLength * 2); // 64-byte signature
}
/**
* Verifies EdDSA signature against message and public key.
* An extended group equation is checked.
* RFC8032 5.1.7
* Compliant with ZIP215:
* 0 <= sig.R/publicKey < 2**256 (can be >= curve.P)
* 0 <= sig.s < l
* Not compliant with RFC8032: it's not possible to comply to both ZIP & RFC at the same time.
*/
function verify(sig, message, publicKey, context) {
message = (0, utils_js_1.ensureBytes)(message);
if (CURVE.preHash)
message = CURVE.preHash(message);
// When hex is passed, we check public key fully.
// When Point instance is passed, we assume it has already been checked, for performance.
// If user passes Point/Sig instance, we assume it has been already verified.
// We don't check its equations for performance. We do check for valid bounds for s though
// We always check for: a) s bounds. b) hex validity
if (publicKey instanceof Point) {
// ignore
}
else if (publicKey instanceof Uint8Array || typeof publicKey === 'string') {
publicKey = Point.fromHex(publicKey, false);
}
else {
throw new Error(`Invalid publicKey: ${publicKey}`);
}
if (sig instanceof Signature)
sig.assertValidity();
else if (sig instanceof Uint8Array || typeof sig === 'string')
sig = Signature.fromHex(sig);
else
throw new Error(`Wrong signature: ${sig}`);
const { r, s } = sig;
const SB = ExtendedPoint.BASE.multiplyUnsafe(s);
const k = hashDomainToScalar(ut.concatBytes(r.toRawBytes(), publicKey.toRawBytes(), message), context);
const kA = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(k);
const RkA = ExtendedPoint.fromAffine(r).add(kA);
function verify(sig, msg, publicKey, context) {
isHex(sig, 'sig');
isHex(msg, 'message');
const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
sig = (0, utils_js_1.ensureBytes)(sig, 2 * len); // An extended group equation is checked.
msg = (0, utils_js_1.ensureBytes)(msg); // ZIP215 compliant, which means not fully RFC8032 compliant.
if (preHash)
msg = preHash(msg); // for ed25519ph, etc
const A = Point.fromHex(publicKey, false); // Check for s bounds, hex validity
const R = Point.fromHex(sig.slice(0, len), false); // 0 <= R < 2^256: ZIP215 R can be >= P
const s = (0, utils_js_1.bytesToNumberLE)(sig.slice(len, 2 * len)); // 0 <= s < l
const SB = G.multiplyUnsafe(s);
const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
const RkA = R.add(A.multiplyUnsafe(k));
// [8][S]B = [8]R + [8][k]A'
return RkA.subtract(SB).clearCofactor().equals(ExtendedPoint.ZERO);
return RkA.subtract(SB).clearCofactor().equals(Point.ZERO);
}
// Enable precomputes. Slows down first publicKey computation by 20ms.
Point.BASE._setWindowSize(8);
G._setWindowSize(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
const utils = {
getExtendedPublicKey,
/**
* Not needed for ed25519 private keys. Needed if you use scalars directly (rare).
*/
hashToPrivateScalar: (hash) => ut.hashToPrivateScalar(hash, CURVE_ORDER, true),
/**
* ed25519 private keys are uniform 32-bit strings. We do not need to check for
* modulo bias like we do in secp256k1 randomPrivateKey()
*/
// ed25519 private keys are uniform 32b. No need to check for modulo bias, like in secp256k1.
randomPrivateKey: () => randomBytes(Fp.BYTES),

@@ -577,6 +402,5 @@ /**

precompute(windowSize = 8, point = Point.BASE) {
const cached = point.equals(Point.BASE) ? point : new Point(point.x, point.y);
cached._setWindowSize(windowSize);
cached.multiply(_2n);
return cached;
point._setWindowSize(windowSize);
point.multiply(BigInt(3));
return point;
},

@@ -589,5 +413,3 @@ };

verify,
ExtendedPoint,
Point,
Signature,
ExtendedPoint: Point,
utils,

@@ -594,0 +416,0 @@ };

/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import { CHash } from './utils.js';
import * as mod from './modular.js';
export declare type htfOpts = {
import type { Group, GroupConstructor, AffinePoint } from './curve.js';
import { Field } from './modular.js';
import { CHash, Hex } from './utils.js';
export declare type Opts = {
DST: string;
encodeDST: string;
p: bigint;

@@ -12,3 +14,3 @@ m: number;

};
export declare function validateHTFOpts(opts: htfOpts): void;
export declare function validateOpts(opts: Opts): void;
export declare function stringToBytes(str: string): Uint8Array;

@@ -25,6 +27,23 @@ export declare function expand_message_xmd(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H: CHash): Uint8Array;

*/
export declare function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
export declare function isogenyMap<T, F extends mod.Field<T>>(field: F, map: [T[], T[], T[], T[]]): (x: T, y: T) => {
export declare function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][];
export declare function isogenyMap<T, F extends Field<T>>(field: F, map: [T[], T[], T[], T[]]): (x: T, y: T) => {
x: T;
y: T;
};
export interface H2CPoint<T> extends Group<H2CPoint<T>> {
add(rhs: H2CPoint<T>): H2CPoint<T>;
toAffine(iz?: bigint): AffinePoint<T>;
clearCofactor(): H2CPoint<T>;
assertValidity(): void;
}
export interface H2CPointConstructor<T> extends GroupConstructor<H2CPoint<T>> {
fromAffine(ap: AffinePoint<T>): H2CPoint<T>;
}
export declare type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
export declare type htfBasicOpts = {
DST: string;
};
export declare function hashToCurve<T>(Point: H2CPointConstructor<T>, mapToCurve: MapToCurve<T>, def: Opts): {
hashToCurve(msg: Hex, options?: htfBasicOpts): H2CPoint<T>;
encodeToCurve(msg: Hex, options?: htfBasicOpts): H2CPoint<T>;
};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isogenyMap = exports.hash_to_field = exports.expand_message_xof = exports.expand_message_xmd = exports.stringToBytes = exports.validateHTFOpts = void 0;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
exports.hashToCurve = exports.isogenyMap = exports.hash_to_field = exports.expand_message_xof = exports.expand_message_xmd = exports.stringToBytes = exports.validateOpts = void 0;
const modular_js_1 = require("./modular.js");
const utils_js_1 = require("./utils.js");
const mod = require("./modular.js");
function validateHTFOpts(opts) {
function validateOpts(opts) {
if (typeof opts.DST !== 'string')

@@ -21,10 +20,8 @@ throw new Error('Invalid htf/DST');

}
exports.validateHTFOpts = validateHTFOpts;
// UTF8 to ui8a
// TODO: looks broken, ASCII only, why not TextEncoder/TextDecoder? it is in hashes anyway
exports.validateOpts = validateOpts;
function stringToBytes(str) {
const bytes = new Uint8Array(str.length);
for (let i = 0; i < str.length; i++)
bytes[i] = str.charCodeAt(i);
return bytes;
if (typeof str !== 'string') {
throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`);
}
return new TextEncoder().encode(str);
}

@@ -131,3 +128,3 @@ exports.stringToBytes = stringToBytes;

const tv = pseudo_random_bytes.subarray(elm_offset, elm_offset + L);
e[j] = mod.mod(os2ip(tv), options.p);
e[j] = (0, modular_js_1.mod)(os2ip(tv), options.p);
}

@@ -150,1 +147,32 @@ u[i] = e;

exports.isogenyMap = isogenyMap;
function hashToCurve(Point, mapToCurve, def) {
validateOpts(def);
if (typeof mapToCurve !== 'function')
throw new Error('hashToCurve: mapToCurve() has not been defined');
return {
// Encodes byte string to elliptic curve
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
hashToCurve(msg, options) {
if (!mapToCurve)
throw new Error('CURVE.mapToCurve() has not been defined');
msg = (0, utils_js_1.ensureBytes)(msg);
const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options });
const P = Point.fromAffine(mapToCurve(u[0]))
.add(Point.fromAffine(mapToCurve(u[1])))
.clearCofactor();
P.assertValidity();
return P;
},
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
encodeToCurve(msg, options) {
if (!mapToCurve)
throw new Error('CURVE.mapToCurve() has not been defined');
msg = (0, utils_js_1.ensureBytes)(msg);
const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options });
const P = Point.fromAffine(mapToCurve(u[0])).clearCofactor();
P.assertValidity();
return P;
},
};
}
exports.hashToCurve = hashToCurve;

@@ -23,8 +23,8 @@ export declare function mod(a: bigint, b: bigint): bigint;

isValid: (num: T) => boolean;
isZero: (num: T) => boolean;
negate(num: T): T;
invert(num: T): T;
is0: (num: T) => boolean;
neg(num: T): T;
inv(num: T): T;
sqrt(num: T): T;
square(num: T): T;
equals(lhs: T, rhs: T): boolean;
sqr(num: T): T;
eql(lhs: T, rhs: T): boolean;
add(lhs: T, rhs: T): T;

@@ -38,5 +38,4 @@ sub(lhs: T, rhs: T): T;

mulN(lhs: T, rhs: T | bigint): T;
squareN(num: T): T;
sqrN(num: T): T;
isOdd?(num: T): boolean;
legendre?(num: T): T;
pow(lhs: T, power: bigint): T;

@@ -53,2 +52,6 @@ invertBatch: (lst: T[]) => T[];

export declare function FpIsSquare<T>(f: Field<T>): (x: T) => boolean;
export declare function nLength(n: bigint, nBitLength?: number): {
nBitLength: number;
nByteLength: number;
};
declare type FpField = Field<bigint> & Required<Pick<Field<bigint>, 'isOdd'>>;

@@ -58,2 +61,12 @@ export declare function Fp(ORDER: bigint, bitLen?: number, isLE?: boolean, redef?: Partial<Field<bigint>>): Readonly<FpField>;

export declare function FpSqrtEven<T>(Fp: Field<T>, elm: T): T;
/**
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
* 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.
* Needs at least 40 bytes of input for 32-byte private key.
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
* @param hash hash output from SHA3 or a similar function
* @returns valid private scalar
*/
export declare function hashToPrivateScalar(hash: string | Uint8Array, groupOrder: bigint, isLE?: boolean): bigint;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FpSqrtEven = exports.FpSqrtOdd = exports.Fp = exports.FpIsSquare = exports.FpDiv = exports.FpInvertBatch = exports.FpPow = exports.validateField = exports.isNegativeLE = exports.FpSqrt = exports.tonelliShanks = exports.invert = exports.pow2 = exports.pow = exports.mod = void 0;
exports.hashToPrivateScalar = exports.FpSqrtEven = exports.FpSqrtOdd = exports.Fp = exports.nLength = exports.FpIsSquare = exports.FpDiv = exports.FpInvertBatch = exports.FpPow = exports.validateField = exports.isNegativeLE = exports.FpSqrt = exports.tonelliShanks = exports.invert = exports.pow2 = exports.pow = exports.mod = void 0;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// TODO: remove circular imports
const utils = require("./utils.js");
// Utilities for modular arithmetics and finite fields
const utils_js_1 = require("./utils.js");
// prettier-ignore

@@ -101,3 +100,3 @@ const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);

const root = Fp.pow(n, p1div4);
if (!Fp.equals(Fp.square(root), n))
if (!Fp.eql(Fp.sqr(root), n))
throw new Error('Cannot find square root');

@@ -111,3 +110,3 @@ return root;

// Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
if (Fp.pow(n, legendreC) === Fp.negate(Fp.ONE))
if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE))
throw new Error('Cannot find square root');

@@ -119,15 +118,15 @@ let r = S;

let b = Fp.pow(n, Q); // first guess at the fudge factor
while (!Fp.equals(b, Fp.ONE)) {
if (Fp.equals(b, Fp.ZERO))
while (!Fp.eql(b, Fp.ONE)) {
if (Fp.eql(b, Fp.ZERO))
return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)
// Find m such b^(2^m)==1
let m = 1;
for (let t2 = Fp.square(b); m < r; m++) {
if (Fp.equals(t2, Fp.ONE))
for (let t2 = Fp.sqr(b); m < r; m++) {
if (Fp.eql(t2, Fp.ONE))
break;
t2 = Fp.square(t2); // t2 *= t2
t2 = Fp.sqr(t2); // t2 *= t2
}
// NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow
const ge = Fp.pow(g, _1n << BigInt(r - m - 1)); // ge = 2^(r-m-1)
g = Fp.square(ge); // g = ge * ge
g = Fp.sqr(ge); // g = ge * ge
x = Fp.mul(x, ge); // x *= ge

@@ -155,3 +154,3 @@ b = Fp.mul(b, g); // b *= g

// Throw if root**2 != n
if (!Fp.equals(Fp.square(root), n))
if (!Fp.eql(Fp.sqr(root), n))
throw new Error('Cannot find square root');

@@ -170,3 +169,3 @@ return root;

const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
if (!Fp.equals(Fp.square(root), n))
if (!Fp.eql(Fp.sqr(root), n))
throw new Error('Cannot find square root');

@@ -207,5 +206,5 @@ return root;

const FIELD_FIELDS = [
'create', 'isValid', 'isZero', 'negate', 'invert', 'sqrt', 'square',
'equals', 'add', 'sub', 'mul', 'pow', 'div',
'addN', 'subN', 'mulN', 'squareN'
'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
'eql', 'add', 'sub', 'mul', 'pow', 'div',
'addN', 'subN', 'mulN', 'sqrN'
];

@@ -242,3 +241,3 @@ function validateField(field) {

p = f.mul(p, d);
d = f.square(d);
d = f.sqr(d);
power >>= 1n;

@@ -253,3 +252,3 @@ }

const lastMultiplied = nums.reduce((acc, num, i) => {
if (f.isZero(num))
if (f.is0(num))
return acc;

@@ -260,6 +259,6 @@ tmp[i] = acc;

// Invert last element
const inverted = f.invert(lastMultiplied);
const inverted = f.inv(lastMultiplied);
// Walk from last to first, multiply them by inverted each other MOD p
nums.reduceRight((acc, num, i) => {
if (f.isZero(num))
if (f.is0(num))
return acc;

@@ -273,3 +272,3 @@ tmp[i] = f.mul(acc, tmp[i]);

function FpDiv(f, lhs, rhs) {
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.invert(rhs));
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
}

@@ -282,10 +281,18 @@ exports.FpDiv = FpDiv;

const p = f.pow(x, legendreConst);
return f.equals(p, f.ZERO) || f.equals(p, f.ONE);
return f.eql(p, f.ZERO) || f.eql(p, f.ONE);
};
}
exports.FpIsSquare = FpIsSquare;
// CURVE.n lengths
function nLength(n, nBitLength) {
// Bit size, byte size of CURVE.n
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
const nByteLength = Math.ceil(_nBitLength / 8);
return { nBitLength: _nBitLength, nByteLength };
}
exports.nLength = nLength;
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);
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
if (BYTES > 2048)

@@ -298,3 +305,3 @@ throw new Error('Field lengths over 2048 bytes are not supported');

BYTES,
MASK: utils.bitMask(BITS),
MASK: (0, utils_js_1.bitMask)(BITS),
ZERO: _0n,

@@ -306,9 +313,9 @@ ONE: _1n,

throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
return _0n <= num && num < ORDER;
return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
},
isZero: (num) => num === _0n,
is0: (num) => num === _0n,
isOdd: (num) => (num & _1n) === _1n,
negate: (num) => mod(-num, ORDER),
equals: (lhs, rhs) => lhs === rhs,
square: (num) => mod(num * num, ORDER),
neg: (num) => mod(-num, ORDER),
eql: (lhs, rhs) => lhs === rhs,
sqr: (num) => mod(num * num, ORDER),
add: (lhs, rhs) => mod(lhs + rhs, ORDER),

@@ -320,7 +327,7 @@ sub: (lhs, rhs) => mod(lhs - rhs, ORDER),

// Same as above, but doesn't normalize
squareN: (num) => num * num,
sqrN: (num) => num * num,
addN: (lhs, rhs) => lhs + rhs,
subN: (lhs, rhs) => lhs - rhs,
mulN: (lhs, rhs) => lhs * rhs,
invert: (num) => invert(num, ORDER),
inv: (num) => invert(num, ORDER),
sqrt: redef.sqrt || ((n) => sqrtP(f, n)),

@@ -331,7 +338,7 @@ invertBatch: (lst) => FpInvertBatch(f, lst),

cmov: (a, b, c) => (c ? b : a),
toBytes: (num) => isLE ? utils.numberToBytesLE(num, BYTES) : utils.numberToBytesBE(num, BYTES),
toBytes: (num) => (isLE ? (0, utils_js_1.numberToBytesLE)(num, BYTES) : (0, utils_js_1.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 isLE ? (0, utils_js_1.bytesToNumberLE)(bytes) : (0, utils_js_1.bytesToNumberBE)(bytes);
},

@@ -346,3 +353,3 @@ });

const root = Fp.sqrt(elm);
return Fp.isOdd(root) ? root : Fp.negate(root);
return Fp.isOdd(root) ? root : Fp.neg(root);
}

@@ -354,4 +361,23 @@ exports.FpSqrtOdd = FpSqrtOdd;

const root = Fp.sqrt(elm);
return Fp.isOdd(root) ? Fp.negate(root) : root;
return Fp.isOdd(root) ? Fp.neg(root) : root;
}
exports.FpSqrtEven = FpSqrtEven;
/**
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
* 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.
* Needs at least 40 bytes of input for 32-byte private key.
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
* @param hash hash output from SHA3 or a similar function
* @returns valid private scalar
*/
function hashToPrivateScalar(hash, groupOrder, isLE = false) {
hash = (0, utils_js_1.ensureBytes)(hash);
const hashLen = hash.length;
const minLen = nLength(groupOrder).nByteLength + 8;
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`);
const num = isLE ? (0, utils_js_1.bytesToNumberLE)(hash) : (0, utils_js_1.bytesToNumberBE)(hash);
return mod(num, groupOrder - _1n) + _1n;
}
exports.hashToPrivateScalar = hashToPrivateScalar;

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

/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
const mod = require("./modular.js");
const modular_js_1 = require("./modular.js");
const utils_js_1 = require("./utils.js");

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

continue; // Optional
if (!(0, utils_js_1.isPositiveInt)(curve[i]))
if (!Number.isSafeInteger(curve[i]))
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);

@@ -35,3 +35,2 @@ }

// Set defaults
// ...nLength(curve.n, curve.nBitLength),
return Object.freeze({ ...curve });

@@ -44,3 +43,3 @@ }

const { P } = CURVE;
const modP = (a) => mod.mod(a, P);
const modP = (a) => (0, modular_js_1.mod)(a, P);
const montgomeryBits = CURVE.montgomeryBits;

@@ -50,3 +49,3 @@ const montgomeryBytes = Math.ceil(montgomeryBits / 8);

const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes) => bytes);
const powPminus2 = CURVE.powPminus2 || ((x) => mod.pow(x, P - BigInt(2), P));
const powPminus2 = CURVE.powPminus2 || ((x) => (0, modular_js_1.pow)(x, P - BigInt(2), P));
/**

@@ -53,0 +52,0 @@ * Checks for num to be in range:

@@ -1,5 +0,3 @@

/*! 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 PrivKey = Hex | bigint;
export declare type CHash = {

@@ -13,20 +11,4 @@ (message: Uint8Array | string): Uint8Array;

};
export declare type BasicCurve<T> = {
Fp: mod.Field<T>;
n: bigint;
nBitLength?: number;
nByteLength?: number;
h: bigint;
hEff?: bigint;
Gx: T;
Gy: T;
wrapPrivateKey?: boolean;
allowInfinityPoint?: boolean;
};
export declare function isPositiveInt(num: any): num is number;
export declare function validateOpts<FP, T>(curve: BasicCurve<FP> & T): Readonly<{
readonly nBitLength: number;
readonly nByteLength: number;
} & BasicCurve<FP> & T>;
export declare function bytesToHex(uint8a: Uint8Array): string;
export declare type FHash = (message: Uint8Array | string) => Uint8Array;
export declare function bytesToHex(bytes: Uint8Array): string;
export declare function numberToHexUnpadded(num: number | bigint): string;

@@ -36,21 +18,8 @@ export declare function hexToNumber(hex: string): bigint;

export declare function bytesToNumberBE(bytes: Uint8Array): bigint;
export declare function bytesToNumberLE(uint8a: Uint8Array): bigint;
export declare function bytesToNumberLE(bytes: Uint8Array): bigint;
export declare const numberToBytesBE: (n: bigint, len: number) => Uint8Array;
export declare const numberToBytesLE: (n: bigint, len: number) => Uint8Array;
export declare const numberToVarBytesBE: (n: bigint) => Uint8Array;
export declare function ensureBytes(hex: Hex, expectedLength?: number): Uint8Array;
export declare function concatBytes(...arrays: Uint8Array[]): Uint8Array;
export declare function nLength(n: bigint, nBitLength?: number): {
nBitLength: number;
nByteLength: number;
};
/**
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
* 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.
* Needs at least 40 bytes of input for 32-byte private key.
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
* @param hash hash output from SHA3 or a similar function
* @returns valid private scalar
*/
export declare function hashToPrivateScalar(hash: Hex, groupOrder: bigint, isLE?: boolean): bigint;
export declare function equalBytes(b1: Uint8Array, b2: Uint8Array): boolean;

@@ -57,0 +26,0 @@ export declare function bitLen(n: bigint): number;

"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 = exports.isPositiveInt = void 0;
exports.bitMask = exports.bitSet = exports.bitGet = exports.bitLen = exports.equalBytes = exports.concatBytes = exports.ensureBytes = exports.numberToVarBytesBE = exports.numberToBytesLE = exports.numberToBytesBE = exports.bytesToNumberLE = exports.bytesToNumberBE = exports.hexToBytes = exports.hexToNumber = exports.numberToHexUnpadded = exports.bytesToHex = void 0;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
const mod = require("./modular.js");
const _0n = BigInt(0);
const _1n = BigInt(1);
const _2n = BigInt(2);
// Bans floats and integers above 2^53-1
function isPositiveInt(num) {
return typeof num === 'number' && Number.isSafeInteger(num) && num > 0;
}
exports.isPositiveInt = isPositiveInt;
function validateOpts(curve) {
mod.validateField(curve.Fp);
for (const i of ['n', 'h']) {
const val = curve[i];
if (typeof val !== 'bigint')
throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
}
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']) {
const val = curve[i];
if (val === undefined)
continue; // Optional
if (!isPositiveInt(val))
throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
}
// Set defaults
return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve });
}
exports.validateOpts = validateOpts;
const u8a = (a) => a instanceof Uint8Array;
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
function bytesToHex(uint8a) {
if (!(uint8a instanceof Uint8Array))
function bytesToHex(bytes) {
if (!u8a(bytes))
throw new Error('Expected Uint8Array');
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < uint8a.length; i++) {
hex += hexes[uint8a[i]];
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
}

@@ -54,5 +27,4 @@ return hex;

function hexToNumber(hex) {
if (typeof hex !== 'string') {
throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
}
if (typeof hex !== 'string')
throw new Error('hexToNumber: expected string, got ' + typeof hex);
// Big Endian

@@ -64,5 +36,4 @@ return BigInt(`0x${hex}`);

function hexToBytes(hex) {
if (typeof hex !== 'string') {
throw new TypeError('hexToBytes: expected string, got ' + typeof hex);
}
if (typeof hex !== 'string')
throw new Error('hexToBytes: expected string, got ' + typeof hex);
if (hex.length % 2)

@@ -87,6 +58,6 @@ throw new Error('hexToBytes: received invalid unpadded hex ' + hex.length);

exports.bytesToNumberBE = bytesToNumberBE;
function bytesToNumberLE(uint8a) {
if (!(uint8a instanceof Uint8Array))
function bytesToNumberLE(bytes) {
if (!u8a(bytes))
throw new Error('Expected Uint8Array');
return BigInt('0x' + bytesToHex(Uint8Array.from(uint8a).reverse()));
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
}

@@ -98,6 +69,14 @@ exports.bytesToNumberLE = bytesToNumberLE;

exports.numberToBytesLE = numberToBytesLE;
// Returns variable number bytes (minimal bigint encoding?)
const numberToVarBytesBE = (n) => {
let hex = n.toString(16);
if (hex.length & 1)
hex = '0' + hex;
return hexToBytes(hex);
};
exports.numberToVarBytesBE = numberToVarBytesBE;
function ensureBytes(hex, expectedLength) {
// Uint8Array.from() instead of hash.slice() because node.js Buffer
// is instance of Uint8Array, and its slice() creates **mutable** copy
const bytes = hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex);
const bytes = u8a(hex) ? Uint8Array.from(hex) : hexToBytes(hex);
if (typeof expectedLength === 'number' && bytes.length !== expectedLength)

@@ -110,3 +89,3 @@ throw new Error(`Expected ${expectedLength} bytes`);

function concatBytes(...arrays) {
if (!arrays.every((b) => b instanceof Uint8Array))
if (!arrays.every((b) => u8a(b)))
throw new Error('Uint8Array list expected');

@@ -125,29 +104,2 @@ if (arrays.length === 1)

exports.concatBytes = concatBytes;
// CURVE.n lengths
function nLength(n, nBitLength) {
// Bit size, byte size of CURVE.n
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
const nByteLength = Math.ceil(_nBitLength / 8);
return { nBitLength: _nBitLength, nByteLength };
}
exports.nLength = nLength;
/**
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
* 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.
* Needs at least 40 bytes of input for 32-byte private key.
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
* @param hash hash output from SHA3 or a similar function
* @returns valid private scalar
*/
function hashToPrivateScalar(hash, groupOrder, isLE = false) {
hash = ensureBytes(hash);
const hashLen = hash.length;
const minLen = nLength(groupOrder).nByteLength + 8;
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`);
const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
return mod.mod(num, groupOrder - _1n) + _1n;
}
exports.hashToPrivateScalar = hashToPrivateScalar;
function equalBytes(b1, b2) {

@@ -154,0 +106,0 @@ // We don't care about timing attacks here

/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import * as mod from './modular.js';
import * as ut from './utils.js';
import { Hex, PrivKey } from './utils.js';
import { htfOpts } from './hash-to-curve.js';
import { Group, GroupConstructor } from './group.js';
import { Hex, PrivKey, CHash } from './utils.js';
import { Group, GroupConstructor, AbstractCurve, AffinePoint } from './curve.js';
export type { AffinePoint };
declare type HmacFnSync = (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array;

@@ -17,3 +17,3 @@ declare type EndomorphismOpts = {

};
export declare type BasicCurve<T> = ut.BasicCurve<T> & {
export declare type BasicCurve<T> = AbstractCurve<T> & {
a: T;

@@ -24,9 +24,4 @@ b: T;

endo?: EndomorphismOpts;
isTorsionFree?: (c: ProjectiveConstructor<T>, point: ProjectivePointType<T>) => boolean;
clearCofactor?: (c: ProjectiveConstructor<T>, point: ProjectivePointType<T>) => ProjectivePointType<T>;
htfDefaults?: htfOpts;
mapToCurve?: (scalar: bigint[]) => {
x: T;
y: T;
};
isTorsionFree?: (c: ProjConstructor<T>, point: ProjPointType<T>) => boolean;
clearCofactor?: (c: ProjConstructor<T>, point: ProjPointType<T>) => ProjPointType<T>;
};

@@ -37,3 +32,8 @@ declare type Entropy = Hex | true;

extraEntropy?: Entropy;
prehash?: boolean;
};
export declare type VerOpts = {
lowS?: boolean;
prehash?: boolean;
};
/**

@@ -60,43 +60,31 @@ * ### Design rationale for types

*/
export interface ProjectivePointType<T> extends Group<ProjectivePointType<T>> {
readonly x: T;
readonly y: T;
readonly z: T;
multiply(scalar: number | bigint, affinePoint?: PointType<T>): ProjectivePointType<T>;
multiplyUnsafe(scalar: bigint): ProjectivePointType<T>;
toAffine(invZ?: T): PointType<T>;
}
export interface ProjectiveConstructor<T> extends GroupConstructor<ProjectivePointType<T>> {
new (x: T, y: T, z: T): ProjectivePointType<T>;
fromAffine(p: PointType<T>): ProjectivePointType<T>;
toAffineBatch(points: ProjectivePointType<T>[]): PointType<T>[];
normalizeZ(points: ProjectivePointType<T>[]): ProjectivePointType<T>[];
}
export interface PointType<T> extends Group<PointType<T>> {
readonly x: T;
readonly y: T;
export interface ProjPointType<T> extends Group<ProjPointType<T>> {
readonly px: T;
readonly py: T;
readonly pz: T;
multiply(scalar: bigint): ProjPointType<T>;
multiplyUnsafe(scalar: bigint): ProjPointType<T>;
multiplyAndAddUnsafe(Q: ProjPointType<T>, a: bigint, b: bigint): ProjPointType<T> | undefined;
_setWindowSize(windowSize: number): void;
toAffine(iz?: T): AffinePoint<T>;
isTorsionFree(): boolean;
clearCofactor(): ProjPointType<T>;
assertValidity(): 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 interface ProjConstructor<T> extends GroupConstructor<ProjPointType<T>> {
new (x: T, y: T, z: T): ProjPointType<T>;
fromAffine(p: AffinePoint<T>): ProjPointType<T>;
fromHex(hex: Hex): ProjPointType<T>;
fromPrivateKey(privateKey: PrivKey): ProjPointType<T>;
normalizeZ(points: ProjPointType<T>[]): ProjPointType<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;
fromBytes: (bytes: Uint8Array) => AffinePoint<T>;
toBytes: (c: ProjConstructor<T>, point: ProjPointType<T>, compressed: boolean) => Uint8Array;
};
export declare type CurvePointsRes<T> = {
Point: PointConstructor<T>;
ProjectivePoint: ProjectiveConstructor<T>;
ProjectivePoint: ProjConstructor<T>;
normalizePrivateKey: (key: PrivKey) => bigint;

@@ -107,4 +95,3 @@ weierstrassEquation: (x: T) => T;

export declare function weierstrassPoints<T>(opts: CurvePointsType<T>): {
Point: PointConstructor<T>;
ProjectivePoint: ProjectiveConstructor<T>;
ProjectivePoint: ProjConstructor<T>;
normalizePrivateKey: (key: PrivKey) => bigint;

@@ -119,10 +106,10 @@ weierstrassEquation: (x: T) => T;

assertValidity(): void;
copyWithRecoveryBit(recovery: number): SignatureType;
addRecoveryBit(recovery: number): SignatureType;
hasHighS(): boolean;
normalizeS(): SignatureType;
recoverPublicKey(msgHash: Hex): PointType<bigint>;
recoverPublicKey(msgHash: Hex): ProjPointType<bigint>;
toCompactRawBytes(): Uint8Array;
toCompactHex(): string;
toDERRawBytes(isCompressed?: boolean): Uint8Array;
toDERHex(isCompressed?: boolean): string;
toCompactRawBytes(): Uint8Array;
toCompactHex(): string;
}

@@ -134,9 +121,14 @@ export declare type SignatureConstructor = {

};
export declare type PubKey = Hex | PointType<bigint>;
declare type SignatureLike = {
r: bigint;
s: bigint;
};
export declare type PubKey = Hex | ProjPointType<bigint>;
export declare type CurveType = BasicCurve<bigint> & {
lowS?: boolean;
hash: ut.CHash;
hash: CHash;
hmac: HmacFnSync;
randomBytes: (bytesLength?: number) => Uint8Array;
truncateHash?: (hash: Uint8Array, truncateOnly?: boolean) => bigint;
bits2int?: (bytes: Uint8Array) => bigint;
bits2int_modN?: (bytes: Uint8Array) => bigint;
};

@@ -158,9 +150,4 @@ declare function validateOpts(curve: CurveType): Readonly<{

readonly endo?: EndomorphismOpts | undefined;
readonly isTorsionFree?: ((c: ProjectiveConstructor<bigint>, point: ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: ProjectiveConstructor<bigint>, point: ProjectivePointType<bigint>) => ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: ProjConstructor<bigint>, point: ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: ProjConstructor<bigint>, point: ProjPointType<bigint>) => ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -170,3 +157,4 @@ readonly hash: ut.CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;

@@ -176,19 +164,9 @@ export declare type CurveFn = {

getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
getSharedSecret: (privateA: PrivKey, publicB: PubKey, isCompressed?: boolean) => Uint8Array;
getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
signUnhashed: (msg: Uint8Array, privKey: PrivKey, opts?: SignOpts) => SignatureType;
verify: (signature: Hex | SignatureType, msgHash: Hex, publicKey: PubKey, opts?: {
lowS?: boolean;
}) => boolean;
Point: PointConstructor<bigint>;
ProjectivePoint: ProjectiveConstructor<bigint>;
verify: (signature: Hex | SignatureLike, msgHash: Hex, publicKey: Hex, opts?: VerOpts) => boolean;
ProjectivePoint: ProjConstructor<bigint>;
Signature: SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: PrivKey) => bigint;
_normalizePublicKey: (publicKey: PubKey) => PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: PrivKey): boolean;

@@ -212,2 +190,1 @@ hashToPrivateKey: (hash: Hex) => Uint8Array;

};
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapToCurveSimpleSWU = exports.SWUFpSqrtRatio = exports.weierstrass = exports.weierstrassPoints = void 0;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// Short Weierstrass curve. The formula is: y² = x³ + ax + b
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapToCurveSimpleSWU = exports.SWUFpSqrtRatio = exports.weierstrass = exports.weierstrassPoints = void 0;
// Differences from @noble/secp256k1 1.7:
// 1. Different double() formula (but same addition)
// 2. Different sqrt() function
// 3. truncateHash() truncateOnly mode
// 4. DRBG supports outputLen bigger than outputLen of hmac
// 5. Support for different hash functions
const mod = require("./modular.js");
const ut = require("./utils.js");
const utils_js_1 = require("./utils.js");
const hash_to_curve_js_1 = require("./hash-to-curve.js");
const group_js_1 = require("./group.js");
// ASN.1 DER encoding utilities
class DERError extends Error {
constructor(message) {
super(message);
}
}
const DER = {
slice(s) {
// Proof: any([(i>=0x80) == (int(hex(i).replace('0x', '').zfill(2)[0], 16)>=8) for i in range(0, 256)])
// Padding done by numberToHex
return Number.parseInt(s[0], 16) >= 8 ? '00' + s : s;
},
parseInt(data) {
if (data.length < 2 || data[0] !== 0x02) {
throw new DERError(`Invalid signature integer tag: ${(0, utils_js_1.bytesToHex)(data)}`);
}
const len = data[1];
const res = data.subarray(2, len + 2);
if (!len || res.length !== len) {
throw new DERError(`Invalid signature integer: wrong length`);
}
// Strange condition, its not about length, but about first bytes of number.
if (res[0] === 0x00 && res[1] <= 0x7f) {
throw new DERError('Invalid signature integer: trailing length');
}
return { data: ut.bytesToNumberBE(res), left: data.subarray(len + 2) };
},
parseSig(data) {
if (data.length < 2 || data[0] != 0x30) {
throw new DERError(`Invalid signature tag: ${(0, utils_js_1.bytesToHex)(data)}`);
}
if (data[1] !== data.length - 2) {
throw new DERError('Invalid signature: incorrect length');
}
const { data: r, left: sBytes } = DER.parseInt(data.subarray(2));
const { data: s, left: rBytesLeft } = DER.parseInt(sBytes);
if (rBytesLeft.length) {
throw new DERError(`Invalid signature: left bytes after parsing: ${(0, utils_js_1.bytesToHex)(rBytesLeft)}`);
}
return { r, s };
},
};
const curve_js_1 = require("./curve.js");
function validatePointOpts(curve) {
const opts = ut.validateOpts(curve);
const opts = (0, curve_js_1.validateAbsOpts)(curve);
const Fp = opts.Fp;

@@ -66,3 +17,3 @@ for (const i of ['a', 'b']) {

}
for (const i of ['isTorsionFree', 'clearCofactor', 'mapToCurve']) {
for (const i of ['isTorsionFree', 'clearCofactor']) {
if (curve[i] === undefined)

@@ -75,3 +26,3 @@ continue; // Optional

if (endo) {
if (!Fp.equals(opts.a, Fp.ZERO)) {
if (!Fp.eql(opts.a, Fp.ZERO)) {
throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');

@@ -89,12 +40,62 @@ }

throw new Error('Invalid fromBytes function');
// Requires including hashToCurve file
if (opts.htfDefaults !== undefined)
(0, hash_to_curve_js_1.validateHTFOpts)(opts.htfDefaults);
// Set defaults
return Object.freeze({ ...opts });
}
// ASN.1 DER encoding utilities
const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
const DER = {
// asn.1 DER encoding utils
Err: class DERErr extends Error {
constructor(m = '') {
super(m);
}
},
_parseInt(data) {
const { Err: E } = DER;
if (data.length < 2 || data[0] !== 0x02)
throw new E('Invalid signature integer tag');
const len = data[1];
const res = data.subarray(2, len + 2);
if (!len || res.length !== len)
throw new E('Invalid signature integer: wrong length');
if (res[0] === 0x00 && res[1] <= 0x7f)
throw new E('Invalid signature integer: trailing length');
// ^ Weird condition: not about length, but about first bytes of number.
return { d: b2n(res), l: data.subarray(len + 2) }; // d is data, l is left
},
toSig(hex) {
// parse DER signature
const { Err: E } = DER;
const data = typeof hex === 'string' ? h2b(hex) : hex;
if (!(data instanceof Uint8Array))
throw new Error('ui8a expected');
let l = data.length;
if (l < 2 || data[0] != 0x30)
throw new E('Invalid signature tag');
if (data[1] !== l - 2)
throw new E('Invalid signature: incorrect length');
const { d: r, l: sBytes } = DER._parseInt(data.subarray(2));
const { d: s, l: rBytesLeft } = DER._parseInt(sBytes);
if (rBytesLeft.length)
throw new E('Invalid signature: left bytes after parsing');
return { r, s };
},
hexFromSig(sig) {
const slice = (s) => (Number.parseInt(s[0], 16) >= 8 ? '00' + s : s); // slice DER
const h = (num) => {
const hex = num.toString(16);
return hex.length & 1 ? `0${hex}` : hex;
};
const s = slice(h(sig.s));
const r = slice(h(sig.r));
const shl = s.length / 2;
const rhl = r.length / 2;
const sl = h(shl);
const rl = h(rhl);
return `30${h(rhl + shl + 4)}02${rl}${r}02${sl}${s}`;
},
};
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
const _0n = BigInt(0);
const _1n = BigInt(1);
const _3n = BigInt(3);
function weierstrassPoints(opts) {

@@ -109,3 +110,3 @@ const CURVE = validatePointOpts(opts);

const { a, b } = CURVE;
const x2 = Fp.square(x); // x * x
const x2 = Fp.sqr(x); // x * x
const x3 = Fp.mul(x2, x); // x2 * x

@@ -116,4 +117,8 @@ return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x3 + a * x + b

function isWithinCurveOrder(num) {
return _0n < num && num < CURVE.n;
return typeof num === 'bigint' && _0n < num && num < CURVE.n;
}
function assertGE(num) {
if (!isWithinCurveOrder(num))
throw new Error('Expected valid bigint: 0 < bigint < curve.n');
}
/**

@@ -126,3 +131,3 @@ * Validates if a private key is valid and converts it to bigint form.

function normalizePrivateKey(key) {
const { normalizePrivateKey: custom, nByteLength: groupLen, wrapPrivateKey, n: order } = CURVE;
const { normalizePrivateKey: custom, nByteLength: groupLen, wrapPrivateKey, n } = CURVE;
if (typeof custom === 'function')

@@ -135,36 +140,26 @@ key = custom(key);

}
else if (ut.isPositiveInt(key)) {
num = BigInt(key);
}
else if (typeof key === 'string') {
if (key.length !== 2 * groupLen)
throw new Error(`Expected ${groupLen} bytes of private key`);
throw new Error(`must be ${groupLen} bytes`);
// Validates individual octets
num = ut.hexToNumber(key);
num = ut.bytesToNumberBE((0, utils_js_1.ensureBytes)(key));
}
else if (key instanceof Uint8Array) {
if (key.length !== groupLen)
throw new Error(`Expected ${groupLen} bytes of private key`);
throw new Error(`must be ${groupLen} bytes`);
num = ut.bytesToNumberBE(key);
}
else {
throw new TypeError('Expected valid private key');
throw new Error('private key must be bytes, hex or bigint, not ' + typeof key);
}
// Useful for curves with cofactor != 1
if (wrapPrivateKey)
num = mod.mod(num, order);
if (!isWithinCurveOrder(num))
throw new Error('Expected private key: 0 < key < n');
num = mod.mod(num, n);
assertGE(num);
return num;
}
/**
* Validates if a scalar ("private number") is valid.
* Scalars are valid only if they are less than curve order.
*/
function normalizeScalar(num) {
if (ut.isPositiveInt(num))
return BigInt(num);
if (typeof num === 'bigint' && isWithinCurveOrder(num))
return num;
throw new TypeError('Expected valid private scalar: 0 < scalar < curve.n');
const pointPrecomputes = new Map();
function assertPrjPoint(other) {
if (!(other instanceof Point))
throw new Error('ProjectivePoint expected');
}

@@ -176,17 +171,32 @@ /**

*/
class ProjectivePoint {
constructor(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
class Point {
constructor(px, py, pz) {
this.px = px;
this.py = py;
this.pz = pz;
if (px == null || !Fp.isValid(px))
throw new Error('x required');
if (py == null || !Fp.isValid(py))
throw new Error('y required');
if (pz == null || !Fp.isValid(pz))
throw new Error('z required');
}
static fromAffine(p) {
if (!(p instanceof Point)) {
throw new TypeError('ProjectivePoint#fromAffine: expected Point');
}
const { x, y } = p || {};
if (!p || !Fp.isValid(x) || !Fp.isValid(y))
throw new Error('invalid affine point');
if (p instanceof Point)
throw new Error('projective point not allowed');
const is0 = (i) => Fp.eql(i, Fp.ZERO);
// fromAffine(x:0, y:0) would produce (x:0, y:0, z:1), but we need (x:0, y:1, z:0)
if (p.equals(Point.ZERO))
return ProjectivePoint.ZERO;
return new ProjectivePoint(p.x, p.y, Fp.ONE);
if (is0(x) && is0(y))
return Point.ZERO;
return new Point(x, y, Fp.ONE);
}
get x() {
return this.toAffine().x;
}
get y() {
return this.toAffine().y;
}
/**

@@ -196,13 +206,52 @@ * Takes a bunch of Projective Points but executes only one

* so this improves performance massively.
* Optimization: converts a list of projective points to a list of identical points with Z=1.
*/
static toAffineBatch(points) {
const toInv = Fp.invertBatch(points.map((p) => p.z));
return points.map((p, i) => p.toAffine(toInv[i]));
static normalizeZ(points) {
const toInv = Fp.invertBatch(points.map((p) => p.pz));
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
}
/**
* Optimization: converts a list of projective points to a list of identical points with Z=1.
* Converts hash string or Uint8Array to Point.
* @param hex short/long ECDSA hex
*/
static normalizeZ(points) {
return ProjectivePoint.toAffineBatch(points).map(ProjectivePoint.fromAffine);
static fromHex(hex) {
const P = Point.fromAffine(CURVE.fromBytes((0, utils_js_1.ensureBytes)(hex)));
P.assertValidity();
return P;
}
// Multiplies generator point by privateKey.
static fromPrivateKey(privateKey) {
return Point.BASE.multiply(normalizePrivateKey(privateKey));
}
// "Private method", don't use it directly
_setWindowSize(windowSize) {
this._WINDOW_SIZE = windowSize;
pointPrecomputes.delete(this);
}
// A point on curve is valid if it conforms to equation.
assertValidity() {
// Zero is valid point too!
if (this.is0()) {
if (CURVE.allowInfinityPoint)
return;
throw new Error('bad point: ZERO');
}
// Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
const { x, y } = this.toAffine();
// Check if x, y are valid field elements
if (!Fp.isValid(x) || !Fp.isValid(y))
throw new Error('bad point: x or y not FE');
const left = Fp.sqr(y); // y²
const right = weierstrassEquation(x); // x³ + ax + b
if (!Fp.eql(left, right))
throw new Error('bad point: equation left != right');
if (!this.isTorsionFree())
throw new Error('bad point: not in prime-order subgroup');
}
hasEvenY() {
const { y } = this.toAffine();
if (Fp.isOdd)
return !Fp.isOdd(y);
throw new Error("Field doesn't support isOdd");
}
/**

@@ -213,6 +262,6 @@ * Compare one point to another.

assertPrjPoint(other);
const { x: X1, y: Y1, z: Z1 } = this;
const { x: X2, y: Y2, z: Z2 } = other;
const U1 = Fp.equals(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
const U2 = Fp.equals(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
const { px: X1, py: Y1, pz: Z1 } = this;
const { px: X2, py: Y2, pz: Z2 } = other;
const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
return U1 && U2;

@@ -224,3 +273,3 @@ }

negate() {
return new ProjectivePoint(this.x, Fp.negate(this.y), this.z);
return new Point(this.px, Fp.neg(this.py), this.pz);
}

@@ -234,3 +283,3 @@ // Renes-Costello-Batina exception-free doubling formula.

const b3 = Fp.mul(b, 3n);
const { x: X1, y: Y1, z: Z1 } = this;
const { px: X1, py: Y1, pz: Z1 } = this;
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore

@@ -268,3 +317,3 @@ let t0 = Fp.mul(X1, X1); // step 1

Z3 = Fp.add(Z3, Z3);
return new ProjectivePoint(X3, Y3, Z3);
return new Point(X3, Y3, Z3);
}

@@ -277,4 +326,4 @@ // Renes-Costello-Batina exception-free addition formula.

assertPrjPoint(other);
const { x: X1, y: Y1, z: Z1 } = this;
const { x: X2, y: Y2, z: Z2 } = other;
const { px: X1, py: Y1, pz: Z1 } = this;
const { px: X2, py: Y2, pz: Z2 } = other;
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore

@@ -323,3 +372,3 @@ const a = CURVE.a;

Z3 = Fp.add(Z3, t0); // step 40
return new ProjectivePoint(X3, Y3, Z3);
return new Point(X3, Y3, Z3);
}

@@ -329,2 +378,11 @@ subtract(other) {

}
is0() {
return this.equals(Point.ZERO);
}
wNAF(n) {
return wnaf.wNAFCached(this, pointPrecomputes, n, (comp) => {
const toInv = Fp.invertBatch(comp.map((p) => p.pz));
return comp.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
});
}
/**

@@ -335,16 +393,16 @@ * Non-constant-time multiplication. Uses double-and-add algorithm.

*/
multiplyUnsafe(scalar) {
const P0 = ProjectivePoint.ZERO;
if (typeof scalar === 'bigint' && scalar === _0n)
return P0;
// Will throw on 0
let n = normalizeScalar(scalar);
multiplyUnsafe(n) {
const I = Point.ZERO;
if (n === _0n)
return I;
assertGE(n); // Will throw on 0
if (n === _1n)
return this;
if (!CURVE.endo)
const { endo } = CURVE;
if (!endo)
return wnaf.unsafeLadder(this, n);
// Apply endomorphism
let { k1neg, k1, k2neg, k2 } = CURVE.endo.splitScalar(n);
let k1p = P0;
let k2p = P0;
let { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
let k1p = I;
let k2p = I;
let d = this;

@@ -364,24 +422,6 @@ while (k1 > _0n || k2 > _0n) {

k2p = k2p.negate();
k2p = new ProjectivePoint(Fp.mul(k2p.x, CURVE.endo.beta), k2p.y, k2p.z);
k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
return k1p.add(k2p);
}
/**
* Implements w-ary non-adjacent form for calculating ec multiplication.
*/
wNAF(n, affinePoint) {
if (!affinePoint && this.equals(ProjectivePoint.BASE))
affinePoint = Point.BASE;
const W = (affinePoint && affinePoint._WINDOW_SIZE) || 1;
// Calculate precomputes on a first run, reuse them after
let precomputes = affinePoint && pointPrecomputes.get(affinePoint);
if (!precomputes) {
precomputes = wnaf.precomputeWindow(this, W);
if (affinePoint && W !== 1) {
precomputes = ProjectivePoint.normalizeZ(precomputes);
pointPrecomputes.set(affinePoint, precomputes);
}
}
return wnaf.wNAF(W, precomputes, n);
}
/**
* Constant time multiplication.

@@ -394,15 +434,14 @@ * Uses wNAF method. Windowed method may be 10% faster,

*/
multiply(scalar, affinePoint) {
let n = normalizeScalar(scalar);
// Real point.
let point;
// Fake point, we use it to achieve constant-time multiplication.
let fake;
if (CURVE.endo) {
const { k1neg, k1, k2neg, k2 } = CURVE.endo.splitScalar(n);
let { p: k1p, f: f1p } = this.wNAF(k1, affinePoint);
let { p: k2p, f: f2p } = this.wNAF(k2, affinePoint);
multiply(scalar) {
assertGE(scalar);
let n = scalar;
let point, fake; // Fake point is used to const-time mult
const { endo } = CURVE;
if (endo) {
const { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
let { p: k1p, f: f1p } = this.wNAF(k1);
let { p: k2p, f: f2p } = this.wNAF(k2);
k1p = wnaf.constTimeNegate(k1neg, k1p);
k2p = wnaf.constTimeNegate(k2neg, k2p);
k2p = new ProjectivePoint(Fp.mul(k2p.x, CURVE.endo.beta), k2p.y, k2p.z);
k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
point = k1p.add(k2p);

@@ -412,3 +451,3 @@ fake = f1p.add(f2p);

else {
const { p, f } = this.wNAF(n, affinePoint);
const { p, f } = this.wNAF(n);
point = p;

@@ -418,22 +457,33 @@ fake = f;

// Normalize `z` for both points, but return only real one
return ProjectivePoint.normalizeZ([point, fake])[0];
return Point.normalizeZ([point, fake])[0];
}
/**
* Efficiently calculate `aP + bQ`. Unsafe, can expose private key, if used incorrectly.
* @returns non-zero affine point
*/
multiplyAndAddUnsafe(Q, a, b) {
const G = Point.BASE; // No Strauss-Shamir trick: we have 10% faster G precomputes
const mul = (P, a // Select faster multiply() method
) => (a === _0n || a === _1n || !P.equals(G) ? P.multiplyUnsafe(a) : P.multiply(a));
const sum = mul(this, a).add(mul(Q, b));
return sum.is0() ? undefined : sum;
}
// Converts Projective point to affine (x, y) coordinates.
// Can accept precomputed Z^-1 - for example, from invertBatch.
// (x, y, z) ∋ (x=x/z, y=y/z)
toAffine(invZ) {
const { x, y, z } = this;
const is0 = this.equals(ProjectivePoint.ZERO);
toAffine(iz) {
const { px: x, py: y, pz: z } = this;
const is0 = this.is0();
// If invZ was 0, we return zero point. However we still want to execute
// all operations, so we replace invZ with a random number, 1.
if (invZ == null)
invZ = is0 ? Fp.ONE : Fp.invert(z);
const ax = Fp.mul(x, invZ);
const ay = Fp.mul(y, invZ);
const zz = Fp.mul(z, invZ);
if (iz == null)
iz = is0 ? Fp.ONE : Fp.inv(z);
const ax = Fp.mul(x, iz);
const ay = Fp.mul(y, iz);
const zz = Fp.mul(z, iz);
if (is0)
return Point.ZERO;
if (!Fp.equals(zz, Fp.ONE))
return { x: Fp.ZERO, y: Fp.ZERO };
if (!Fp.eql(zz, Fp.ONE))
throw new Error('invZ was invalid');
return new Point(ax, ay);
return { x: ax, y: ay };
}

@@ -445,3 +495,3 @@ isTorsionFree() {

if (isTorsionFree)
return isTorsionFree(ProjectivePoint, this);
return isTorsionFree(Point, this);
throw new Error('isTorsionFree() has not been declared for the elliptic curve');

@@ -454,158 +504,19 @@ }

if (clearCofactor)
return clearCofactor(ProjectivePoint, this);
return clearCofactor(Point, this);
return this.multiplyUnsafe(CURVE.h);
}
}
ProjectivePoint.BASE = new ProjectivePoint(CURVE.Gx, CURVE.Gy, Fp.ONE);
ProjectivePoint.ZERO = new ProjectivePoint(Fp.ZERO, Fp.ONE, Fp.ZERO);
const _bits = CURVE.nBitLength;
const wnaf = (0, group_js_1.wNAF)(ProjectivePoint, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
function assertPrjPoint(other) {
if (!(other instanceof ProjectivePoint))
throw new TypeError('ProjectivePoint expected');
}
// Stores precomputed values for points.
const pointPrecomputes = new WeakMap();
/**
* Default Point works in default aka affine coordinates: (x, y)
*/
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
// "Private method", don't use it directly
_setWindowSize(windowSize) {
this._WINDOW_SIZE = windowSize;
pointPrecomputes.delete(this);
}
// Checks for y % 2 == 0
hasEvenY() {
if (Fp.isOdd)
return !Fp.isOdd(this.y);
throw new Error("Field doesn't support isOdd");
}
/**
* Converts hash string or Uint8Array to Point.
* @param hex short/long ECDSA hex
*/
static fromHex(hex) {
const { x, y } = CURVE.fromBytes(ut.ensureBytes(hex));
const point = new Point(x, y);
point.assertValidity();
return point;
}
// Multiplies generator point by privateKey.
static fromPrivateKey(privateKey) {
return Point.BASE.multiply(normalizePrivateKey(privateKey));
}
toRawBytes(isCompressed = false) {
toRawBytes(isCompressed = true) {
this.assertValidity();
return CURVE.toBytes(Point, this, isCompressed);
}
toHex(isCompressed = false) {
return (0, utils_js_1.bytesToHex)(this.toRawBytes(isCompressed));
toHex(isCompressed = true) {
return ut.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 at infinity');
}
// Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
const msg = 'Point is not on elliptic curve';
const { x, y } = this;
// Check if x, y are valid field elements
if (!Fp.isValid(x) || !Fp.isValid(y))
throw new Error(msg);
const left = Fp.square(y); // y²
const right = weierstrassEquation(x); // x³ + ax + b
if (!Fp.equals(left, right))
throw new Error(msg);
if (!this.isTorsionFree())
throw new Error('Point must be of prime-order subgroup');
}
equals(other) {
if (!(other instanceof Point))
throw new TypeError('Point#equals: expected Point');
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, Fp.negate(this.y));
}
toProj() {
return ProjectivePoint.fromAffine(this);
}
// Adds point to itself
double() {
return this.toProj().double().toAffine();
}
add(other) {
return this.toProj().add(ProjectivePoint.fromAffine(other)).toAffine();
}
subtract(other) {
return this.add(other.negate());
}
multiply(scalar) {
return this.toProj().multiply(scalar, this).toAffine();
}
multiplyUnsafe(scalar) {
return this.toProj().multiplyUnsafe(scalar).toAffine();
}
clearCofactor() {
return this.toProj().clearCofactor().toAffine();
}
isTorsionFree() {
return this.toProj().isTorsionFree();
}
/**
* Efficiently calculate `aP + bQ`.
* Unsafe, can expose private key, if used incorrectly.
* TODO: Utilize Shamir's trick
* @returns non-zero affine point
*/
multiplyAndAddUnsafe(Q, a, b) {
const P = this.toProj();
const aP = a === _0n || a === _1n || this !== Point.BASE ? P.multiplyUnsafe(a) : P.multiply(a);
const bQ = ProjectivePoint.fromAffine(Q).multiplyUnsafe(b);
const sum = aP.add(bQ);
return sum.equals(ProjectivePoint.ZERO) ? undefined : sum.toAffine();
}
// 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) {
const { mapToCurve } = CURVE;
if (!mapToCurve)
throw new Error('CURVE.mapToCurve() has not been defined');
msg = ut.ensureBytes(msg);
const u = (0, hash_to_curve_js_1.hash_to_field)(msg, 2, { ...CURVE.htfDefaults, ...options });
const { x: x0, y: y0 } = mapToCurve(u[0]);
const { x: x1, y: y1 } = mapToCurve(u[1]);
return new Point(x0, y0).add(new Point(x1, y1)).clearCofactor();
}
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
static encodeToCurve(msg, options) {
const { mapToCurve } = CURVE;
if (!mapToCurve)
throw new Error('CURVE.mapToCurve() has not been defined');
msg = ut.ensureBytes(msg);
const u = (0, hash_to_curve_js_1.hash_to_field)(msg, 1, { ...CURVE.htfDefaults, ...options });
const { x, y } = mapToCurve(u[0]);
return new Point(x, y).clearCofactor();
}
}
/**
* Base point aka generator. Any public_key = Point.BASE * private_key
*/
Point.BASE = new Point(CURVE.Gx, CURVE.Gy);
/**
* Identity point aka point at infinity. p - p = zero_p; p + zero_p = p
*/
Point.ZERO = new Point(Fp.ZERO, Fp.ZERO);
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
const _bits = CURVE.nBitLength;
const wnaf = (0, curve_js_1.wNAF)(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
return {
Point: Point,
ProjectivePoint: ProjectivePoint,
ProjectivePoint: Point,
normalizePrivateKey,

@@ -618,4 +529,4 @@ weierstrassEquation,

function validateOpts(curve) {
const opts = ut.validateOpts(curve);
if (typeof opts.hash !== 'function' || !ut.isPositiveInt(opts.hash.outputLen))
const opts = (0, curve_js_1.validateAbsOpts)(curve);
if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
throw new Error('Invalid hash function');

@@ -629,51 +540,54 @@ if (typeof opts.hmac !== 'function')

}
/**
* 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);
const u8n = (data) => new Uint8Array(data); // creates Uint8Array
const u8fr = (arr) => Uint8Array.from(arr); // another shortcut
function hmacDrbg(hashLen, qByteLen, 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)
let v = u8n(hashLen); // Minimal non-full-spec HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
let k = u8n(hashLen); // Steps B and C of RFC6979 3.2: set hashLen, in our case always same
let i = 0; // Iterations counter, will throw when over 1000
const reset = () => {
v.fill(1);
k.fill(0);
i = 0;
};
const h = (...b) => hmacFn(k, v, ...b); // hmac(k)(v, ...values)
const reseed = (seed = u8n()) => {
// HMAC-DRBG reseed() function. Steps D-G
k = h(u8fr([0x00]), seed); // k = hmac(k || v || 0x00 || seed)
v = h(); // v = hmac(k || 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();
k = h(u8fr([0x01]), seed); // k = hmac(k || v || 0x01 || seed)
v = h(); // v = hmac(k || v)
};
const gen = () => {
// HMAC-DRBG generate() function
if (i++ >= 1000)
throw new Error('drbg: tried 1000 values');
let len = 0;
const out = [];
while (len < this.qByteLen) {
this.v = this.hmacSync(this.v);
const sl = this.v.slice();
while (len < qByteLen) {
v = h();
const sl = v.slice();
out.push(sl);
len += this.v.length;
len += v.length;
}
return ut.concatBytes(...out);
}
};
const genUntil = (seed, pred) => {
reset();
reseed(seed); // Steps D-G
let res = undefined; // Step H: grind until k is in [1..n-1]
while (!(res = pred(gen())))
reseed();
reset();
return res;
};
return genUntil;
}

@@ -687,15 +601,22 @@ function weierstrass(curveDef) {

function isValidFieldElement(num) {
// 0 is disallowed by arbitrary reasons. Probably because infinity point?
return _0n < num && num < Fp.ORDER;
return _0n < num && num < Fp.ORDER; // 0 is banned since it's not invertible FE
}
const { Point, ProjectivePoint, normalizePrivateKey, weierstrassEquation, isWithinCurveOrder } = weierstrassPoints({
function modN(a) {
return mod.mod(a, CURVE_ORDER);
}
function invN(a) {
return mod.invert(a, CURVE_ORDER);
}
const { ProjectivePoint: Point, normalizePrivateKey, weierstrassEquation, isWithinCurveOrder, } = weierstrassPoints({
...CURVE,
toBytes(c, point, isCompressed) {
const x = Fp.toBytes(point.x);
const a = point.toAffine();
const x = Fp.toBytes(a.x);
const cat = ut.concatBytes;
if (isCompressed) {
// TODO: hasEvenY
return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x);
}
else {
return cat(Uint8Array.from([0x04]), x, Fp.toBytes(point.y));
return cat(Uint8Array.from([0x04]), x, Fp.toBytes(a.y));
}

@@ -705,6 +626,7 @@ },

const len = bytes.length;
const header = bytes[0];
const head = bytes[0];
const tail = bytes.subarray(1);
// this.assertValidity() is done inside of fromHex
if (len === compressedLen && (header === 0x02 || header === 0x03)) {
const x = ut.bytesToNumberBE(bytes.subarray(1));
if (len === compressedLen && (head === 0x02 || head === 0x03)) {
const x = ut.bytesToNumberBE(tail);
if (!isValidFieldElement(x))

@@ -716,10 +638,10 @@ throw new Error('Point is not on curve');

// ECDSA
const isFirstByteOdd = (bytes[0] & 1) === 1;
if (isFirstByteOdd !== isYOdd)
y = Fp.negate(y);
const isHeadOdd = (head & 1) === 1;
if (isHeadOdd !== isYOdd)
y = Fp.neg(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));
else if (len === uncompressedLen && head === 0x04) {
const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));
const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));
return { x, y };

@@ -732,26 +654,3 @@ }

});
// 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}`);
}
const numToNByteStr = (num) => ut.bytesToHex(ut.numberToBytesBE(num, CURVE.nByteLength));
function isBiggerThanHalfOrder(number) {

@@ -762,18 +661,6 @@ const HALF = CURVE_ORDER >> _1n;

function normalizeS(s) {
return isBiggerThanHalfOrder(s) ? mod.mod(-s, CURVE_ORDER) : s;
return isBiggerThanHalfOrder(s) ? modN(-s) : s;
}
function bits2int_2(bytes) {
const delta = bytes.length * 8 - CURVE.nBitLength;
const num = ut.bytesToNumberBE(bytes);
return delta > 0 ? num >> BigInt(delta) : num;
}
// Ensures ECDSA message hashes are 32 bytes and < curve order
function _truncateHash(hash, truncateOnly = false) {
const h = bits2int_2(hash);
if (truncateOnly)
return h;
const { n } = CURVE;
return h >= n ? h - n : h;
}
const truncateHash = CURVE.truncateHash || _truncateHash;
// slice bytes num
const slcNum = (b, from, to) => ut.bytesToNumberBE(b.slice(from, to));
/**

@@ -791,12 +678,5 @@ * ECDSA signature with its (r, s) properties. Supports DER & compact representations.

static fromCompact(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 ? (0, utils_js_1.bytesToHex)(hex) : hex;
const gl = CURVE.nByteLength * 2; // group length in hex, not ui8a
if (str.length !== 2 * gl)
throw new Error(`${name}: Expected ${gl / 2}-byte hex`);
const slice = (from, to) => ut.hexToNumber(str.slice(from, to));
return new Signature(slice(0, gl), slice(gl, 2 * gl));
const gl = CURVE.nByteLength;
hex = (0, utils_js_1.ensureBytes)(hex, gl * 2);
return new Signature(slcNum(hex, 0, gl), slcNum(hex, gl, 2 * gl));
}

@@ -806,61 +686,38 @@ // DER encoded ECDSA signature

static fromDER(hex) {
const arr = hex instanceof Uint8Array;
if (typeof hex !== 'string' && !arr)
throw new TypeError(`Signature.fromDER: Expected string or Uint8Array`);
const { r, s } = DER.parseSig(arr ? hex : ut.hexToBytes(hex));
if (typeof hex !== 'string' && !(hex instanceof Uint8Array))
throw new Error(`Signature.fromDER: Expected string or Uint8Array`);
const { r, s } = DER.toSig((0, utils_js_1.ensureBytes)(hex));
return new Signature(r, s);
}
assertValidity() {
const { r, s } = this;
if (!isWithinCurveOrder(r))
throw new Error('Invalid Signature: r must be 0 < r < n');
if (!isWithinCurveOrder(s))
throw new Error('Invalid Signature: s must be 0 < s < n');
// can use assertGE here
if (!isWithinCurveOrder(this.r))
throw new Error('r must be 0 < r < n');
if (!isWithinCurveOrder(this.s))
throw new Error('s must be 0 < s < n');
}
copyWithRecoveryBit(recovery) {
addRecoveryBit(recovery) {
return new Signature(this.r, this.s, recovery);
}
/**
* Recovers public key from signature with recovery bit. Throws on invalid hash.
* https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Public_key_recovery
* It's also possible to recover key without bit: try all 4 bit values and check for sig match.
*
* ```
* recover(r, s, h) where
* u1 = hs^-1 mod n
* u2 = sr^-1 mod n
* Q = u1⋅G + u2⋅R
* ```
*
* @param msgHash message hash
* @returns Point corresponding to public key
*/
recoverPublicKey(msgHash) {
const { r, s, recovery } = this;
if (recovery == null)
throw new Error('Cannot recover: recovery bit is not present');
if (![0, 1, 2, 3].includes(recovery))
throw new Error('Cannot recover: invalid recovery bit');
const h = truncateHash(ut.ensureBytes(msgHash));
const { n } = CURVE;
const radj = recovery === 2 || recovery === 3 ? r + n : r;
const { n: N } = CURVE; // ECDSA public key recovery secg.org/sec1-v2.pdf 4.1.6
const { r, s, recovery: rec } = this;
const h = bits2int_modN((0, utils_js_1.ensureBytes)(msgHash)); // Truncate hash
if (rec == null || ![0, 1, 2, 3].includes(rec))
throw new Error('recovery id invalid');
const radj = rec === 2 || rec === 3 ? r + N : r;
if (radj >= Fp.ORDER)
throw new Error('Cannot recover: bit 2/3 is invalid with current r');
const rinv = mod.invert(radj, n);
// Q = u1⋅G + u2⋅R
const u1 = mod.mod(-h * rinv, n);
const u2 = mod.mod(s * rinv, n);
const prefix = recovery & 1 ? '03' : '02';
const R = Point.fromHex(prefix + numToFieldStr(radj));
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // unsafe is fine: no priv data leaked
throw new Error('recovery id 2 or 3 invalid');
const prefix = (rec & 1) === 0 ? '02' : '03';
const R = Point.fromHex(prefix + numToNByteStr(radj));
const ir = invN(radj); // r^-1
const u1 = modN(-h * ir); // -hr^-1
const u2 = modN(s * ir); // sr^-1
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
if (!Q)
throw new Error('Cannot recover: point at infinify');
throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
Q.assertValidity();
return Q;
}
/**
* Default signatures are always low-s, to prevent malleability.
* `sign(lowS: true)` always produces low-s sigs.
* `verify(lowS: true)` always fails for high-s.
*/
// Signatures should be low-s, to prevent malleability.
hasHighS() {

@@ -870,5 +727,3 @@ return isBiggerThanHalfOrder(this.s);

normalizeS() {
return this.hasHighS()
? new Signature(this.r, mod.mod(-this.s, CURVE_ORDER), this.recovery)
: this;
return this.hasHighS() ? new Signature(this.r, modN(-this.s), this.recovery) : this;
}

@@ -880,11 +735,3 @@ // DER-encoded

toDERHex() {
const { numberToHexUnpadded: toHex } = ut;
const sHex = DER.slice(toHex(this.s));
const rHex = DER.slice(toHex(this.r));
const sHexL = sHex.length / 2;
const rHexL = rHex.length / 2;
const sLen = toHex(sHexL);
const rLen = toHex(rHexL);
const length = toHex(rHexL + sHexL + 4);
return `30${length}02${rLen}${rHex}02${sLen}${sHex}`;
return DER.hexFromSig({ r: this.r, s: this.s });
}

@@ -896,3 +743,3 @@ // padded bytes of r, then padded bytes of s

toCompactHex() {
return numToFieldStr(this.r) + numToFieldStr(this.s);
return numToNByteStr(this.r) + numToNByteStr(this.s);
}

@@ -910,13 +757,7 @@ }

},
_bigintToBytes: numToField,
_bigintToString: numToFieldStr,
_normalizePrivateKey: normalizePrivateKey,
_normalizePublicKey: normalizePublicKey,
_isWithinCurveOrder: isWithinCurveOrder,
_isValidFieldElement: isValidFieldElement,
_weierstrassEquation: weierstrassEquation,
/**
* Converts some bytes to a valid private key. Needs at least (nBitLength+64) bytes.
*/
hashToPrivateKey: (hash) => numToField(ut.hashToPrivateScalar(hash, CURVE_ORDER)),
hashToPrivateKey: (hash) => ut.numberToBytesBE(mod.hashToPrivateScalar(hash, CURVE_ORDER), CURVE.nByteLength),
/**

@@ -936,6 +777,5 @@ * Produces cryptographically secure private key from random of size (nBitLength+64)

precompute(windowSize = 8, point = Point.BASE) {
const cached = point === Point.BASE ? point : new Point(point.x, point.y);
cached._setWindowSize(windowSize);
cached.multiply(_3n);
return cached;
point._setWindowSize(windowSize);
point.multiply(BigInt(3));
return point;
},

@@ -949,3 +789,3 @@ };

*/
function getPublicKey(privateKey, isCompressed = false) {
function getPublicKey(privateKey, isCompressed = true) {
return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed);

@@ -977,52 +817,68 @@ }

*/
function getSharedSecret(privateA, publicB, isCompressed = false) {
function getSharedSecret(privateA, publicB, isCompressed = true) {
if (isProbPub(privateA))
throw new TypeError('getSharedSecret: first arg must be private key');
throw new Error('first arg must be private key');
if (!isProbPub(publicB))
throw new TypeError('getSharedSecret: second arg must be public key');
const b = normalizePublicKey(publicB);
b.assertValidity();
throw new Error('second arg must be public key');
const b = Point.fromHex(publicB); // check for being on-curve
return b.multiply(normalizePrivateKey(privateA)).toRawBytes(isCompressed);
}
// RFC6979 methods
function bits2int(bytes) {
const { nByteLength } = CURVE;
if (!(bytes instanceof Uint8Array))
throw new Error('Expected Uint8Array');
const slice = bytes.length > nByteLength ? bytes.slice(0, nByteLength) : bytes;
// const slice = bytes; nByteLength; nBitLength;
let num = ut.bytesToNumberBE(slice);
// const { nBitLength } = CURVE;
// const delta = (bytes.length * 8) - nBitLength;
// if (delta > 0) {
// // console.log('bits=', bytes.length*8, 'CURVE n=', nBitLength, 'delta=', delta);
// // console.log(bytes.length, nBitLength, delta);
// // console.log(bytes, new Error().stack);
// num >>= BigInt(delta);
// }
return num;
}
function bits2octets(bytes) {
const z1 = bits2int(bytes);
const z2 = mod.mod(z1, CURVE_ORDER);
return int2octets(z2 < _0n ? z1 : z2);
}
// RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.
// FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which matches bits2int.
// bits2int can produce res>N, we can do mod(res, N) since the bitLen is the same.
// int2octets can't be used; pads small msgs with 0: unacceptatble for trunc as per RFC vectors
const bits2int = CURVE.bits2int ||
function (bytes) {
// For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)
// for some cases, since bytes.length * 8 is not actual bitLength.
const delta = bytes.length * 8 - CURVE.nBitLength; // truncate to nBitLength leftmost bits
const num = ut.bytesToNumberBE(bytes); // check for == u8 done here
return delta > 0 ? num >> BigInt(delta) : num;
};
const bits2int_modN = CURVE.bits2int_modN ||
function (bytes) {
return modN(bits2int(bytes)); // can't use bytesToNumberBE here
};
// NOTE: pads output with zero as per spec
const ORDER_MASK = ut.bitMask(CURVE.nBitLength);
function int2octets(num) {
return numToField(num); // prohibits >nByteLength bytes
if (typeof num !== 'bigint')
throw new Error('Expected bigint');
if (!(_0n <= num && num < ORDER_MASK))
throw new Error(`Expected number < 2^${CURVE.nBitLength}`);
// works with order, can have different size than numToField!
return ut.numberToBytesBE(num, CURVE.nByteLength);
}
// Steps A, D of RFC6979 3.2
// Creates RFC6979 seed; converts msg/privKey to numbers.
function initSigArgs(msgHash, privateKey, extraEntropy) {
// Used only in sign, not in verify.
// NOTE: we cannot assume here that msgHash has same amount of bytes as curve order, this will be wrong at least for P521.
// Also it can be bigger for P224 + SHA256
function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
if (msgHash == null)
throw new Error(`sign: expected valid message hash, not "${msgHash}"`);
if (['recovered', 'canonical'].some((k) => k in opts))
// Ban legacy options
throw new Error('sign() legacy options not supported');
let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
if (prehash)
msgHash = CURVE.hash((0, utils_js_1.ensureBytes)(msgHash));
if (lowS == null)
lowS = true; // RFC6979 3.2: we skip step A, because
// Step A is ignored, since we already provide hash instead of msg
const h1 = numToField(truncateHash(ut.ensureBytes(msgHash)));
// NOTE: instead of bits2int, we calling here truncateHash, since we need
// custom truncation for stark. For other curves it is essentially same as calling bits2int + mod
// However, we cannot later call bits2octets (which is truncateHash + int2octets), since nested bits2int is broken
// for curves where nBitLength % 8 !== 0, so we unwrap it here as int2octets call.
// const bits2octets = (bits)=>int2octets(bytesToNumberBE(truncateHash(bits)))
const h1int = bits2int_modN((0, utils_js_1.ensureBytes)(msgHash));
const h1octets = int2octets(h1int);
const d = normalizePrivateKey(privateKey);
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
const seedArgs = [int2octets(d), bits2octets(h1)];
// RFC6979 3.6: additional k' could be provided
if (extraEntropy != null) {
if (extraEntropy === true)
extraEntropy = CURVE.randomBytes(Fp.BYTES);
const e = ut.ensureBytes(extraEntropy);
const seedArgs = [int2octets(d), h1octets];
if (ent != null) {
// RFC6979 3.6: additional k' (optional)
if (ent === true)
ent = CURVE.randomBytes(Fp.BYTES);
const e = (0, utils_js_1.ensureBytes)(ent);
if (e.length !== Fp.BYTES)

@@ -1032,43 +888,30 @@ throw new Error(`sign: Expected ${Fp.BYTES} bytes of extra data`);

}
// seed is constructed from private key and message
// Step D
// V, 0x00 are done in HmacDRBG constructor.
const seed = ut.concatBytes(...seedArgs);
const m = bits2int(h1);
return { seed, m, d };
}
/**
* Converts signature params into point & r/s, checks them for validity.
* k must be in range [1, n-1]
* @param k signature's k param: deterministic in our case, random in non-rfc6979 sigs
* @param m message that would be signed
* @param d private key
* @returns Signature with its point on curve Q OR undefined if params were invalid
*/
function kmdToSig(kBytes, m, d, lowS = true) {
const { n } = CURVE;
const k = truncateHash(kBytes, true);
if (!isWithinCurveOrder(k))
return;
// Important: all mod() calls in the function must be done over `n`
const kinv = mod.invert(k, n);
const q = Point.BASE.multiply(k);
// r = x mod n
const r = mod.mod(q.x, n);
if (r === _0n)
return;
// s = (m + dr)/k mod n where x/k == x*inv(k)
const s = mod.mod(kinv * mod.mod(m + mod.mod(d * r, n), n), n);
if (s === _0n)
return;
// recovery bit is usually 0 or 1; rarely it's 2 or 3, when q.x > n
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n);
let normS = s;
if (lowS && isBiggerThanHalfOrder(s)) {
normS = normalizeS(s);
recovery ^= 1;
const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2
const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
// Converts signature params into point w r/s, checks result for validity.
function k2sig(kBytes) {
// RFC 6979 Section 3.2, step 3: k = bits2int(T)
const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
if (!isWithinCurveOrder(k))
return; // Important: all mod() calls here must be done over N
const ik = invN(k); // k^-1 mod n
const q = Point.BASE.multiply(k).toAffine(); // q = Gk
const r = modN(q.x); // r = q.x mod n
if (r === _0n)
return;
const s = modN(ik * modN(m + modN(d * r))); // s = k^-1(m + rd) mod n
if (s === _0n)
return;
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n); // recovery bit (2 or 3, when q.x > n)
let normS = s;
if (lowS && isBiggerThanHalfOrder(s)) {
normS = normalizeS(s); // if lowS was passed, ensure s is always
recovery ^= 1; // // in the bottom half of N
}
return new Signature(r, normS, recovery); // use normS, not s
}
return new Signature(r, normS, recovery);
return { seed, k2sig };
}
const defaultSigOpts = { lowS: CURVE.lowS };
const defaultSigOpts = { lowS: CURVE.lowS, prehash: false };
const defaultVerOpts = { lowS: CURVE.lowS, prehash: false };
/**

@@ -1082,24 +925,12 @@ * Signs message hash (not message: you need to hash it by yourself).

* ```
* @param opts `lowS, extraEntropy`
* @param opts `lowS, extraEntropy, prehash`
*/
function sign(msgHash, privKey, opts = defaultSigOpts) {
// Steps A, D of RFC6979 3.2.
const { seed, m, d } = initSigArgs(msgHash, privKey, opts.extraEntropy);
// Steps B, C, D, E, F, G
const drbg = new HmacDrbg(CURVE.hash.outputLen, CURVE.nByteLength, CURVE.hmac);
drbg.reseedSync(seed);
// Step H3, repeat until k is in range [1, n-1]
let sig;
while (!(sig = kmdToSig(drbg.generateSync(), m, d, opts.lowS)))
drbg.reseedSync();
return sig;
const { seed, k2sig } = prepSig(msgHash, privKey, opts); // Steps A, D of RFC6979 3.2.
const genUntil = hmacDrbg(CURVE.hash.outputLen, CURVE.nByteLength, CURVE.hmac);
return genUntil(seed, k2sig); // Steps B, C, D, E, F, G
}
/**
* Signs a message (not message hash).
*/
function signUnhashed(msg, privKey, opts = defaultSigOpts) {
return sign(CURVE.hash(ut.ensureBytes(msg)), privKey, opts);
}
// Enable precomputes. Slows down first publicKey computation by 20ms.
Point.BASE._setWindowSize(8);
// utils.precompute(8, ProjectivePoint.BASE)
/**

@@ -1118,20 +949,26 @@ * Verifies a signature against message hash and public key.

*/
function verify(signature, msgHash, publicKey, opts = { lowS: CURVE.lowS }) {
function verify(signature, msgHash, publicKey, opts = defaultVerOpts) {
let P;
let _sig = undefined;
if (publicKey instanceof Point)
throw new Error('publicKey must be hex');
try {
if (signature instanceof Signature) {
signature.assertValidity();
if (signature && typeof signature === 'object' && !(signature instanceof Uint8Array)) {
const { r, s } = signature;
_sig = new Signature(r, s); // assertValidity() is executed on creation
}
else {
// Signature can be represented in 2 ways: compact (64-byte) & DER (variable-length).
// Since DER can also be 64 bytes, we check for it first.
// Signature can be represented in 2 ways: compact (2*nByteLength) & DER (variable-length).
// Since DER can also be 2*nByteLength bytes, we check for it first.
try {
signature = Signature.fromDER(signature);
_sig = Signature.fromDER(signature);
}
catch (derError) {
if (!(derError instanceof DERError))
if (!(derError instanceof DER.Err))
throw derError;
signature = Signature.fromCompact(signature);
_sig = Signature.fromCompact(signature);
}
}
msgHash = ut.ensureBytes(msgHash);
msgHash = (0, utils_js_1.ensureBytes)(msgHash);
P = Point.fromHex(publicKey);
}

@@ -1141,24 +978,15 @@ catch (error) {

}
if (opts.lowS && signature.hasHighS())
if (opts.lowS && _sig.hasHighS())
return false;
let P;
try {
P = normalizePublicKey(publicKey);
}
catch (error) {
return false;
}
const { n } = CURVE;
const { r, s } = signature;
const h = truncateHash(msgHash);
const sinv = mod.invert(s, n); // s^-1
// R = u1⋅G - u2⋅P
const u1 = mod.mod(h * sinv, n);
const u2 = mod.mod(r * sinv, n);
// Some implementations compare R.x in projective, without inversion.
// The speed-up is <5%, so we don't complicate the code.
const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2);
if (opts.prehash)
msgHash = CURVE.hash(msgHash);
const { r, s } = _sig;
const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
const is = invN(s); // s^-1
const u1 = modN(h * is); // u1 = hs^-1 mod n
const u2 = modN(r * is); // u2 = rs^-1 mod n
const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine(); // R = u1⋅G + u2⋅P
if (!R)
return false;
const v = mod.mod(R.x, n);
const v = modN(R.x);
return v === r;

@@ -1171,6 +999,5 @@ }

sign,
signUnhashed,
verify,
Point,
ProjectivePoint,
// Point,
ProjectivePoint: Point,
Signature,

@@ -1182,3 +1009,3 @@ utils,

// Implementation of the Shallue and van de Woestijne method for any Weierstrass curve
// TODO: check if there is a way to merge this with uvRation in Edwards && move to modular?
// TODO: check if there is a way to merge this with uvRatio in Edwards && move to modular?
// b = True and y = sqrt(u / v) if (u / v) is square in F, and

@@ -1202,3 +1029,3 @@ // b = False and y = sqrt(Z * (u / v)) otherwise.

let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4
let tv3 = Fp.square(tv2); // 3. tv3 = tv2^2
let tv3 = Fp.sqr(tv2); // 3. tv3 = tv2^2
tv3 = Fp.mul(tv3, v); // 4. tv3 = tv3 * v

@@ -1212,3 +1039,3 @@ let tv5 = Fp.mul(u, tv3); // 5. tv5 = u * tv3

tv5 = Fp.pow(tv4, c5); // 11. tv5 = tv4^c5
let isQR = Fp.equals(tv5, Fp.ONE); // 12. isQR = tv5 == 1
let isQR = Fp.eql(tv5, Fp.ONE); // 12. isQR = tv5 == 1
tv2 = Fp.mul(tv3, c7); // 13. tv2 = tv3 * c7

@@ -1222,3 +1049,3 @@ tv5 = Fp.mul(tv4, tv1); // 14. tv5 = tv4 * tv1

let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
const e1 = Fp.equals(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1

@@ -1235,5 +1062,5 @@ tv1 = Fp.mul(tv1, tv1); // 23. tv1 = tv1 * tv1

const c1 = (Fp.ORDER - 3n) / 4n; // 1. c1 = (q - 3) / 4 # Integer arithmetic
const c2 = Fp.sqrt(Fp.negate(Z)); // 2. c2 = sqrt(-Z)
const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z)
sqrtRatio = (u, v) => {
let tv1 = Fp.square(v); // 1. tv1 = v^2
let tv1 = Fp.sqr(v); // 1. tv1 = v^2
const tv2 = Fp.mul(u, v); // 2. tv2 = u * v

@@ -1244,4 +1071,4 @@ tv1 = Fp.mul(tv1, tv2); // 3. tv1 = tv1 * tv2

const y2 = Fp.mul(y1, c2); // 6. y2 = y1 * c2
const tv3 = Fp.mul(Fp.square(y1), v); // 7. tv3 = y1^2; 8. tv3 = tv3 * v
const isQR = Fp.equals(tv3, u); // 9. isQR = tv3 == u
const tv3 = Fp.mul(Fp.sqr(y1), v); // 7. tv3 = y1^2; 8. tv3 = tv3 * v
const isQR = Fp.eql(tv3, u); // 9. isQR = tv3 == u
let y = Fp.cmov(y2, y1, isQR); // 10. y = CMOV(y2, y1, isQR)

@@ -1269,12 +1096,12 @@ return { isValid: isQR, value: y }; // 11. return (isQR, y) isQR ? y : y*c2

let tv1, tv2, tv3, tv4, tv5, tv6, x, y;
tv1 = Fp.square(u); // 1. tv1 = u^2
tv1 = Fp.sqr(u); // 1. tv1 = u^2
tv1 = Fp.mul(tv1, opts.Z); // 2. tv1 = Z * tv1
tv2 = Fp.square(tv1); // 3. tv2 = tv1^2
tv2 = Fp.sqr(tv1); // 3. tv2 = tv1^2
tv2 = Fp.add(tv2, tv1); // 4. tv2 = tv2 + tv1
tv3 = Fp.add(tv2, Fp.ONE); // 5. tv3 = tv2 + 1
tv3 = Fp.mul(tv3, opts.B); // 6. tv3 = B * tv3
tv4 = Fp.cmov(opts.Z, Fp.negate(tv2), !Fp.equals(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
tv4 = Fp.cmov(opts.Z, Fp.neg(tv2), !Fp.eql(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
tv4 = Fp.mul(tv4, opts.A); // 8. tv4 = A * tv4
tv2 = Fp.square(tv3); // 9. tv2 = tv3^2
tv6 = Fp.square(tv4); // 10. tv6 = tv4^2
tv2 = Fp.sqr(tv3); // 9. tv2 = tv3^2
tv6 = Fp.sqr(tv4); // 10. tv6 = tv4^2
tv5 = Fp.mul(tv6, opts.A); // 11. tv5 = A * tv6

@@ -1293,3 +1120,3 @@ tv2 = Fp.add(tv2, tv5); // 12. tv2 = tv2 + tv5

const e1 = Fp.isOdd(u) === Fp.isOdd(y); // 23. e1 = sgn0(u) == sgn0(y)
y = Fp.cmov(Fp.negate(y), y, e1); // 24. y = CMOV(-y, y, e1)
y = Fp.cmov(Fp.neg(y), y, e1); // 24. y = CMOV(-y, y, e1)
x = Fp.div(x, tv4); // 25. x = x / tv4

@@ -1296,0 +1123,0 @@ return { x, y };

@@ -71,5 +71,5 @@ "use strict";

isValid: ({ c0, c1 }) => typeof c0 === 'bigint' && typeof c1 === 'bigint',
isZero: ({ c0, c1 }) => Fp.isZero(c0) && Fp.isZero(c1),
equals: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp.equals(c0, r0) && Fp.equals(c1, r1),
negate: ({ c0, c1 }) => ({ c0: Fp.negate(c0), c1: Fp.negate(c1) }),
is0: ({ c0, c1 }) => Fp.is0(c0) && Fp.is0(c1),
eql: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp.eql(c0, r0) && Fp.eql(c1, r1),
neg: ({ c0, c1 }) => ({ c0: Fp.neg(c0), c1: Fp.neg(c1) }),
pow: (num, power) => mod.FpPow(Fp2, num, power),

@@ -81,3 +81,3 @@ invertBatch: (nums) => mod.FpInvertBatch(Fp2, nums),

mul: Fp2Multiply,
square: Fp2Square,
sqr: Fp2Square,
// NonNormalized stuff

@@ -87,6 +87,6 @@ addN: Fp2Add,

mulN: Fp2Multiply,
squareN: Fp2Square,
sqrN: Fp2Square,
// Why inversion for bigint inside Fp instead of Fp2? it is even used in that context?
div: (lhs, rhs) => Fp2.mul(lhs, typeof rhs === 'bigint' ? Fp.invert(Fp.create(rhs)) : Fp2.invert(rhs)),
invert: ({ c0: a, c1: b }) => {
div: (lhs, rhs) => Fp2.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp2.inv(rhs)),
inv: ({ c0: a, c1: b }) => {
// We wish to find the multiplicative inverse of a nonzero

@@ -105,7 +105,7 @@ // element a + bu in Fp2. We leverage an identity

// only a single inversion in Fp.
const factor = Fp.invert(Fp.create(a * a + b * b));
const factor = Fp.inv(Fp.create(a * a + b * b));
return { c0: Fp.mul(factor, Fp.create(a)), c1: Fp.mul(factor, Fp.create(-b)) };
},
sqrt: (num) => {
if (Fp2.equals(num, Fp2.ZERO))
if (Fp2.eql(num, Fp2.ZERO))
return Fp2.ZERO; // Algo doesn't handles this case

@@ -119,5 +119,5 @@ // TODO: Optimize this line. It's extremely slow.

const candidateSqrt = Fp2.pow(num, (Fp2.ORDER + 8n) / 16n);
const check = Fp2.div(Fp2.square(candidateSqrt), num); // candidateSqrt.square().div(this);
const check = Fp2.div(Fp2.sqr(candidateSqrt), num); // candidateSqrt.square().div(this);
const R = FP2_ROOTS_OF_UNITY;
const divisor = [R[0], R[2], R[4], R[6]].find((r) => Fp2.equals(r, check));
const divisor = [R[0], R[2], R[4], R[6]].find((r) => Fp2.eql(r, check));
if (!divisor)

@@ -130,3 +130,3 @@ throw new Error('No root');

const x1 = Fp2.div(candidateSqrt, root);
const x2 = Fp2.negate(x1);
const x2 = Fp2.neg(x1);
const { re: re1, im: im1 } = Fp2.reim(x1);

@@ -242,6 +242,6 @@ const { re: re2, im: im2 } = Fp2.reim(x2);

const Fp6Square = ({ c0, c1, c2 }) => {
let t0 = Fp2.square(c0); // c0²
let t0 = Fp2.sqr(c0); // c0²
let t1 = Fp2.mul(Fp2.mul(c0, c1), 2n); // 2 * c0 * c1
let t3 = Fp2.mul(Fp2.mul(c1, c2), 2n); // 2 * c1 * c2
let t4 = Fp2.square(c2); // c2²
let t4 = Fp2.sqr(c2); // c2²
return {

@@ -251,3 +251,3 @@ c0: Fp2.add(Fp2.mulByNonresidue(t3), t0),

// T1 + (c0 - c1 + c2)² + T3 - T0 - T4
c2: Fp2.sub(Fp2.sub(Fp2.add(Fp2.add(t1, Fp2.square(Fp2.add(Fp2.sub(c0, c1), c2))), t3), t0), t4),
c2: Fp2.sub(Fp2.sub(Fp2.add(Fp2.add(t1, Fp2.sqr(Fp2.add(Fp2.sub(c0, c1), c2))), t3), t0), t4),
};

@@ -264,5 +264,5 @@ };

isValid: ({ c0, c1, c2 }) => Fp2.isValid(c0) && Fp2.isValid(c1) && Fp2.isValid(c2),
isZero: ({ c0, c1, c2 }) => Fp2.isZero(c0) && Fp2.isZero(c1) && Fp2.isZero(c2),
negate: ({ c0, c1, c2 }) => ({ c0: Fp2.negate(c0), c1: Fp2.negate(c1), c2: Fp2.negate(c2) }),
equals: ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) => Fp2.equals(c0, r0) && Fp2.equals(c1, r1) && Fp2.equals(c2, r2),
is0: ({ c0, c1, c2 }) => Fp2.is0(c0) && Fp2.is0(c1) && Fp2.is0(c2),
neg: ({ c0, c1, c2 }) => ({ c0: Fp2.neg(c0), c1: Fp2.neg(c1), c2: Fp2.neg(c2) }),
eql: ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) => Fp2.eql(c0, r0) && Fp2.eql(c1, r1) && Fp2.eql(c2, r2),
sqrt: () => {

@@ -272,3 +272,3 @@ throw new Error('Not implemented');

// Do we need division by bigint at all? Should be done via order:
div: (lhs, rhs) => Fp6.mul(lhs, typeof rhs === 'bigint' ? Fp.invert(Fp.create(rhs)) : Fp6.invert(rhs)),
div: (lhs, rhs) => Fp6.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp6.inv(rhs)),
pow: (num, power) => mod.FpPow(Fp6, num, power),

@@ -280,3 +280,3 @@ invertBatch: (nums) => mod.FpInvertBatch(Fp6, nums),

mul: Fp6Multiply,
square: Fp6Square,
sqr: Fp6Square,
// NonNormalized stuff

@@ -286,9 +286,9 @@ addN: Fp6Add,

mulN: Fp6Multiply,
squareN: Fp6Square,
invert: ({ c0, c1, c2 }) => {
let t0 = Fp2.sub(Fp2.square(c0), Fp2.mulByNonresidue(Fp2.mul(c2, c1))); // c0² - c2 * c1 * (u + 1)
let t1 = Fp2.sub(Fp2.mulByNonresidue(Fp2.square(c2)), Fp2.mul(c0, c1)); // c2² * (u + 1) - c0 * c1
let t2 = Fp2.sub(Fp2.square(c1), Fp2.mul(c0, c2)); // c1² - c0 * c2
sqrN: Fp6Square,
inv: ({ c0, c1, c2 }) => {
let t0 = Fp2.sub(Fp2.sqr(c0), Fp2.mulByNonresidue(Fp2.mul(c2, c1))); // c0² - c2 * c1 * (u + 1)
let t1 = Fp2.sub(Fp2.mulByNonresidue(Fp2.sqr(c2)), Fp2.mul(c0, c1)); // c2² * (u + 1) - c0 * c1
let t2 = Fp2.sub(Fp2.sqr(c1), Fp2.mul(c0, c2)); // c1² - c0 * c2
// 1/(((c2 * T1 + c1 * T2) * v) + c0 * T0)
let t4 = Fp2.invert(Fp2.add(Fp2.mulByNonresidue(Fp2.add(Fp2.mul(c2, t1), Fp2.mul(c1, t2))), Fp2.mul(c0, t0)));
let t4 = Fp2.inv(Fp2.add(Fp2.mulByNonresidue(Fp2.add(Fp2.mul(c2, t1), Fp2.mul(c1, t2))), Fp2.mul(c0, t0)));
return { c0: Fp2.mul(t4, t0), c1: Fp2.mul(t4, t1), c2: Fp2.mul(t4, t2) };

@@ -434,7 +434,7 @@ },

function Fp4Square(a, b) {
const a2 = Fp2.square(a);
const b2 = Fp2.square(b);
const a2 = Fp2.sqr(a);
const b2 = Fp2.sqr(b);
return {
first: Fp2.add(Fp2.mulByNonresidue(b2), a2),
second: Fp2.sub(Fp2.sub(Fp2.square(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
second: Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
};

@@ -451,13 +451,13 @@ }

isValid: ({ c0, c1 }) => Fp6.isValid(c0) && Fp6.isValid(c1),
isZero: ({ c0, c1 }) => Fp6.isZero(c0) && Fp6.isZero(c1),
negate: ({ c0, c1 }) => ({ c0: Fp6.negate(c0), c1: Fp6.negate(c1) }),
equals: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp6.equals(c0, r0) && Fp6.equals(c1, r1),
is0: ({ c0, c1 }) => Fp6.is0(c0) && Fp6.is0(c1),
neg: ({ c0, c1 }) => ({ c0: Fp6.neg(c0), c1: Fp6.neg(c1) }),
eql: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp6.eql(c0, r0) && Fp6.eql(c1, r1),
sqrt: () => {
throw new Error('Not implemented');
},
invert: ({ c0, c1 }) => {
let t = Fp6.invert(Fp6.sub(Fp6.square(c0), Fp6.mulByNonresidue(Fp6.square(c1)))); // 1 / (c0² - c1² * v)
return { c0: Fp6.mul(c0, t), c1: Fp6.negate(Fp6.mul(c1, t)) }; // ((C0 * T) * T) + (-C1 * T) * w
inv: ({ c0, c1 }) => {
let t = Fp6.inv(Fp6.sub(Fp6.sqr(c0), Fp6.mulByNonresidue(Fp6.sqr(c1)))); // 1 / (c0² - c1² * v)
return { c0: Fp6.mul(c0, t), c1: Fp6.neg(Fp6.mul(c1, t)) }; // ((C0 * T) * T) + (-C1 * T) * w
},
div: (lhs, rhs) => Fp12.mul(lhs, typeof rhs === 'bigint' ? Fp.invert(Fp.create(rhs)) : Fp12.invert(rhs)),
div: (lhs, rhs) => Fp12.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp12.inv(rhs)),
pow: (num, power) => mod.FpPow(Fp12, num, power),

@@ -469,3 +469,3 @@ invertBatch: (nums) => mod.FpInvertBatch(Fp12, nums),

mul: Fp12Multiply,
square: Fp12Square,
sqr: Fp12Square,
// NonNormalized stuff

@@ -475,3 +475,3 @@ addN: Fp12Add,

mulN: Fp12Multiply,
squareN: Fp12Square,
sqrN: Fp12Square,
// Bytes utils

@@ -530,3 +530,3 @@ fromBytes: (b) => {

}),
conjugate: ({ c0, c1 }) => ({ c0, c1: Fp6.negate(c1) }),
conjugate: ({ c0, c1 }) => ({ c0, c1: Fp6.neg(c1) }),
// A cyclotomic group is a subgroup of Fp^n defined by

@@ -810,3 +810,3 @@ // GΦₙ(p) = {α ∈ Fpⁿ : α^Φₙ(p) = 1}

function psi2(x, y) {
return [Fp2.mul(x, PSI2_C1), Fp2.negate(y)];
return [Fp2.mul(x, PSI2_C1), Fp2.neg(y)];
}

@@ -833,2 +833,3 @@ function G2psi2(c, P) {

DST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
encodeDST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
// p: the characteristic of F

@@ -900,3 +901,3 @@ // where F is a finite field of characteristic p and order q = p^m

const cubicRootOfUnityModP = 0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffen;
const phi = new c(Fp.mul(point.x, cubicRootOfUnityModP), point.y, point.z);
const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz);
// todo: unroll

@@ -943,3 +944,3 @@ const xP = point.multiplyUnsafe(exports.bls12_381.CURVE.x).negate(); // [x]P

if ((y * 2n) / P !== aflag)
y = Fp.negate(y);
y = Fp.neg(y);
return { x: Fp.create(x), y: Fp.create(y) };

@@ -950,3 +951,3 @@ }

if ((bytes[0] & (1 << 6)) !== 0)
return exports.bls12_381.G1.Point.ZERO;
return exports.bls12_381.G1.ProjectivePoint.ZERO.toAffine();
const x = (0, utils_js_1.bytesToNumberBE)(bytes.slice(0, Fp.BYTES));

@@ -962,3 +963,3 @@ const y = (0, utils_js_1.bytesToNumberBE)(bytes.slice(Fp.BYTES));

const isZero = point.equals(c.ZERO);
const { x, y } = point;
const { x, y } = point.toAffine();
if (isCompressed) {

@@ -1050,2 +1051,4 @@ if (isZero)

const bitS = m_byte & 0x20; // sign bit
const L = Fp.BYTES;
const slc = (b, from, to) => (0, utils_js_1.bytesToNumberBE)(b.slice(from, to));
if (bytes.length === 96 && bitC) {

@@ -1062,4 +1065,4 @@ const { b } = exports.bls12_381.CURVE.G2;

}
const x_1 = (0, utils_js_1.bytesToNumberBE)(bytes.slice(0, Fp.BYTES));
const x_0 = (0, utils_js_1.bytesToNumberBE)(bytes.slice(Fp.BYTES));
const x_1 = slc(bytes, 0, L);
const x_0 = slc(bytes, L, 2 * L);
const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });

@@ -1069,3 +1072,3 @@ const right = Fp2.add(Fp2.pow(x, 3n), b); // y² = x³ + 4 * (u+1) = x³ + b

const Y_bit = y.c1 === 0n ? (y.c0 * 2n) / P : (y.c1 * 2n) / P ? 1n : 0n;
y = bitS > 0 && Y_bit > 0 ? y : Fp2.negate(y);
y = bitS > 0 && Y_bit > 0 ? y : Fp2.neg(y);
return { x, y };

@@ -1078,6 +1081,6 @@ }

}
const x1 = (0, utils_js_1.bytesToNumberBE)(bytes.slice(0, Fp.BYTES));
const x0 = (0, utils_js_1.bytesToNumberBE)(bytes.slice(Fp.BYTES, 2 * Fp.BYTES));
const y1 = (0, utils_js_1.bytesToNumberBE)(bytes.slice(2 * Fp.BYTES, 3 * Fp.BYTES));
const y0 = (0, utils_js_1.bytesToNumberBE)(bytes.slice(3 * Fp.BYTES));
const x1 = slc(bytes, 0, L);
const x0 = slc(bytes, L, 2 * L);
const y1 = slc(bytes, 2 * L, 3 * L);
const y0 = slc(bytes, 3 * L, 4 * L);
return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };

@@ -1091,3 +1094,3 @@ }

const isZero = point.equals(c.ZERO);
const { x, y } = point;
const { x, y } = point.toAffine();
if (isCompressed) {

@@ -1124,3 +1127,3 @@ const P = Fp.ORDER;

if (bflag1 === 1n)
return exports.bls12_381.G2.Point.ZERO;
return exports.bls12_381.G2.ProjectivePoint.ZERO;
const x1 = Fp.create(z1 & Fp.MASK);

@@ -1141,4 +1144,5 @@ const x2 = Fp.create(z2);

if (isGreater || isZero)
y = Fp2.negate(y);
const point = new exports.bls12_381.G2.Point(x, y);
y = Fp2.neg(y);
const point = exports.bls12_381.G2.ProjectivePoint.fromAffine({ x, y });
// console.log('Signature.decode', point);
point.assertValidity();

@@ -1150,6 +1154,7 @@ return point;

point.assertValidity();
if (point.equals(exports.bls12_381.G2.Point.ZERO))
if (point.equals(exports.bls12_381.G2.ProjectivePoint.ZERO))
return (0, utils_js_1.concatBytes)(COMPRESSED_ZERO, (0, utils_js_1.numberToBytesBE)(0n, Fp.BYTES));
const { re: x0, im: x1 } = Fp2.reim(point.x);
const { re: y0, im: y1 } = Fp2.reim(point.y);
const a = point.toAffine();
const { re: x0, im: x1 } = Fp2.reim(a.x);
const { re: y0, im: y1 } = Fp2.reim(a.y);
const tmp = y1 > 0n ? y1 * 2n : y0 * 2n;

@@ -1156,0 +1161,0 @@ const aflag1 = Boolean((tmp / Fp.ORDER) & 1n);

@@ -5,4 +5,4 @@ "use strict";

/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
const sha256_1 = require("@noble/hashes/sha256");
const weierstrass_js_1 = require("./abstract/weierstrass.js");
const sha256_1 = require("@noble/hashes/sha256");
const _shortw_utils_js_1 = require("./_shortw_utils.js");

@@ -9,0 +9,0 @@ const modular_js_1 = require("./abstract/modular.js");

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

import { ExtendedPointType } from './abstract/edwards.js';
import { ExtPointType } from './abstract/edwards.js';
import { Hex } from './abstract/utils.js';
import * as htf from './abstract/hash-to-curve.js';
export declare const ED25519_TORSION_SUBGROUP: string[];

@@ -8,3 +9,5 @@ export declare const ed25519: import("./abstract/edwards.js").CurveFn;

export declare const x25519: import("./abstract/montgomery.js").CurveFn;
declare type ExtendedPoint = ExtendedPointType;
declare const hashToCurve: (msg: Hex, options?: htf.htfBasicOpts | undefined) => htf.H2CPoint<bigint>, encodeToCurve: (msg: Hex, options?: htf.htfBasicOpts | undefined) => htf.H2CPoint<bigint>;
export { hashToCurve, encodeToCurve };
declare type ExtendedPoint = ExtPointType;
/**

@@ -46,5 +49,4 @@ * Each ed25519/ExtendedPoint has 8 different equivalent points. This can be

subtract(other: RistrettoPoint): RistrettoPoint;
multiply(scalar: number | bigint): RistrettoPoint;
multiplyUnsafe(scalar: number | bigint): RistrettoPoint;
multiply(scalar: bigint): RistrettoPoint;
multiplyUnsafe(scalar: bigint): RistrettoPoint;
}
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RistrettoPoint = exports.x25519 = exports.ed25519ph = exports.ed25519ctx = exports.ed25519 = exports.ED25519_TORSION_SUBGROUP = void 0;
exports.RistrettoPoint = exports.encodeToCurve = exports.hashToCurve = exports.x25519 = exports.ed25519ph = exports.ed25519ctx = exports.ed25519 = exports.ED25519_TORSION_SUBGROUP = void 0;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

@@ -11,2 +11,3 @@ const sha512_1 = require("@noble/hashes/sha512");

const utils_js_1 = require("./abstract/utils.js");
const htf = require("./abstract/hash-to-curve.js");
/**

@@ -86,2 +87,52 @@ * ed25519 Twisted Edwards curve with following addons:

const Fp = (0, modular_js_1.Fp)(ED25519_P, undefined, true);
const ED25519_DEF = {
// Param: a
a: BigInt(-1),
// Equal to -121665/121666 over finite field.
// Negative number is P - number, and division is invert(number, P)
d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
// Finite field 𝔽p over which we'll do calculations; 2n ** 255n - 19n
Fp,
// Subgroup order: how many points ed25519 has
// 2n ** 252n + 27742317777372353535851937790883648493n;
n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
// Cofactor
h: BigInt(8),
// Base point (x, y) aka generator point
Gx: BigInt('15112221349535400772501151409588531511454012693041857206046113283949847762202'),
Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'),
hash: sha512_1.sha512,
randomBytes: utils_1.randomBytes,
adjustScalarBytes,
// dom2
// Ratio of u to v. Allows us to combine inversion and square root. Uses algo from RFC8032 5.1.3.
// Constant-time, u/√v
uvRatio,
};
exports.ed25519 = (0, edwards_js_1.twistedEdwards)(ED25519_DEF);
function ed25519_domain(data, ctx, phflag) {
if (ctx.length > 255)
throw new Error('Context is too big');
return (0, utils_1.concatBytes)((0, utils_1.utf8ToBytes)('SigEd25519 no Ed25519 collisions'), new Uint8Array([phflag ? 1 : 0, ctx.length]), ctx, data);
}
exports.ed25519ctx = (0, edwards_js_1.twistedEdwards)({ ...ED25519_DEF, domain: ed25519_domain });
exports.ed25519ph = (0, edwards_js_1.twistedEdwards)({
...ED25519_DEF,
domain: ed25519_domain,
preHash: sha512_1.sha512,
});
exports.x25519 = (0, montgomery_js_1.montgomery)({
P: ED25519_P,
a24: BigInt('121665'),
montgomeryBits: 255,
nByteLength: 32,
Gu: '0900000000000000000000000000000000000000000000000000000000000000',
powPminus2: (x) => {
const P = ED25519_P;
// x^(p-2) aka x^(2^255-21)
const { pow_p_5_8, b2 } = ed25519_pow_2_252_3(x);
return (0, modular_js_1.mod)((0, modular_js_1.pow2)(pow_p_5_8, BigInt(3), P) * b2, P);
},
adjustScalarBytes,
});
// Hash To Curve Elligator2 Map (NOTE: different from ristretto255 elligator)

@@ -92,3 +143,3 @@ // NOTE: very important part is usage of FpSqrtEven for ELL2_C1_EDWARDS, since

const ELL2_C2 = Fp.pow(_2n, ELL2_C1); // 2. c2 = 2^c1
const ELL2_C3 = Fp.sqrt(Fp.negate(Fp.ONE)); // 3. c3 = sqrt(-1)
const ELL2_C3 = Fp.sqrt(Fp.neg(Fp.ONE)); // 3. c3 = sqrt(-1)
const ELL2_C4 = (Fp.ORDER - BigInt(5)) / BigInt(8); // 4. c4 = (q - 5) / 8 # Integer arithmetic

@@ -98,7 +149,7 @@ const ELL2_J = BigInt(486662);

function map_to_curve_elligator2_curve25519(u) {
let tv1 = Fp.square(u); // 1. tv1 = u^2
let tv1 = Fp.sqr(u); // 1. tv1 = u^2
tv1 = Fp.mul(tv1, _2n); // 2. tv1 = 2 * tv1
let xd = Fp.add(tv1, Fp.ONE); // 3. xd = tv1 + 1 # Nonzero: -1 is square (mod p), tv1 is not
let x1n = Fp.negate(ELL2_J); // 4. x1n = -J # x1 = x1n / xd = -J / (1 + 2 * u^2)
let tv2 = Fp.square(xd); // 5. tv2 = xd^2
let x1n = Fp.neg(ELL2_J); // 4. x1n = -J # x1 = x1n / xd = -J / (1 + 2 * u^2)
let tv2 = Fp.sqr(xd); // 5. tv2 = xd^2
let gxd = Fp.mul(tv2, xd); // 6. gxd = tv2 * xd # gxd = xd^3

@@ -109,4 +160,4 @@ let gx1 = Fp.mul(tv1, ELL2_J); // 7. gx1 = J * tv1 # x1n + J * xd

gx1 = Fp.mul(gx1, x1n); // 10. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
let tv3 = Fp.square(gxd); // 11. tv3 = gxd^2
tv2 = Fp.square(tv3); // 12. tv2 = tv3^2 # gxd^4
let tv3 = Fp.sqr(gxd); // 11. tv3 = gxd^2
tv2 = Fp.sqr(tv3); // 12. tv2 = tv3^2 # gxd^4
tv3 = Fp.mul(tv3, gxd); // 13. tv3 = tv3 * gxd # gxd^3

@@ -118,5 +169,5 @@ tv3 = Fp.mul(tv3, gx1); // 14. tv3 = tv3 * gx1 # gx1 * gxd^3

let y12 = Fp.mul(y11, ELL2_C3); // 18. y12 = y11 * c3
tv2 = Fp.square(y11); // 19. tv2 = y11^2
tv2 = Fp.sqr(y11); // 19. tv2 = y11^2
tv2 = Fp.mul(tv2, gxd); // 20. tv2 = tv2 * gxd
let e1 = Fp.equals(tv2, gx1); // 21. e1 = tv2 == gx1
let e1 = Fp.eql(tv2, gx1); // 21. e1 = tv2 == gx1
let y1 = Fp.cmov(y12, y11, e1); // 22. y1 = CMOV(y12, y11, e1) # If g(x1) is square, this is its sqrt

@@ -128,16 +179,16 @@ let x2n = Fp.mul(x1n, tv1); // 23. x2n = x1n * tv1 # x2 = x2n / xd = 2 * u^2 * x1n / xd

let gx2 = Fp.mul(gx1, tv1); // 27. gx2 = gx1 * tv1 # g(x2) = gx2 / gxd = 2 * u^2 * g(x1)
tv2 = Fp.square(y21); // 28. tv2 = y21^2
tv2 = Fp.sqr(y21); // 28. tv2 = y21^2
tv2 = Fp.mul(tv2, gxd); // 29. tv2 = tv2 * gxd
let e2 = Fp.equals(tv2, gx2); // 30. e2 = tv2 == gx2
let e2 = Fp.eql(tv2, gx2); // 30. e2 = tv2 == gx2
let y2 = Fp.cmov(y22, y21, e2); // 31. y2 = CMOV(y22, y21, e2) # If g(x2) is square, this is its sqrt
tv2 = Fp.square(y1); // 32. tv2 = y1^2
tv2 = Fp.sqr(y1); // 32. tv2 = y1^2
tv2 = Fp.mul(tv2, gxd); // 33. tv2 = tv2 * gxd
let e3 = Fp.equals(tv2, gx1); // 34. e3 = tv2 == gx1
let e3 = Fp.eql(tv2, gx1); // 34. e3 = tv2 == gx1
let xn = Fp.cmov(x2n, x1n, e3); // 35. xn = CMOV(x2n, x1n, e3) # If e3, x = x1, else x = x2
let y = Fp.cmov(y2, y1, e3); // 36. y = CMOV(y2, y1, e3) # If e3, y = y1, else y = y2
let e4 = Fp.isOdd(y); // 37. e4 = sgn0(y) == 1 # Fix sign of y
y = Fp.cmov(y, Fp.negate(y), e3 !== e4); // 38. y = CMOV(y, -y, e3 XOR e4)
y = Fp.cmov(y, Fp.neg(y), e3 !== e4); // 38. y = CMOV(y, -y, e3 XOR e4)
return { xMn: xn, xMd: xd, yMn: y, yMd: 1n }; // 39. return (xn, xd, y, 1)
}
const ELL2_C1_EDWARDS = (0, modular_js_1.FpSqrtEven)(Fp, Fp.negate(BigInt(486664))); // sgn0(c1) MUST equal 0
const ELL2_C1_EDWARDS = (0, modular_js_1.FpSqrtEven)(Fp, Fp.neg(BigInt(486664))); // sgn0(c1) MUST equal 0
function map_to_curve_elligator2_edwards25519(u) {

@@ -151,3 +202,3 @@ const { xMn, xMd, yMn, yMd } = map_to_curve_elligator2_curve25519(u); // 1. (xMn, xMd, yMn, yMd) = map_to_curve_elligator2_curve25519(u)

let tv1 = Fp.mul(xd, yd); // 7. tv1 = xd * yd
let e = Fp.equals(tv1, Fp.ZERO); // 8. e = tv1 == 0
let e = Fp.eql(tv1, Fp.ZERO); // 8. e = tv1 == 0
xn = Fp.cmov(xn, Fp.ZERO, e); // 9. xn = CMOV(xn, 0, e)

@@ -160,64 +211,16 @@ xd = Fp.cmov(xd, Fp.ONE, e); // 10. xd = CMOV(xd, 1, e)

}
const ED25519_DEF = {
// Param: a
a: BigInt(-1),
// Equal to -121665/121666 over finite field.
// Negative number is P - number, and division is invert(number, P)
d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
// Finite field 𝔽p over which we'll do calculations; 2n ** 255n - 19n
Fp,
// Subgroup order: how many points ed25519 has
// 2n ** 252n + 27742317777372353535851937790883648493n;
n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
// Cofactor
h: BigInt(8),
// Base point (x, y) aka generator point
Gx: BigInt('15112221349535400772501151409588531511454012693041857206046113283949847762202'),
Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'),
const { hashToCurve, encodeToCurve } = htf.hashToCurve(exports.ed25519.ExtendedPoint, (scalars) => map_to_curve_elligator2_edwards25519(scalars[0]), {
DST: 'edwards25519_XMD:SHA-512_ELL2_RO_',
encodeDST: 'edwards25519_XMD:SHA-512_ELL2_NU_',
p: Fp.ORDER,
m: 1,
k: 128,
expand: 'xmd',
hash: sha512_1.sha512,
randomBytes: utils_1.randomBytes,
adjustScalarBytes,
// dom2
// Ratio of u to v. Allows us to combine inversion and square root. Uses algo from RFC8032 5.1.3.
// Constant-time, u/√v
uvRatio,
htfDefaults: {
DST: 'edwards25519_XMD:SHA-512_ELL2_RO_',
p: Fp.ORDER,
m: 1,
k: 128,
expand: 'xmd',
hash: sha512_1.sha512,
},
mapToCurve: (scalars) => map_to_curve_elligator2_edwards25519(scalars[0]),
};
exports.ed25519 = (0, edwards_js_1.twistedEdwards)(ED25519_DEF);
function ed25519_domain(data, ctx, phflag) {
if (ctx.length > 255)
throw new Error('Context is too big');
return (0, utils_1.concatBytes)((0, utils_1.utf8ToBytes)('SigEd25519 no Ed25519 collisions'), new Uint8Array([phflag ? 1 : 0, ctx.length]), ctx, data);
}
exports.ed25519ctx = (0, edwards_js_1.twistedEdwards)({ ...ED25519_DEF, domain: ed25519_domain });
exports.ed25519ph = (0, edwards_js_1.twistedEdwards)({
...ED25519_DEF,
domain: ed25519_domain,
preHash: sha512_1.sha512,
});
exports.x25519 = (0, montgomery_js_1.montgomery)({
P: ED25519_P,
a24: BigInt('121665'),
montgomeryBits: 255,
nByteLength: 32,
Gu: '0900000000000000000000000000000000000000000000000000000000000000',
powPminus2: (x) => {
const P = ED25519_P;
// x^(p-2) aka x^(2^255-21)
const { pow_p_5_8, b2 } = ed25519_pow_2_252_3(x);
return (0, modular_js_1.mod)((0, modular_js_1.pow2)(pow_p_5_8, BigInt(3), P) * b2, P);
},
adjustScalarBytes,
});
exports.hashToCurve = hashToCurve;
exports.encodeToCurve = encodeToCurve;
function assertRstPoint(other) {
if (!(other instanceof RistrettoPoint))
throw new TypeError('RistrettoPoint expected');
throw new Error('RistrettoPoint expected');
}

@@ -331,3 +334,3 @@ // √(-1) aka √(a) aka 2^((p-1)/4)

toRawBytes() {
let { x, y, z, t } = this.ep;
let { ex: x, ey: y, ez: z, et: t } = this.ep;
const P = exports.ed25519.CURVE.Fp.ORDER;

@@ -370,8 +373,8 @@ const mod = exports.ed25519.CURVE.Fp.create;

assertRstPoint(other);
const a = this.ep;
const b = other.ep;
const { ex: X1, ey: Y1 } = this.ep;
const { ex: X2, ey: Y2 } = this.ep;
const mod = exports.ed25519.CURVE.Fp.create;
// (x1 * y2 == y1 * x2) | (y1 * y2 == x1 * x2)
const one = mod(a.x * b.y) === mod(a.y * b.x);
const two = mod(a.y * b.y) === mod(a.x * b.x);
const one = mod(X1 * Y2) === mod(Y1 * X2);
const two = mod(Y1 * Y2) === mod(X1 * X2);
return one || two;

@@ -378,0 +381,0 @@ }

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

import * as htf from './abstract/hash-to-curve.js';
export declare const ed448: import("./abstract/edwards.js").CurveFn;
export declare const ed448ph: import("./abstract/edwards.js").CurveFn;
export declare const x448: import("./abstract/montgomery.js").CurveFn;
declare const hashToCurve: (msg: import("./abstract/utils.js").Hex, options?: htf.htfBasicOpts | undefined) => htf.H2CPoint<bigint>, encodeToCurve: (msg: import("./abstract/utils.js").Hex, options?: htf.htfBasicOpts | undefined) => htf.H2CPoint<bigint>;
export { hashToCurve, encodeToCurve };
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.x448 = exports.ed448ph = exports.ed448 = void 0;
exports.encodeToCurve = exports.hashToCurve = exports.x448 = exports.ed448ph = exports.ed448 = void 0;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

@@ -10,2 +10,3 @@ const sha3_1 = require("@noble/hashes/sha3");

const montgomery_js_1 = require("./abstract/montgomery.js");
const htf = require("./abstract/hash-to-curve.js");
/**

@@ -53,75 +54,2 @@ * Edwards448 (not Ed448-Goldilocks) curve with following addons:

const Fp = (0, modular_js_1.Fp)(ed448P, 456, true);
// Hash To Curve Elligator2 Map
const ELL2_C1 = (Fp.ORDER - BigInt(3)) / BigInt(4); // 1. c1 = (q - 3) / 4 # Integer arithmetic
const ELL2_J = BigInt(156326);
function map_to_curve_elligator2_curve448(u) {
let tv1 = Fp.square(u); // 1. tv1 = u^2
let e1 = Fp.equals(tv1, Fp.ONE); // 2. e1 = tv1 == 1
tv1 = Fp.cmov(tv1, Fp.ZERO, e1); // 3. tv1 = CMOV(tv1, 0, e1) # If Z * u^2 == -1, set tv1 = 0
let xd = Fp.sub(Fp.ONE, tv1); // 4. xd = 1 - tv1
let x1n = Fp.negate(ELL2_J); // 5. x1n = -J
let tv2 = Fp.square(xd); // 6. tv2 = xd^2
let gxd = Fp.mul(tv2, xd); // 7. gxd = tv2 * xd # gxd = xd^3
let gx1 = Fp.mul(tv1, Fp.negate(ELL2_J)); // 8. gx1 = -J * tv1 # x1n + J * xd
gx1 = Fp.mul(gx1, x1n); // 9. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd
gx1 = Fp.add(gx1, tv2); // 10. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2
gx1 = Fp.mul(gx1, x1n); // 11. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
let tv3 = Fp.square(gxd); // 12. tv3 = gxd^2
tv2 = Fp.mul(gx1, gxd); // 13. tv2 = gx1 * gxd # gx1 * gxd
tv3 = Fp.mul(tv3, tv2); // 14. tv3 = tv3 * tv2 # gx1 * gxd^3
let y1 = Fp.pow(tv3, ELL2_C1); // 15. y1 = tv3^c1 # (gx1 * gxd^3)^((p - 3) / 4)
y1 = Fp.mul(y1, tv2); // 16. y1 = y1 * tv2 # gx1 * gxd * (gx1 * gxd^3)^((p - 3) / 4)
let x2n = Fp.mul(x1n, Fp.negate(tv1)); // 17. x2n = -tv1 * x1n # x2 = x2n / xd = -1 * u^2 * x1n / xd
let y2 = Fp.mul(y1, u); // 18. y2 = y1 * u
y2 = Fp.cmov(y2, Fp.ZERO, e1); // 19. y2 = CMOV(y2, 0, e1)
tv2 = Fp.square(y1); // 20. tv2 = y1^2
tv2 = Fp.mul(tv2, gxd); // 21. tv2 = tv2 * gxd
let e2 = Fp.equals(tv2, gx1); // 22. e2 = tv2 == gx1
let xn = Fp.cmov(x2n, x1n, e2); // 23. xn = CMOV(x2n, x1n, e2) # If e2, x = x1, else x = x2
let y = Fp.cmov(y2, y1, e2); // 24. y = CMOV(y2, y1, e2) # If e2, y = y1, else y = y2
let e3 = Fp.isOdd(y); // 25. e3 = sgn0(y) == 1 # Fix sign of y
y = Fp.cmov(y, Fp.negate(y), e2 !== e3); // 26. y = CMOV(y, -y, e2 XOR e3)
return { xn, xd, yn: y, yd: Fp.ONE }; // 27. return (xn, xd, y, 1)
}
function map_to_curve_elligator2_edwards448(u) {
let { xn, xd, yn, yd } = map_to_curve_elligator2_curve448(u); // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
let xn2 = Fp.square(xn); // 2. xn2 = xn^2
let xd2 = Fp.square(xd); // 3. xd2 = xd^2
let xd4 = Fp.square(xd2); // 4. xd4 = xd2^2
let yn2 = Fp.square(yn); // 5. yn2 = yn^2
let yd2 = Fp.square(yd); // 6. yd2 = yd^2
let xEn = Fp.sub(xn2, xd2); // 7. xEn = xn2 - xd2
let tv2 = Fp.sub(xEn, xd2); // 8. tv2 = xEn - xd2
xEn = Fp.mul(xEn, xd2); // 9. xEn = xEn * xd2
xEn = Fp.mul(xEn, yd); // 10. xEn = xEn * yd
xEn = Fp.mul(xEn, yn); // 11. xEn = xEn * yn
xEn = Fp.mul(xEn, 4n); // 12. xEn = xEn * 4
tv2 = Fp.mul(tv2, xn2); // 13. tv2 = tv2 * xn2
tv2 = Fp.mul(tv2, yd2); // 14. tv2 = tv2 * yd2
let tv3 = Fp.mul(yn2, 4n); // 15. tv3 = 4 * yn2
let tv1 = Fp.add(tv3, yd2); // 16. tv1 = tv3 + yd2
tv1 = Fp.mul(tv1, xd4); // 17. tv1 = tv1 * xd4
let xEd = Fp.add(tv1, tv2); // 18. xEd = tv1 + tv2
tv2 = Fp.mul(tv2, xn); // 19. tv2 = tv2 * xn
let tv4 = Fp.mul(xn, xd4); // 20. tv4 = xn * xd4
let yEn = Fp.sub(tv3, yd2); // 21. yEn = tv3 - yd2
yEn = Fp.mul(yEn, tv4); // 22. yEn = yEn * tv4
yEn = Fp.sub(yEn, tv2); // 23. yEn = yEn - tv2
tv1 = Fp.add(xn2, xd2); // 24. tv1 = xn2 + xd2
tv1 = Fp.mul(tv1, xd2); // 25. tv1 = tv1 * xd2
tv1 = Fp.mul(tv1, xd); // 26. tv1 = tv1 * xd
tv1 = Fp.mul(tv1, yn2); // 27. tv1 = tv1 * yn2
tv1 = Fp.mul(tv1, BigInt(-2)); // 28. tv1 = -2 * tv1
let yEd = Fp.add(tv2, tv1); // 29. yEd = tv2 + tv1
tv4 = Fp.mul(tv4, yd2); // 30. tv4 = tv4 * yd2
yEd = Fp.add(yEd, tv4); // 31. yEd = yEd + tv4
tv1 = Fp.mul(xEd, yEd); // 32. tv1 = xEd * yEd
let e = Fp.equals(tv1, Fp.ZERO); // 33. e = tv1 == 0
xEn = Fp.cmov(xEn, Fp.ZERO, e); // 34. xEn = CMOV(xEn, 0, e)
xEd = Fp.cmov(xEd, Fp.ONE, e); // 35. xEd = CMOV(xEd, 1, e)
yEn = Fp.cmov(yEn, Fp.ONE, e); // 36. yEn = CMOV(yEn, 1, e)
yEd = Fp.cmov(yEd, Fp.ONE, e); // 37. yEd = CMOV(yEd, 1, e)
const inv = Fp.invertBatch([xEd, yEd]); // batch division
return { x: Fp.mul(xEn, inv[0]), y: Fp.mul(yEn, inv[1]) }; // 38. return (xEn, xEd, yEn, yEd)
}
const ED448_DEF = {

@@ -174,11 +102,2 @@ // Param: a

},
htfDefaults: {
DST: 'edwards448_XOF:SHAKE256_ELL2_RO_',
p: Fp.ORDER,
m: 1,
k: 224,
expand: 'xof',
hash: sha3_1.shake256,
},
mapToCurve: (scalars) => map_to_curve_elligator2_edwards448(scalars[0]),
};

@@ -216,1 +135,85 @@ exports.ed448 = (0, edwards_js_1.twistedEdwards)(ED448_DEF);

});
// Hash To Curve Elligator2 Map
const ELL2_C1 = (Fp.ORDER - BigInt(3)) / BigInt(4); // 1. c1 = (q - 3) / 4 # Integer arithmetic
const ELL2_J = BigInt(156326);
function map_to_curve_elligator2_curve448(u) {
let tv1 = Fp.sqr(u); // 1. tv1 = u^2
let e1 = Fp.eql(tv1, Fp.ONE); // 2. e1 = tv1 == 1
tv1 = Fp.cmov(tv1, Fp.ZERO, e1); // 3. tv1 = CMOV(tv1, 0, e1) # If Z * u^2 == -1, set tv1 = 0
let xd = Fp.sub(Fp.ONE, tv1); // 4. xd = 1 - tv1
let x1n = Fp.neg(ELL2_J); // 5. x1n = -J
let tv2 = Fp.sqr(xd); // 6. tv2 = xd^2
let gxd = Fp.mul(tv2, xd); // 7. gxd = tv2 * xd # gxd = xd^3
let gx1 = Fp.mul(tv1, Fp.neg(ELL2_J)); // 8. gx1 = -J * tv1 # x1n + J * xd
gx1 = Fp.mul(gx1, x1n); // 9. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd
gx1 = Fp.add(gx1, tv2); // 10. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2
gx1 = Fp.mul(gx1, x1n); // 11. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
let tv3 = Fp.sqr(gxd); // 12. tv3 = gxd^2
tv2 = Fp.mul(gx1, gxd); // 13. tv2 = gx1 * gxd # gx1 * gxd
tv3 = Fp.mul(tv3, tv2); // 14. tv3 = tv3 * tv2 # gx1 * gxd^3
let y1 = Fp.pow(tv3, ELL2_C1); // 15. y1 = tv3^c1 # (gx1 * gxd^3)^((p - 3) / 4)
y1 = Fp.mul(y1, tv2); // 16. y1 = y1 * tv2 # gx1 * gxd * (gx1 * gxd^3)^((p - 3) / 4)
let x2n = Fp.mul(x1n, Fp.neg(tv1)); // 17. x2n = -tv1 * x1n # x2 = x2n / xd = -1 * u^2 * x1n / xd
let y2 = Fp.mul(y1, u); // 18. y2 = y1 * u
y2 = Fp.cmov(y2, Fp.ZERO, e1); // 19. y2 = CMOV(y2, 0, e1)
tv2 = Fp.sqr(y1); // 20. tv2 = y1^2
tv2 = Fp.mul(tv2, gxd); // 21. tv2 = tv2 * gxd
let e2 = Fp.eql(tv2, gx1); // 22. e2 = tv2 == gx1
let xn = Fp.cmov(x2n, x1n, e2); // 23. xn = CMOV(x2n, x1n, e2) # If e2, x = x1, else x = x2
let y = Fp.cmov(y2, y1, e2); // 24. y = CMOV(y2, y1, e2) # If e2, y = y1, else y = y2
let e3 = Fp.isOdd(y); // 25. e3 = sgn0(y) == 1 # Fix sign of y
y = Fp.cmov(y, Fp.neg(y), e2 !== e3); // 26. y = CMOV(y, -y, e2 XOR e3)
return { xn, xd, yn: y, yd: Fp.ONE }; // 27. return (xn, xd, y, 1)
}
function map_to_curve_elligator2_edwards448(u) {
let { xn, xd, yn, yd } = map_to_curve_elligator2_curve448(u); // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
let xn2 = Fp.sqr(xn); // 2. xn2 = xn^2
let xd2 = Fp.sqr(xd); // 3. xd2 = xd^2
let xd4 = Fp.sqr(xd2); // 4. xd4 = xd2^2
let yn2 = Fp.sqr(yn); // 5. yn2 = yn^2
let yd2 = Fp.sqr(yd); // 6. yd2 = yd^2
let xEn = Fp.sub(xn2, xd2); // 7. xEn = xn2 - xd2
let tv2 = Fp.sub(xEn, xd2); // 8. tv2 = xEn - xd2
xEn = Fp.mul(xEn, xd2); // 9. xEn = xEn * xd2
xEn = Fp.mul(xEn, yd); // 10. xEn = xEn * yd
xEn = Fp.mul(xEn, yn); // 11. xEn = xEn * yn
xEn = Fp.mul(xEn, 4n); // 12. xEn = xEn * 4
tv2 = Fp.mul(tv2, xn2); // 13. tv2 = tv2 * xn2
tv2 = Fp.mul(tv2, yd2); // 14. tv2 = tv2 * yd2
let tv3 = Fp.mul(yn2, 4n); // 15. tv3 = 4 * yn2
let tv1 = Fp.add(tv3, yd2); // 16. tv1 = tv3 + yd2
tv1 = Fp.mul(tv1, xd4); // 17. tv1 = tv1 * xd4
let xEd = Fp.add(tv1, tv2); // 18. xEd = tv1 + tv2
tv2 = Fp.mul(tv2, xn); // 19. tv2 = tv2 * xn
let tv4 = Fp.mul(xn, xd4); // 20. tv4 = xn * xd4
let yEn = Fp.sub(tv3, yd2); // 21. yEn = tv3 - yd2
yEn = Fp.mul(yEn, tv4); // 22. yEn = yEn * tv4
yEn = Fp.sub(yEn, tv2); // 23. yEn = yEn - tv2
tv1 = Fp.add(xn2, xd2); // 24. tv1 = xn2 + xd2
tv1 = Fp.mul(tv1, xd2); // 25. tv1 = tv1 * xd2
tv1 = Fp.mul(tv1, xd); // 26. tv1 = tv1 * xd
tv1 = Fp.mul(tv1, yn2); // 27. tv1 = tv1 * yn2
tv1 = Fp.mul(tv1, BigInt(-2)); // 28. tv1 = -2 * tv1
let yEd = Fp.add(tv2, tv1); // 29. yEd = tv2 + tv1
tv4 = Fp.mul(tv4, yd2); // 30. tv4 = tv4 * yd2
yEd = Fp.add(yEd, tv4); // 31. yEd = yEd + tv4
tv1 = Fp.mul(xEd, yEd); // 32. tv1 = xEd * yEd
let e = Fp.eql(tv1, Fp.ZERO); // 33. e = tv1 == 0
xEn = Fp.cmov(xEn, Fp.ZERO, e); // 34. xEn = CMOV(xEn, 0, e)
xEd = Fp.cmov(xEd, Fp.ONE, e); // 35. xEd = CMOV(xEd, 1, e)
yEn = Fp.cmov(yEn, Fp.ONE, e); // 36. yEn = CMOV(yEn, 1, e)
yEd = Fp.cmov(yEd, Fp.ONE, e); // 37. yEd = CMOV(yEd, 1, e)
const inv = Fp.invertBatch([xEd, yEd]); // batch division
return { x: Fp.mul(xEn, inv[0]), y: Fp.mul(yEn, inv[1]) }; // 38. return (xEn, xEd, yEn, yEd)
}
const { hashToCurve, encodeToCurve } = htf.hashToCurve(exports.ed448.ExtendedPoint, (scalars) => map_to_curve_elligator2_edwards448(scalars[0]), {
DST: 'edwards448_XOF:SHAKE256_ELL2_RO_',
encodeDST: 'edwards448_XOF:SHAKE256_ELL2_NU_',
p: Fp.ORDER,
m: 1,
k: 224,
expand: 'xof',
hash: sha3_1.shake256,
});
exports.hashToCurve = hashToCurve;
exports.encodeToCurve = encodeToCurve;

@@ -1,12 +0,14 @@

import * as ut from './utils.js';
import { stringToBytes, hash_to_field as hashToField, expand_message_xmd as expandMessageXMD, } from './hash-to-curve.js';
import { weierstrassPoints } from './weierstrass.js';
import { hashToPrivateScalar } from './modular.js';
import { bitLen, bitGet, hexToBytes, bytesToHex } from './utils.js';
import * as htf from './hash-to-curve.js';
import { weierstrassPoints, } from './weierstrass.js';
export function bls(CURVE) {
// Fields looks pretty specific for curve, so for now we need to pass them with options
const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE;
const BLS_X_LEN = ut.bitLen(CURVE.x);
const BLS_X_LEN = bitLen(CURVE.x);
const groupLen = 32; // TODO: calculate; hardcoded for now
// Pre-compute coefficients for sparse multiplication
// Point addition and point double calculations is reused for coefficients
function calcPairingPrecomputes(x, y) {
function calcPairingPrecomputes(p) {
const { x, y } = p;
// prettier-ignore

@@ -19,16 +21,16 @@ const Qx = x, Qy = y, Qz = Fp2.ONE;

// Double
let t0 = Fp2.square(Ry); // Ry²
let t1 = Fp2.square(Rz); // Rz²
let t0 = Fp2.sqr(Ry); // Ry²
let t1 = Fp2.sqr(Rz); // Rz²
let t2 = Fp2.multiplyByB(Fp2.mul(t1, 3n)); // 3 * T1 * B
let t3 = Fp2.mul(t2, 3n); // 3 * T2
let t4 = Fp2.sub(Fp2.sub(Fp2.square(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
let t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
ell_coeff.push([
Fp2.sub(t2, t0),
Fp2.mul(Fp2.square(Rx), 3n),
Fp2.negate(t4), // -T4
Fp2.mul(Fp2.sqr(Rx), 3n),
Fp2.neg(t4), // -T4
]);
Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), 2n); // ((T0 - T3) * Rx * Ry) / 2
Ry = Fp2.sub(Fp2.square(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.square(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.sqr(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
Rz = Fp2.mul(t0, t4); // T0 * T4
if (ut.bitGet(CURVE.x, i)) {
if (bitGet(CURVE.x, i)) {
// Addition

@@ -39,9 +41,9 @@ let t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz

Fp2.sub(Fp2.mul(t0, Qx), Fp2.mul(t1, Qy)),
Fp2.negate(t0),
Fp2.neg(t0),
t1, // T1
]);
let t2 = Fp2.square(t1); // T1²
let t2 = Fp2.sqr(t1); // T1²
let t3 = Fp2.mul(t2, t1); // T2 * T1
let t4 = Fp2.mul(t2, Rx); // T2 * Rx
let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.square(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
Rx = Fp2.mul(t1, t5); // T1 * T5

@@ -62,3 +64,3 @@ Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry

f12 = Fp12.multiplyBy014(f12, E[0], Fp2.mul(E[1], Px), Fp2.mul(E[2], Py));
if (ut.bitGet(x, i)) {
if (bitGet(x, i)) {
j += 1;

@@ -69,3 +71,3 @@ const F = ell[j];

if (i !== 0)
f12 = Fp12.square(f12);
f12 = Fp12.sqr(f12);
}

@@ -75,19 +77,11 @@ return Fp12.conjugate(f12);

const utils = {
hexToBytes: ut.hexToBytes,
bytesToHex: ut.bytesToHex,
stringToBytes: stringToBytes,
hexToBytes: hexToBytes,
bytesToHex: bytesToHex,
stringToBytes: htf.stringToBytes,
// TODO: do we need to export it here?
hashToField: (msg, count, options = {}) => hashToField(msg, count, { ...CURVE.htfDefaults, ...options }),
expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => expandMessageXMD(msg, DST, lenInBytes, H),
hashToPrivateKey: (hash) => Fr.toBytes(ut.hashToPrivateScalar(hash, CURVE.r)),
hashToField: (msg, count, options = {}) => htf.hash_to_field(msg, count, { ...CURVE.htfDefaults, ...options }),
expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => htf.expand_message_xmd(msg, DST, lenInBytes, H),
hashToPrivateKey: (hash) => Fr.toBytes(hashToPrivateScalar(hash, CURVE.r)),
randomBytes: (bytesLength = groupLen) => CURVE.randomBytes(bytesLength),
randomPrivateKey: () => utils.hashToPrivateKey(utils.randomBytes(groupLen + 8)),
getDSTLabel: () => CURVE.htfDefaults.DST,
setDSTLabel(newLabel) {
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3.1
if (typeof newLabel !== 'string' || newLabel.length > 2048 || newLabel.length === 0) {
throw new TypeError('Invalid DST');
}
CURVE.htfDefaults.DST = newLabel;
},
};

@@ -99,2 +93,6 @@ // Point on G1 curve: (x, y)

});
const G1HashToCurve = htf.hashToCurve(G1.ProjectivePoint, CURVE.G1.mapToCurve, {
...CURVE.htfDefaults,
...CURVE.G1.htfDefaults,
});
function pairingPrecomputes(point) {

@@ -104,13 +102,10 @@ const p = point;

return p._PPRECOMPUTES;
p._PPRECOMPUTES = calcPairingPrecomputes(p.x, p.y);
p._PPRECOMPUTES = calcPairingPrecomputes(point.toAffine());
return p._PPRECOMPUTES;
}
function clearPairingPrecomputes(point) {
const p = point;
p._PPRECOMPUTES = undefined;
}
clearPairingPrecomputes;
function millerLoopG1(Q, P) {
return millerLoop(pairingPrecomputes(P), [Q.x, Q.y]);
}
// TODO: export
// function clearPairingPrecomputes(point: G2) {
// const p = point as G2 & withPairingPrecomputes;
// p._PPRECOMPUTES = undefined;
// }
// Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)

@@ -121,21 +116,29 @@ const G2 = weierstrassPoints({

});
const C = G2.ProjectivePoint; // TODO: fix
const G2HashToCurve = htf.hashToCurve(C, CURVE.G2.mapToCurve, {
...CURVE.htfDefaults,
...CURVE.G2.htfDefaults,
});
const { Signature } = CURVE.G2;
// Calculates bilinear pairing
function pairing(P, Q, withFinalExponent = true) {
if (P.equals(G1.Point.ZERO) || Q.equals(G2.Point.ZERO))
throw new Error('No pairings at point of Infinity');
function pairing(Q, P, withFinalExponent = true) {
if (Q.equals(G1.ProjectivePoint.ZERO) || P.equals(G2.ProjectivePoint.ZERO))
throw new Error('pairing is not available for ZERO point');
Q.assertValidity();
P.assertValidity();
Q.assertValidity();
// Performance: 9ms for millerLoop and ~14ms for exp.
const looped = millerLoopG1(P, Q);
const Qa = Q.toAffine();
const looped = millerLoop(pairingPrecomputes(P), [Qa.x, Qa.y]);
return withFinalExponent ? Fp12.finalExponentiate(looped) : looped;
}
function normP1(point) {
return point instanceof G1.Point ? point : G1.Point.fromHex(point);
return point instanceof G1.ProjectivePoint ? point : G1.ProjectivePoint.fromHex(point);
}
function normP2(point) {
return point instanceof G2.Point ? point : Signature.decode(point);
return point instanceof G2.ProjectivePoint ? point : Signature.decode(point);
}
function normP2Hash(point) {
return point instanceof G2.Point ? point : G2.Point.hashToCurve(point);
function normP2Hash(point, htfOpts) {
return point instanceof G2.ProjectivePoint
? point
: G2HashToCurve.hashToCurve(point, htfOpts);
}

@@ -145,9 +148,9 @@ // Multiplies generator by private key.

function getPublicKey(privateKey) {
return G1.Point.fromPrivateKey(privateKey).toRawBytes(true);
return G1.ProjectivePoint.fromPrivateKey(privateKey).toRawBytes(true);
}
function sign(message, privateKey) {
const msgPoint = normP2Hash(message);
function sign(message, privateKey, htfOpts) {
const msgPoint = normP2Hash(message, htfOpts);
msgPoint.assertValidity();
const sigPoint = msgPoint.multiply(G1.normalizePrivateKey(privateKey));
if (message instanceof G2.Point)
if (message instanceof G2.ProjectivePoint)
return sigPoint;

@@ -158,6 +161,6 @@ return Signature.encode(sigPoint);

// e(P, H(m)) == e(G, S)
function verify(signature, message, publicKey) {
function verify(signature, message, publicKey, htfOpts) {
const P = normP1(publicKey);
const Hm = normP2Hash(message);
const G = G1.Point.BASE;
const Hm = normP2Hash(message, htfOpts);
const G = G1.ProjectivePoint.BASE;
const S = normP2(signature);

@@ -169,3 +172,3 @@ // Instead of doing 2 exponentiations, we use property of billinear maps

const exp = Fp12.finalExponentiate(Fp12.mul(eGS, ePHm));
return Fp12.equals(exp, Fp12.ONE);
return Fp12.eql(exp, Fp12.ONE);
}

@@ -175,7 +178,5 @@ function aggregatePublicKeys(publicKeys) {

throw new Error('Expected non-empty array');
const agg = publicKeys
.map(normP1)
.reduce((sum, p) => sum.add(G1.ProjectivePoint.fromAffine(p)), G1.ProjectivePoint.ZERO);
const aggAffine = agg.toAffine();
if (publicKeys[0] instanceof G1.Point) {
const agg = publicKeys.map(normP1).reduce((sum, p) => sum.add(p), G1.ProjectivePoint.ZERO);
const aggAffine = agg; //.toAffine();
if (publicKeys[0] instanceof G1.ProjectivePoint) {
aggAffine.assertValidity();

@@ -190,7 +191,5 @@ return aggAffine;

throw new Error('Expected non-empty array');
const agg = signatures
.map(normP2)
.reduce((sum, s) => sum.add(G2.ProjectivePoint.fromAffine(s)), G2.ProjectivePoint.ZERO);
const aggAffine = agg.toAffine();
if (signatures[0] instanceof G2.Point) {
const agg = signatures.map(normP2).reduce((sum, s) => sum.add(s), G2.ProjectivePoint.ZERO);
const aggAffine = agg; //.toAffine();
if (signatures[0] instanceof G2.ProjectivePoint) {
aggAffine.assertValidity();

@@ -203,3 +202,5 @@ return aggAffine;

// e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
function verifyBatch(signature, messages, publicKeys) {
function verifyBatch(signature, messages, publicKeys, htfOpts) {
// @ts-ignore
// console.log('verifyBatch', bytesToHex(signature as any), messages, publicKeys.map(bytesToHex));
if (!messages.length)

@@ -210,3 +211,3 @@ throw new Error('Expected non-empty messages array');

const sig = normP2(signature);
const nMessages = messages.map(normP2Hash);
const nMessages = messages.map((i) => normP2Hash(i, htfOpts));
const nPublicKeys = publicKeys.map(normP1);

@@ -216,3 +217,3 @@ try {

for (const message of new Set(nMessages)) {
const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.Point.ZERO);
const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.ProjectivePoint.ZERO);
// const msg = message instanceof PointG2 ? message : await PointG2.hashToCurve(message);

@@ -222,6 +223,6 @@ // Possible to batch pairing for same msg with different groupPublicKey here

}
paired.push(pairing(G1.Point.BASE.negate(), sig, false));
paired.push(pairing(G1.ProjectivePoint.BASE.negate(), sig, false));
const product = paired.reduce((a, b) => Fp12.mul(a, b), Fp12.ONE);
const exp = Fp12.finalExponentiate(product);
return Fp12.equals(exp, Fp12.ONE);
return Fp12.eql(exp, Fp12.ONE);
}

@@ -232,4 +233,3 @@ catch {

}
// Pre-compute points. Refer to README.
G1.Point.BASE._setWindowSize(4);
G1.ProjectivePoint.BASE._setWindowSize(4);
return {

@@ -247,2 +247,3 @@ CURVE,

calcPairingPrecomputes,
hashToCurve: { G1: G1HashToCurve, G2: G2HashToCurve },
pairing,

@@ -249,0 +250,0 @@ getPublicKey,

/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
// Differences from @noble/ed25519 1.7:
// 1. Variable field element lengths between EDDSA/ECDH:
// EDDSA (RFC8032) is 456 bits / 57 bytes, ECDH (RFC7748) is 448 bits / 56 bytes
// 2. Different addition formula (doubling is same)
// 3. uvRatio differs between curves (half-expected, not only pow fn changes)
// 4. Point decompression code is different (unexpected), now using generalized formula
// 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 * as ut from './utils.js';
import { ensureBytes } from './utils.js';
import { wNAF } from './group.js';
import { hash_to_field as hashToField, validateHTFOpts } from './hash-to-curve.js';
import { mod } from './modular.js';
import { bytesToHex, bytesToNumberLE, concatBytes, ensureBytes, numberToBytesLE, } from './utils.js';
import { wNAF, validateAbsOpts, } from './curve.js';
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n

@@ -21,4 +12,4 @@ const _0n = BigInt(0);

function validateOpts(curve) {
const opts = ut.validateOpts(curve);
if (typeof opts.hash !== 'function' || !ut.isPositiveInt(opts.hash.outputLen))
const opts = validateAbsOpts(curve);
if (typeof opts.hash !== 'function')
throw new Error('Invalid hash function');

@@ -40,16 +31,11 @@ for (const i of ['a', 'd']) {

}
if (opts.htfDefaults !== undefined)
validateHTFOpts(opts.htfDefaults);
// Set defaults
return Object.freeze({ ...opts });
}
// NOTE: it is not generic twisted curve for now, but ed25519/ed448 generic implementation
// It is not generic twisted curve for now, but ed25519/ed448 generic implementation
export function twistedEdwards(curveDef) {
const CURVE = validateOpts(curveDef);
const Fp = CURVE.Fp;
const CURVE_ORDER = CURVE.n;
const maxGroupElement = _2n ** BigInt(CURVE.nByteLength * 8);
// Function overrides
const { randomBytes } = CURVE;
const modP = Fp.create;
const { Fp, n: CURVE_ORDER, preHash, hash: cHash, randomBytes, nByteLength, h: cofactor } = CURVE;
const MASK = _2n ** BigInt(nByteLength * 8);
const modP = Fp.create; // Function overrides
// sqrt(u/v)

@@ -59,3 +45,3 @@ const uvRatio = CURVE.uvRatio ||

try {
return { isValid: true, value: Fp.sqrt(u * Fp.invert(v)) };
return { isValid: true, value: Fp.sqrt(u * Fp.inv(v)) };
}

@@ -73,37 +59,66 @@ catch (e) {

}); // NOOP
/**
* Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
* Default Point works in affine coordinates: (x, y)
* https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates
*/
class ExtendedPoint {
constructor(x, y, z, t) {
this.x = x;
this.y = y;
this.z = z;
this.t = t;
const inBig = (n) => typeof n === 'bigint' && 0n < n; // n in [1..]
const inRange = (n, max) => inBig(n) && inBig(max) && n < max; // n in [1..max-1]
const in0MaskRange = (n) => n === _0n || inRange(n, MASK); // n in [0..MASK-1]
function assertInRange(n, max) {
// n in [1..max-1]
if (inRange(n, max))
return n;
throw new Error(`Expected valid scalar < ${max}, got ${typeof n} ${n}`);
}
function assertGE0(n) {
// n in [0..CURVE_ORDER-1]
return n === _0n ? n : assertInRange(n, CURVE_ORDER); // GE = prime subgroup, not full group
}
const pointPrecomputes = new Map();
function isPoint(other) {
if (!(other instanceof Point))
throw new Error('ExtendedPoint expected');
}
// Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
// https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates
class Point {
constructor(ex, ey, ez, et) {
this.ex = ex;
this.ey = ey;
this.ez = ez;
this.et = et;
if (!in0MaskRange(ex))
throw new Error('x required');
if (!in0MaskRange(ey))
throw new Error('y required');
if (!in0MaskRange(ez))
throw new Error('z required');
if (!in0MaskRange(et))
throw new Error('t required');
}
get x() {
return this.toAffine().x;
}
get y() {
return this.toAffine().y;
}
static fromAffine(p) {
if (!(p instanceof Point)) {
throw new TypeError('ExtendedPoint#fromAffine: expected Point');
}
if (p.equals(Point.ZERO))
return ExtendedPoint.ZERO;
return new ExtendedPoint(p.x, p.y, _1n, modP(p.x * p.y));
if (p instanceof Point)
throw new Error('extended point not allowed');
const { x, y } = p || {};
if (!in0MaskRange(x) || !in0MaskRange(y))
throw new Error('invalid affine point');
return new Point(x, y, _1n, modP(x * y));
}
// Takes a bunch of Jacobian Points but executes only one
// invert on all of them. invert is very slow operation,
// so this improves performance massively.
static toAffineBatch(points) {
const toInv = Fp.invertBatch(points.map((p) => p.z));
return points.map((p, i) => p.toAffine(toInv[i]));
}
static normalizeZ(points) {
return this.toAffineBatch(points).map(this.fromAffine);
const toInv = Fp.invertBatch(points.map((p) => p.ez));
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
}
// "Private method", don't use it directly
_setWindowSize(windowSize) {
this._WINDOW_SIZE = windowSize;
pointPrecomputes.delete(this);
}
assertValidity() { }
// Compare one point to another.
equals(other) {
assertExtPoint(other);
const { x: X1, y: Y1, z: Z1 } = this;
const { x: X2, y: Y2, z: Z2 } = other;
isPoint(other);
const { ex: X1, ey: Y1, ez: Z1 } = this;
const { ex: X2, ey: Y2, ez: Z2 } = other;
const X1Z2 = modP(X1 * Z2);

@@ -115,5 +130,8 @@ const X2Z1 = modP(X2 * Z1);

}
// Inverses point to one corresponding to (x, -y) in Affine coordinates.
is0() {
return this.equals(Point.ZERO);
}
negate() {
return new ExtendedPoint(modP(-this.x), this.y, this.z, modP(-this.t));
// Flips point sign to a negative one (-x, y in affine coords)
return new Point(modP(-this.ex), this.ey, this.ez, modP(-this.et));
}

@@ -125,3 +143,3 @@ // Fast algo for doubling Extended Point.

const { a } = CURVE;
const { x: X1, y: Y1, z: Z1 } = this;
const { ex: X1, ey: Y1, ez: Z1 } = this;
const A = modP(X1 * X1); // A = X12

@@ -140,3 +158,3 @@ const B = modP(Y1 * Y1); // B = Y12

const Z3 = modP(F * G); // Z3 = F*G
return new ExtendedPoint(X3, Y3, Z3, T3);
return new Point(X3, Y3, Z3, T3);
}

@@ -147,6 +165,6 @@ // Fast algo for adding 2 Extended Points.

add(other) {
assertExtPoint(other);
isPoint(other);
const { a, d } = CURVE;
const { x: X1, y: Y1, z: Z1, t: T1 } = this;
const { x: X2, y: Y2, z: Z2, t: T2 } = other;
const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
const { ex: X2, ey: Y2, ez: Z2, et: T2 } = other;
// Faster algo for adding 2 Extended Points when curve's a=-1.

@@ -171,3 +189,3 @@ // http://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-4

const Z3 = modP(F * G);
return new ExtendedPoint(X3, Y3, Z3, T3);
return new Point(X3, Y3, Z3, T3);
}

@@ -186,3 +204,3 @@ const A = modP(X1 * X2); // A = X1*X2

const Z3 = modP(F * G); // Z3 = F*G
return new ExtendedPoint(X3, Y3, Z3, T3);
return new Point(X3, Y3, Z3, T3);
}

@@ -192,22 +210,9 @@ subtract(other) {

}
wNAF(n, affinePoint) {
if (!affinePoint && this.equals(ExtendedPoint.BASE))
affinePoint = Point.BASE;
const W = (affinePoint && affinePoint._WINDOW_SIZE) || 1;
let precomputes = affinePoint && pointPrecomputes.get(affinePoint);
if (!precomputes) {
precomputes = wnaf.precomputeWindow(this, W);
if (affinePoint && W !== 1) {
precomputes = ExtendedPoint.normalizeZ(precomputes);
pointPrecomputes.set(affinePoint, precomputes);
}
}
const { p, f } = wnaf.wNAF(W, precomputes, n);
return ExtendedPoint.normalizeZ([p, f])[0];
wNAF(n) {
return wnaf.wNAFCached(this, pointPrecomputes, n, Point.normalizeZ);
}
// Constant time multiplication.
// Uses wNAF method. Windowed method may be 10% faster,
// but takes 2x longer to generate and consumes 2x memory.
multiply(scalar, affinePoint) {
return this.wNAF(normalizeScalar(scalar, CURVE_ORDER), affinePoint);
// Constant-time multiplication.
multiply(scalar) {
const { p, f } = this.wNAF(assertInRange(scalar, CURVE_ORDER));
return Point.normalizeZ([p, f])[0];
}

@@ -218,10 +223,9 @@ // Non-constant-time multiplication. Uses double-and-add algorithm.

multiplyUnsafe(scalar) {
let n = normalizeScalar(scalar, CURVE_ORDER, false);
const P0 = ExtendedPoint.ZERO;
let n = assertGE0(scalar);
if (n === _0n)
return P0;
if (this.equals(P0) || n === _1n)
return I;
if (this.equals(I) || n === _1n)
return this;
if (this.equals(ExtendedPoint.BASE))
return this.wNAF(n);
if (this.equals(G))
return this.wNAF(n).p;
return wnaf.unsafeLadder(this, n);

@@ -234,24 +238,24 @@ }

isSmallOrder() {
return this.multiplyUnsafe(CURVE.h).equals(ExtendedPoint.ZERO);
return this.multiplyUnsafe(cofactor).is0();
}
// Multiplies point by curve order (very big scalar CURVE.n) and checks if the result is 0.
// Multiplies point by curve order and checks if the result is 0.
// Returns `false` is the point is dirty.
isTorsionFree() {
return wnaf.unsafeLadder(this, CURVE_ORDER).equals(ExtendedPoint.ZERO);
return wnaf.unsafeLadder(this, CURVE_ORDER).is0();
}
// Converts Extended point to default (x, y) coordinates.
// Can accept precomputed Z^-1 - for example, from invertBatch.
toAffine(invZ) {
const { x, y, z } = this;
const is0 = this.equals(ExtendedPoint.ZERO);
if (invZ == null)
invZ = is0 ? _8n : Fp.invert(z); // 8 was chosen arbitrarily
const ax = modP(x * invZ);
const ay = modP(y * invZ);
const zz = modP(z * invZ);
toAffine(iz) {
const { ex: x, ey: y, ez: z } = this;
const is0 = this.is0();
if (iz == null)
iz = is0 ? _8n : Fp.inv(z); // 8 was chosen arbitrarily
const ax = modP(x * iz);
const ay = modP(y * iz);
const zz = modP(z * iz);
if (is0)
return Point.ZERO;
return { x: _0n, y: _1n };
if (zz !== _1n)
throw new Error('invZ was invalid');
return new Point(ax, ay);
return { x: ax, y: ay };
}

@@ -264,25 +268,2 @@ clearCofactor() {

}
}
ExtendedPoint.BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
ExtendedPoint.ZERO = new ExtendedPoint(_0n, _1n, _1n, _0n);
const wnaf = wNAF(ExtendedPoint, CURVE.nByteLength * 8);
function assertExtPoint(other) {
if (!(other instanceof ExtendedPoint))
throw new TypeError('ExtendedPoint expected');
}
// Stores precomputed values for points.
const pointPrecomputes = new WeakMap();
/**
* Default Point works in affine coordinates: (x, y)
*/
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
// "Private method", don't use it directly.
_setWindowSize(windowSize) {
this._WINDOW_SIZE = windowSize;
pointPrecomputes.delete(this);
}
// Converts hash string or Uint8Array to Point.

@@ -293,274 +274,118 @@ // Uses algo from RFC8032 5.1.3.

const len = Fp.BYTES;
hex = ensureBytes(hex, len);
// 1. First, interpret the string as an integer in little-endian
// representation. Bit 255 of this number is the least significant
// bit of the x-coordinate and denote this value x_0. The
// y-coordinate is recovered simply by clearing this bit. If the
// resulting value is >= p, decoding fails.
const normed = hex.slice();
const lastByte = hex[len - 1];
normed[len - 1] = lastByte & ~0x80;
const y = ut.bytesToNumberLE(normed);
if (strict && y >= Fp.ORDER)
throw new Error('Expected 0 < hex < P');
if (!strict && y >= maxGroupElement)
throw new Error('Expected 0 < hex < CURVE.n');
// 2. To recover the x-coordinate, the curve equation implies
// Ed25519: x² = (y² - 1) / (d y² + 1) (mod p).
// Ed448: x² = (y² - 1) / (d y² - 1) (mod p).
// For generic case:
// a*x²+y²=1+d*x²*y²
// -> y²-1 = d*x²*y²-a*x²
// -> y²-1 = x² (d*y²-a)
// -> x² = (y²-1) / (d*y²-a)
// The denominator is always non-zero mod p. Let u = y² - 1 and v = d y² + 1.
const y2 = modP(y * y);
const u = modP(y2 - _1n);
const v = modP(d * y2 - a);
let { isValid, value: x } = uvRatio(u, v);
hex = ensureBytes(hex, len); // copy hex to a new array
const normed = hex.slice(); // copy again, we'll manipulate it
const lastByte = hex[len - 1]; // select last byte
normed[len - 1] = lastByte & ~0x80; // clear last bit
const y = bytesToNumberLE(normed);
if (y === _0n) {
// y=0 is allowed
}
else {
// RFC8032 prohibits >= p, but ZIP215 doesn't
if (strict)
assertInRange(y, Fp.ORDER); // strict=true [1..P-1] (2^255-19-1 for ed25519)
else
assertInRange(y, MASK); // strict=false [1..MASK-1] (2^256-1 for ed25519)
}
// Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:
// ax²+y²=1+dx²y² => y²-1=dx²y²-ax² => y²-1=x²(dy²-a) => x²=(y²-1)/(dy²-a)
const y2 = modP(y * y); // denominator is always non-0 mod p.
const u = modP(y2 - _1n); // u = y² - 1
const v = modP(d * y2 - a); // v = d y² + 1.
let { isValid, value: x } = uvRatio(u, v); // √(u/v)
if (!isValid)
throw new Error('Point.fromHex: invalid y coordinate');
// 4. Finally, use the x_0 bit to select the right square root. If
// x = 0, and x_0 = 1, decoding fails. Otherwise, if x_0 != x mod
// 2, set x <-- p - x. Return the decoded point (x,y).
const isXOdd = (x & _1n) === _1n;
const isLastByteOdd = (lastByte & 0x80) !== 0;
const isXOdd = (x & _1n) === _1n; // There are 2 square roots. Use x_0 bit to select proper
const isLastByteOdd = (lastByte & 0x80) !== 0; // if x=0 and x_0 = 1, fail
if (isLastByteOdd !== isXOdd)
x = modP(-x);
return new Point(x, y);
x = modP(-x); // if x_0 != x mod 2, set x = p-x
return Point.fromAffine({ x, y });
}
static fromPrivateKey(privateKey) {
return getExtendedPublicKey(privateKey).point;
static fromPrivateKey(privKey) {
return getExtendedPublicKey(privKey).point;
}
// There can always be only two x values (x, -x) for any y
// When compressing point, it's enough to only store its y coordinate
// and use the last byte to encode sign of x.
toRawBytes() {
const bytes = ut.numberToBytesLE(this.y, Fp.BYTES);
bytes[Fp.BYTES - 1] |= this.x & _1n ? 0x80 : 0;
return bytes;
const { x, y } = this.toAffine();
const bytes = numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y
return bytes; // and use the last byte to encode sign of x
}
// Same as toRawBytes, but returns string.
toHex() {
return ut.bytesToHex(this.toRawBytes());
return bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string.
}
// Determines if point is in prime-order subgroup.
// Returns `false` is the point is dirty.
isTorsionFree() {
return ExtendedPoint.fromAffine(this).isTorsionFree();
}
equals(other) {
if (!(other instanceof Point))
throw new TypeError('Point#equals: expected Point');
return this.x === other.x && this.y === other.y;
}
negate() {
return new Point(modP(-this.x), this.y);
}
double() {
return ExtendedPoint.fromAffine(this).double().toAffine();
}
add(other) {
return ExtendedPoint.fromAffine(this).add(ExtendedPoint.fromAffine(other)).toAffine();
}
subtract(other) {
return this.add(other.negate());
}
/**
* Constant time multiplication.
* @param scalar Big-Endian number
* @returns new point
*/
multiply(scalar) {
return ExtendedPoint.fromAffine(this).multiply(scalar, this).toAffine();
}
clearCofactor() {
return ExtendedPoint.fromAffine(this).clearCofactor().toAffine();
}
// 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) {
const { mapToCurve, htfDefaults } = CURVE;
if (!mapToCurve)
throw new Error('No mapToCurve defined for curve');
const u = hashToField(ensureBytes(msg), 2, { ...htfDefaults, ...options });
const { x: x0, y: y0 } = mapToCurve(u[0]);
const { x: x1, y: y1 } = 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) {
const { mapToCurve, htfDefaults } = CURVE;
if (!mapToCurve)
throw new Error('No mapToCurve defined for curve');
const u = hashToField(ensureBytes(msg), 1, { ...htfDefaults, ...options });
const { x, y } = mapToCurve(u[0]);
return new Point(x, y).clearCofactor();
}
}
// Base point aka generator
// public_key = Point.BASE * private_key
Point.BASE = new Point(CURVE.Gx, CURVE.Gy);
// Identity point aka point at infinity
// point = point + zero_point
Point.ZERO = new Point(_0n, _1n);
/**
* EDDSA signature.
*/
class Signature {
constructor(r, s) {
this.r = r;
this.s = s;
this.assertValidity();
}
static fromHex(hex) {
const len = Fp.BYTES;
const bytes = ensureBytes(hex, 2 * len);
const r = Point.fromHex(bytes.slice(0, len), false);
const s = ut.bytesToNumberLE(bytes.slice(len, 2 * len));
return new Signature(r, s);
}
assertValidity() {
const { r, s } = this;
if (!(r instanceof Point))
throw new Error('Expected Point instance');
// 0 <= s < l
normalizeScalar(s, CURVE_ORDER, false);
return this;
}
toRawBytes() {
return ut.concatBytes(this.r.toRawBytes(), ut.numberToBytesLE(this.s, Fp.BYTES));
}
toHex() {
return ut.bytesToHex(this.toRawBytes());
}
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
Point.ZERO = new Point(_0n, _1n, _1n, _0n); // 0, 1, 1, 0
const { BASE: G, ZERO: I } = Point;
const wnaf = wNAF(Point, nByteLength * 8);
function modN(a) {
return mod(a, CURVE_ORDER);
}
// Little-endian SHA512 with modulo n
function modnLE(hash) {
return mod.mod(ut.bytesToNumberLE(hash), CURVE_ORDER);
function modN_LE(hash) {
return modN(bytesToNumberLE(hash));
}
/**
* Checks for num to be in range:
* For strict == true: `0 < num < max`.
* For strict == false: `0 <= num < max`.
* Converts non-float safe numbers to bigints.
*/
function normalizeScalar(num, max, strict = true) {
if (!max)
throw new TypeError('Specify max value');
if (ut.isPositiveInt(num))
num = BigInt(num);
if (typeof num === 'bigint' && num < max) {
if (strict) {
if (_0n < num)
return num;
}
else {
if (_0n <= num)
return num;
}
}
throw new TypeError(`Expected valid scalar: 0 < scalar < ${max}`);
function isHex(item, err) {
if (typeof item !== 'string' && !(item instanceof Uint8Array))
throw new Error(`${err} must be hex string or Uint8Array`);
}
/** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */
function getExtendedPublicKey(key) {
const groupLen = CURVE.nByteLength;
// Normalize bigint / number / string to Uint8Array
const keyb = typeof key === 'bigint' || typeof key === 'number'
? ut.numberToBytesLE(normalizeScalar(key, maxGroupElement), groupLen)
: key;
isHex(key, 'private key');
const len = nByteLength;
// Hash private key with curve's hash function to produce uniformingly random input
// We check byte lengths e.g.: ensureBytes(64, hash(ensureBytes(32, key)))
const hashed = ensureBytes(CURVE.hash(ensureBytes(keyb, groupLen)), 2 * groupLen);
// First half's bits are cleared to produce a random field element.
const head = adjustScalarBytes(hashed.slice(0, groupLen));
// Second half is called key prefix (5.1.6)
const prefix = hashed.slice(groupLen, 2 * groupLen);
// The actual private scalar
const scalar = modnLE(head);
// Point on Edwards curve aka public key
const point = Point.BASE.multiply(scalar);
// Uint8Array representation
const pointBytes = point.toRawBytes();
// Check byte lengths: ensure(64, h(ensure(32, key)))
const hashed = ensureBytes(cHash(ensureBytes(key, len)), 2 * len);
const head = adjustScalarBytes(hashed.slice(0, len)); // clear first half bits, produce FE
const prefix = hashed.slice(len, 2 * len); // second half is called key prefix (5.1.6)
const scalar = modN_LE(head); // The actual private scalar
const point = G.multiply(scalar); // Point on Edwards curve aka public key
const pointBytes = point.toRawBytes(); // Uint8Array representation
return { head, prefix, scalar, point, pointBytes };
}
/**
* Calculates ed25519 public key. RFC8032 5.1.5
* 1. private key is hashed with sha512, then first 32 bytes are taken from the hash
* 2. 3 least significant bits of the first byte are cleared
*/
function getPublicKey(privateKey) {
return getExtendedPublicKey(privateKey).pointBytes;
// Calculates EdDSA pub key. RFC8032 5.1.5. Privkey is hashed. Use first half with 3 bits cleared
function getPublicKey(privKey) {
return getExtendedPublicKey(privKey).pointBytes;
}
const EMPTY = new Uint8Array();
function hashDomainToScalar(message, context = EMPTY) {
context = ensureBytes(context);
return modnLE(CURVE.hash(domain(message, context, !!CURVE.preHash)));
// int('LE', SHA512(dom2(F, C) || msgs)) mod N
function hashDomainToScalar(context = new Uint8Array(), ...msgs) {
const msg = concatBytes(...msgs);
return modN_LE(cHash(domain(msg, ensureBytes(context), !!preHash)));
}
/** Signs message with privateKey. RFC8032 5.1.6 */
function sign(message, privateKey, context) {
message = ensureBytes(message);
if (CURVE.preHash)
message = CURVE.preHash(message);
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privateKey);
const r = hashDomainToScalar(ut.concatBytes(prefix, message), context);
const R = Point.BASE.multiply(r); // R = rG
const k = hashDomainToScalar(ut.concatBytes(R.toRawBytes(), pointBytes, message), context); // k = hash(R+P+msg)
const s = mod.mod(r + k * scalar, CURVE_ORDER); // s = r + kp
return new Signature(R, s).toRawBytes();
function sign(msg, privKey, context) {
isHex(msg, 'message');
msg = ensureBytes(msg);
if (preHash)
msg = preHash(msg); // for ed25519ph etc.
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
const r = hashDomainToScalar(context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
const R = G.multiply(r).toRawBytes(); // R = rG
const k = hashDomainToScalar(context, R, pointBytes, msg); // R || A || PH(M)
const s = modN(r + k * scalar); // S = (r + k * s) mod L
assertGE0(s); // 0 <= s < l
const res = concatBytes(R, numberToBytesLE(s, Fp.BYTES));
return ensureBytes(res, nByteLength * 2); // 64-byte signature
}
/**
* Verifies EdDSA signature against message and public key.
* An extended group equation is checked.
* RFC8032 5.1.7
* Compliant with ZIP215:
* 0 <= sig.R/publicKey < 2**256 (can be >= curve.P)
* 0 <= sig.s < l
* Not compliant with RFC8032: it's not possible to comply to both ZIP & RFC at the same time.
*/
function verify(sig, message, publicKey, context) {
message = ensureBytes(message);
if (CURVE.preHash)
message = CURVE.preHash(message);
// When hex is passed, we check public key fully.
// When Point instance is passed, we assume it has already been checked, for performance.
// If user passes Point/Sig instance, we assume it has been already verified.
// We don't check its equations for performance. We do check for valid bounds for s though
// We always check for: a) s bounds. b) hex validity
if (publicKey instanceof Point) {
// ignore
}
else if (publicKey instanceof Uint8Array || typeof publicKey === 'string') {
publicKey = Point.fromHex(publicKey, false);
}
else {
throw new Error(`Invalid publicKey: ${publicKey}`);
}
if (sig instanceof Signature)
sig.assertValidity();
else if (sig instanceof Uint8Array || typeof sig === 'string')
sig = Signature.fromHex(sig);
else
throw new Error(`Wrong signature: ${sig}`);
const { r, s } = sig;
const SB = ExtendedPoint.BASE.multiplyUnsafe(s);
const k = hashDomainToScalar(ut.concatBytes(r.toRawBytes(), publicKey.toRawBytes(), message), context);
const kA = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(k);
const RkA = ExtendedPoint.fromAffine(r).add(kA);
function verify(sig, msg, publicKey, context) {
isHex(sig, 'sig');
isHex(msg, 'message');
const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
sig = ensureBytes(sig, 2 * len); // An extended group equation is checked.
msg = ensureBytes(msg); // ZIP215 compliant, which means not fully RFC8032 compliant.
if (preHash)
msg = preHash(msg); // for ed25519ph, etc
const A = Point.fromHex(publicKey, false); // Check for s bounds, hex validity
const R = Point.fromHex(sig.slice(0, len), false); // 0 <= R < 2^256: ZIP215 R can be >= P
const s = bytesToNumberLE(sig.slice(len, 2 * len)); // 0 <= s < l
const SB = G.multiplyUnsafe(s);
const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
const RkA = R.add(A.multiplyUnsafe(k));
// [8][S]B = [8]R + [8][k]A'
return RkA.subtract(SB).clearCofactor().equals(ExtendedPoint.ZERO);
return RkA.subtract(SB).clearCofactor().equals(Point.ZERO);
}
// Enable precomputes. Slows down first publicKey computation by 20ms.
Point.BASE._setWindowSize(8);
G._setWindowSize(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
const utils = {
getExtendedPublicKey,
/**
* Not needed for ed25519 private keys. Needed if you use scalars directly (rare).
*/
hashToPrivateScalar: (hash) => ut.hashToPrivateScalar(hash, CURVE_ORDER, true),
/**
* ed25519 private keys are uniform 32-bit strings. We do not need to check for
* modulo bias like we do in secp256k1 randomPrivateKey()
*/
// ed25519 private keys are uniform 32b. No need to check for modulo bias, like in secp256k1.
randomPrivateKey: () => randomBytes(Fp.BYTES),

@@ -574,6 +399,5 @@ /**

precompute(windowSize = 8, point = Point.BASE) {
const cached = point.equals(Point.BASE) ? point : new Point(point.x, point.y);
cached._setWindowSize(windowSize);
cached.multiply(_2n);
return cached;
point._setWindowSize(windowSize);
point.multiply(BigInt(3));
return point;
},

@@ -586,7 +410,5 @@ };

verify,
ExtendedPoint,
Point,
Signature,
ExtendedPoint: Point,
utils,
};
}

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

/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import { concatBytes } from './utils.js';
import * as mod from './modular.js';
export function validateHTFOpts(opts) {
import { mod } from './modular.js';
import { concatBytes, ensureBytes } from './utils.js';
export function validateOpts(opts) {
if (typeof opts.DST !== 'string')

@@ -18,9 +17,7 @@ throw new Error('Invalid htf/DST');

}
// UTF8 to ui8a
// TODO: looks broken, ASCII only, why not TextEncoder/TextDecoder? it is in hashes anyway
export function stringToBytes(str) {
const bytes = new Uint8Array(str.length);
for (let i = 0; i < str.length; i++)
bytes[i] = str.charCodeAt(i);
return bytes;
if (typeof str !== 'string') {
throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`);
}
return new TextEncoder().encode(str);
}

@@ -124,3 +121,3 @@ // Octet Stream to Integer (bytesToNumberBE)

const tv = pseudo_random_bytes.subarray(elm_offset, elm_offset + L);
e[j] = mod.mod(os2ip(tv), options.p);
e[j] = mod(os2ip(tv), options.p);
}

@@ -141,1 +138,31 @@ u[i] = e;

}
export function hashToCurve(Point, mapToCurve, def) {
validateOpts(def);
if (typeof mapToCurve !== 'function')
throw new Error('hashToCurve: mapToCurve() has not been defined');
return {
// Encodes byte string to elliptic curve
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
hashToCurve(msg, options) {
if (!mapToCurve)
throw new Error('CURVE.mapToCurve() has not been defined');
msg = ensureBytes(msg);
const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options });
const P = Point.fromAffine(mapToCurve(u[0]))
.add(Point.fromAffine(mapToCurve(u[1])))
.clearCofactor();
P.assertValidity();
return P;
},
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
encodeToCurve(msg, options) {
if (!mapToCurve)
throw new Error('CURVE.mapToCurve() has not been defined');
msg = ensureBytes(msg);
const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options });
const P = Point.fromAffine(mapToCurve(u[0])).clearCofactor();
P.assertValidity();
return P;
},
};
}
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// TODO: remove circular imports
import * as utils from './utils.js';
// Utilities for modular arithmetics and finite fields
import { bitMask, numberToBytesBE, numberToBytesLE, bytesToNumberBE, bytesToNumberLE, ensureBytes, } from './utils.js';
// prettier-ignore

@@ -94,3 +93,3 @@ const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);

const root = Fp.pow(n, p1div4);
if (!Fp.equals(Fp.square(root), n))
if (!Fp.eql(Fp.sqr(root), n))
throw new Error('Cannot find square root');

@@ -104,3 +103,3 @@ return root;

// Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
if (Fp.pow(n, legendreC) === Fp.negate(Fp.ONE))
if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE))
throw new Error('Cannot find square root');

@@ -112,15 +111,15 @@ let r = S;

let b = Fp.pow(n, Q); // first guess at the fudge factor
while (!Fp.equals(b, Fp.ONE)) {
if (Fp.equals(b, Fp.ZERO))
while (!Fp.eql(b, Fp.ONE)) {
if (Fp.eql(b, Fp.ZERO))
return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)
// Find m such b^(2^m)==1
let m = 1;
for (let t2 = Fp.square(b); m < r; m++) {
if (Fp.equals(t2, Fp.ONE))
for (let t2 = Fp.sqr(b); m < r; m++) {
if (Fp.eql(t2, Fp.ONE))
break;
t2 = Fp.square(t2); // t2 *= t2
t2 = Fp.sqr(t2); // t2 *= t2
}
// NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow
const ge = Fp.pow(g, _1n << BigInt(r - m - 1)); // ge = 2^(r-m-1)
g = Fp.square(ge); // g = ge * ge
g = Fp.sqr(ge); // g = ge * ge
x = Fp.mul(x, ge); // x *= ge

@@ -147,3 +146,3 @@ b = Fp.mul(b, g); // b *= g

// Throw if root**2 != n
if (!Fp.equals(Fp.square(root), n))
if (!Fp.eql(Fp.sqr(root), n))
throw new Error('Cannot find square root');

@@ -162,3 +161,3 @@ return root;

const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
if (!Fp.equals(Fp.square(root), n))
if (!Fp.eql(Fp.sqr(root), n))
throw new Error('Cannot find square root');

@@ -197,5 +196,5 @@ return root;

const FIELD_FIELDS = [
'create', 'isValid', 'isZero', 'negate', 'invert', 'sqrt', 'square',
'equals', 'add', 'sub', 'mul', 'pow', 'div',
'addN', 'subN', 'mulN', 'squareN'
'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
'eql', 'add', 'sub', 'mul', 'pow', 'div',
'addN', 'subN', 'mulN', 'sqrN'
];

@@ -231,3 +230,3 @@ export function validateField(field) {

p = f.mul(p, d);
d = f.square(d);
d = f.sqr(d);
power >>= 1n;

@@ -241,3 +240,3 @@ }

const lastMultiplied = nums.reduce((acc, num, i) => {
if (f.isZero(num))
if (f.is0(num))
return acc;

@@ -248,6 +247,6 @@ tmp[i] = acc;

// Invert last element
const inverted = f.invert(lastMultiplied);
const inverted = f.inv(lastMultiplied);
// Walk from last to first, multiply them by inverted each other MOD p
nums.reduceRight((acc, num, i) => {
if (f.isZero(num))
if (f.is0(num))
return acc;

@@ -260,3 +259,3 @@ tmp[i] = f.mul(acc, tmp[i]);

export function FpDiv(f, lhs, rhs) {
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.invert(rhs));
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
}

@@ -268,9 +267,16 @@ // This function returns True whenever the value x is a square in the field F.

const p = f.pow(x, legendreConst);
return f.equals(p, f.ZERO) || f.equals(p, f.ONE);
return f.eql(p, f.ZERO) || f.eql(p, f.ONE);
};
}
// CURVE.n lengths
export function nLength(n, nBitLength) {
// Bit size, byte size of CURVE.n
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
const nByteLength = Math.ceil(_nBitLength / 8);
return { nBitLength: _nBitLength, nByteLength };
}
export 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);
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
if (BYTES > 2048)

@@ -283,3 +289,3 @@ throw new Error('Field lengths over 2048 bytes are not supported');

BYTES,
MASK: utils.bitMask(BITS),
MASK: bitMask(BITS),
ZERO: _0n,

@@ -291,9 +297,9 @@ ONE: _1n,

throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
return _0n <= num && num < ORDER;
return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
},
isZero: (num) => num === _0n,
is0: (num) => num === _0n,
isOdd: (num) => (num & _1n) === _1n,
negate: (num) => mod(-num, ORDER),
equals: (lhs, rhs) => lhs === rhs,
square: (num) => mod(num * num, ORDER),
neg: (num) => mod(-num, ORDER),
eql: (lhs, rhs) => lhs === rhs,
sqr: (num) => mod(num * num, ORDER),
add: (lhs, rhs) => mod(lhs + rhs, ORDER),

@@ -305,7 +311,7 @@ sub: (lhs, rhs) => mod(lhs - rhs, ORDER),

// Same as above, but doesn't normalize
squareN: (num) => num * num,
sqrN: (num) => num * num,
addN: (lhs, rhs) => lhs + rhs,
subN: (lhs, rhs) => lhs - rhs,
mulN: (lhs, rhs) => lhs * rhs,
invert: (num) => invert(num, ORDER),
inv: (num) => invert(num, ORDER),
sqrt: redef.sqrt || ((n) => sqrtP(f, n)),

@@ -316,7 +322,7 @@ invertBatch: (lst) => FpInvertBatch(f, lst),

cmov: (a, b, c) => (c ? b : a),
toBytes: (num) => isLE ? utils.numberToBytesLE(num, BYTES) : utils.numberToBytesBE(num, BYTES),
toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : 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 isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
},

@@ -330,3 +336,3 @@ });

const root = Fp.sqrt(elm);
return Fp.isOdd(root) ? root : Fp.negate(root);
return Fp.isOdd(root) ? root : Fp.neg(root);
}

@@ -337,3 +343,21 @@ export function FpSqrtEven(Fp, elm) {

const root = Fp.sqrt(elm);
return Fp.isOdd(root) ? Fp.negate(root) : root;
return Fp.isOdd(root) ? Fp.neg(root) : root;
}
/**
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
* 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.
* Needs at least 40 bytes of input for 32-byte private key.
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
* @param hash hash output from SHA3 or a similar function
* @returns valid private scalar
*/
export function hashToPrivateScalar(hash, groupOrder, isLE = false) {
hash = ensureBytes(hash);
const hashLen = hash.length;
const minLen = nLength(groupOrder).nByteLength + 8;
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`);
const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
return mod(num, groupOrder - _1n) + _1n;
}
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import * as mod from './modular.js';
import { ensureBytes, numberToBytesLE, bytesToNumberLE, isPositiveInt } from './utils.js';
import { mod, pow } from './modular.js';
import { ensureBytes, numberToBytesLE, bytesToNumberLE } from './utils.js';
const _0n = BigInt(0);

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

continue; // Optional
if (!isPositiveInt(curve[i]))
if (!Number.isSafeInteger(curve[i]))
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);

@@ -31,3 +31,2 @@ }

// Set defaults
// ...nLength(curve.n, curve.nBitLength),
return Object.freeze({ ...curve });

@@ -40,3 +39,3 @@ }

const { P } = CURVE;
const modP = (a) => mod.mod(a, P);
const modP = (a) => mod(a, P);
const montgomeryBits = CURVE.montgomeryBits;

@@ -46,3 +45,3 @@ const montgomeryBytes = Math.ceil(montgomeryBits / 8);

const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes) => bytes);
const powPminus2 = CURVE.powPminus2 || ((x) => mod.pow(x, P - BigInt(2), P));
const powPminus2 = CURVE.powPminus2 || ((x) => pow(x, P - BigInt(2), P));
/**

@@ -49,0 +48,0 @@ * Checks for num to be in range:

/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import * as mod from './modular.js';
const _0n = BigInt(0);
const _1n = BigInt(1);
const _2n = BigInt(2);
// Bans floats and integers above 2^53-1
export function isPositiveInt(num) {
return typeof num === 'number' && Number.isSafeInteger(num) && num > 0;
}
export function validateOpts(curve) {
mod.validateField(curve.Fp);
for (const i of ['n', 'h']) {
const val = curve[i];
if (typeof val !== 'bigint')
throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
}
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']) {
const val = curve[i];
if (val === undefined)
continue; // Optional
if (!isPositiveInt(val))
throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
}
// Set defaults
return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve });
}
const u8a = (a) => a instanceof Uint8Array;
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
export function bytesToHex(uint8a) {
if (!(uint8a instanceof Uint8Array))
export function bytesToHex(bytes) {
if (!u8a(bytes))
throw new Error('Expected Uint8Array');
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < uint8a.length; i++) {
hex += hexes[uint8a[i]];
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
}

@@ -47,5 +22,4 @@ return hex;

export function hexToNumber(hex) {
if (typeof hex !== 'string') {
throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
}
if (typeof hex !== 'string')
throw new Error('hexToNumber: expected string, got ' + typeof hex);
// Big Endian

@@ -56,5 +30,4 @@ return BigInt(`0x${hex}`);

export function hexToBytes(hex) {
if (typeof hex !== 'string') {
throw new TypeError('hexToBytes: expected string, got ' + typeof hex);
}
if (typeof hex !== 'string')
throw new Error('hexToBytes: expected string, got ' + typeof hex);
if (hex.length % 2)

@@ -77,13 +50,20 @@ throw new Error('hexToBytes: received invalid unpadded hex ' + hex.length);

}
export function bytesToNumberLE(uint8a) {
if (!(uint8a instanceof Uint8Array))
export function bytesToNumberLE(bytes) {
if (!u8a(bytes))
throw new Error('Expected Uint8Array');
return BigInt('0x' + bytesToHex(Uint8Array.from(uint8a).reverse()));
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
}
export const numberToBytesBE = (n, len) => hexToBytes(n.toString(16).padStart(len * 2, '0'));
export const numberToBytesLE = (n, len) => numberToBytesBE(n, len).reverse();
// Returns variable number bytes (minimal bigint encoding?)
export const numberToVarBytesBE = (n) => {
let hex = n.toString(16);
if (hex.length & 1)
hex = '0' + hex;
return hexToBytes(hex);
};
export function ensureBytes(hex, expectedLength) {
// Uint8Array.from() instead of hash.slice() because node.js Buffer
// is instance of Uint8Array, and its slice() creates **mutable** copy
const bytes = hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex);
const bytes = u8a(hex) ? Uint8Array.from(hex) : hexToBytes(hex);
if (typeof expectedLength === 'number' && bytes.length !== expectedLength)

@@ -95,3 +75,3 @@ throw new Error(`Expected ${expectedLength} bytes`);

export function concatBytes(...arrays) {
if (!arrays.every((b) => b instanceof Uint8Array))
if (!arrays.every((b) => u8a(b)))
throw new Error('Uint8Array list expected');

@@ -109,27 +89,2 @@ if (arrays.length === 1)

}
// CURVE.n lengths
export function nLength(n, nBitLength) {
// Bit size, byte size of CURVE.n
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
const nByteLength = Math.ceil(_nBitLength / 8);
return { nBitLength: _nBitLength, nByteLength };
}
/**
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
* 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.
* Needs at least 40 bytes of input for 32-byte private key.
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
* @param hash hash output from SHA3 or a similar function
* @returns valid private scalar
*/
export function hashToPrivateScalar(hash, groupOrder, isLE = false) {
hash = ensureBytes(hash);
const hashLen = hash.length;
const minLen = nLength(groupOrder).nByteLength + 8;
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`);
const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
return mod.mod(num, groupOrder - _1n) + _1n;
}
export function equalBytes(b1, b2) {

@@ -136,0 +91,0 @@ // We don't care about timing attacks here

/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// Short Weierstrass curve. The formula is: y² = x³ + ax + b
// Differences from @noble/secp256k1 1.7:
// 1. Different double() formula (but same addition)
// 2. Different sqrt() function
// 3. truncateHash() truncateOnly mode
// 4. DRBG supports outputLen bigger than outputLen of hmac
// 5. Support for different hash functions
import * as mod from './modular.js';
import * as ut from './utils.js';
import { bytesToHex } from './utils.js';
import { hash_to_field, validateHTFOpts } from './hash-to-curve.js';
import { wNAF } from './group.js';
// ASN.1 DER encoding utilities
class DERError extends Error {
constructor(message) {
super(message);
}
}
const DER = {
slice(s) {
// Proof: any([(i>=0x80) == (int(hex(i).replace('0x', '').zfill(2)[0], 16)>=8) for i in range(0, 256)])
// Padding done by numberToHex
return Number.parseInt(s[0], 16) >= 8 ? '00' + s : s;
},
parseInt(data) {
if (data.length < 2 || data[0] !== 0x02) {
throw new DERError(`Invalid signature integer tag: ${bytesToHex(data)}`);
}
const len = data[1];
const res = data.subarray(2, len + 2);
if (!len || res.length !== len) {
throw new DERError(`Invalid signature integer: wrong length`);
}
// Strange condition, its not about length, but about first bytes of number.
if (res[0] === 0x00 && res[1] <= 0x7f) {
throw new DERError('Invalid signature integer: trailing length');
}
return { data: ut.bytesToNumberBE(res), left: data.subarray(len + 2) };
},
parseSig(data) {
if (data.length < 2 || data[0] != 0x30) {
throw new DERError(`Invalid signature tag: ${bytesToHex(data)}`);
}
if (data[1] !== data.length - 2) {
throw new DERError('Invalid signature: incorrect length');
}
const { data: r, left: sBytes } = DER.parseInt(data.subarray(2));
const { data: s, left: rBytesLeft } = DER.parseInt(sBytes);
if (rBytesLeft.length) {
throw new DERError(`Invalid signature: left bytes after parsing: ${bytesToHex(rBytesLeft)}`);
}
return { r, s };
},
};
import { ensureBytes } from './utils.js';
import { wNAF, validateAbsOpts, } from './curve.js';
function validatePointOpts(curve) {
const opts = ut.validateOpts(curve);
const opts = validateAbsOpts(curve);
const Fp = opts.Fp;

@@ -63,3 +14,3 @@ for (const i of ['a', 'b']) {

}
for (const i of ['isTorsionFree', 'clearCofactor', 'mapToCurve']) {
for (const i of ['isTorsionFree', 'clearCofactor']) {
if (curve[i] === undefined)

@@ -72,3 +23,3 @@ continue; // Optional

if (endo) {
if (!Fp.equals(opts.a, Fp.ZERO)) {
if (!Fp.eql(opts.a, Fp.ZERO)) {
throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');

@@ -86,12 +37,62 @@ }

throw new Error('Invalid fromBytes function');
// Requires including hashToCurve file
if (opts.htfDefaults !== undefined)
validateHTFOpts(opts.htfDefaults);
// Set defaults
return Object.freeze({ ...opts });
}
// ASN.1 DER encoding utilities
const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
const DER = {
// asn.1 DER encoding utils
Err: class DERErr extends Error {
constructor(m = '') {
super(m);
}
},
_parseInt(data) {
const { Err: E } = DER;
if (data.length < 2 || data[0] !== 0x02)
throw new E('Invalid signature integer tag');
const len = data[1];
const res = data.subarray(2, len + 2);
if (!len || res.length !== len)
throw new E('Invalid signature integer: wrong length');
if (res[0] === 0x00 && res[1] <= 0x7f)
throw new E('Invalid signature integer: trailing length');
// ^ Weird condition: not about length, but about first bytes of number.
return { d: b2n(res), l: data.subarray(len + 2) }; // d is data, l is left
},
toSig(hex) {
// parse DER signature
const { Err: E } = DER;
const data = typeof hex === 'string' ? h2b(hex) : hex;
if (!(data instanceof Uint8Array))
throw new Error('ui8a expected');
let l = data.length;
if (l < 2 || data[0] != 0x30)
throw new E('Invalid signature tag');
if (data[1] !== l - 2)
throw new E('Invalid signature: incorrect length');
const { d: r, l: sBytes } = DER._parseInt(data.subarray(2));
const { d: s, l: rBytesLeft } = DER._parseInt(sBytes);
if (rBytesLeft.length)
throw new E('Invalid signature: left bytes after parsing');
return { r, s };
},
hexFromSig(sig) {
const slice = (s) => (Number.parseInt(s[0], 16) >= 8 ? '00' + s : s); // slice DER
const h = (num) => {
const hex = num.toString(16);
return hex.length & 1 ? `0${hex}` : hex;
};
const s = slice(h(sig.s));
const r = slice(h(sig.r));
const shl = s.length / 2;
const rhl = r.length / 2;
const sl = h(shl);
const rl = h(rhl);
return `30${h(rhl + shl + 4)}02${rl}${r}02${sl}${s}`;
},
};
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
const _0n = BigInt(0);
const _1n = BigInt(1);
const _3n = BigInt(3);
export function weierstrassPoints(opts) {

@@ -106,3 +107,3 @@ const CURVE = validatePointOpts(opts);

const { a, b } = CURVE;
const x2 = Fp.square(x); // x * x
const x2 = Fp.sqr(x); // x * x
const x3 = Fp.mul(x2, x); // x2 * x

@@ -113,4 +114,8 @@ return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x3 + a * x + b

function isWithinCurveOrder(num) {
return _0n < num && num < CURVE.n;
return typeof num === 'bigint' && _0n < num && num < CURVE.n;
}
function assertGE(num) {
if (!isWithinCurveOrder(num))
throw new Error('Expected valid bigint: 0 < bigint < curve.n');
}
/**

@@ -123,3 +128,3 @@ * Validates if a private key is valid and converts it to bigint form.

function normalizePrivateKey(key) {
const { normalizePrivateKey: custom, nByteLength: groupLen, wrapPrivateKey, n: order } = CURVE;
const { normalizePrivateKey: custom, nByteLength: groupLen, wrapPrivateKey, n } = CURVE;
if (typeof custom === 'function')

@@ -132,36 +137,26 @@ key = custom(key);

}
else if (ut.isPositiveInt(key)) {
num = BigInt(key);
}
else if (typeof key === 'string') {
if (key.length !== 2 * groupLen)
throw new Error(`Expected ${groupLen} bytes of private key`);
throw new Error(`must be ${groupLen} bytes`);
// Validates individual octets
num = ut.hexToNumber(key);
num = ut.bytesToNumberBE(ensureBytes(key));
}
else if (key instanceof Uint8Array) {
if (key.length !== groupLen)
throw new Error(`Expected ${groupLen} bytes of private key`);
throw new Error(`must be ${groupLen} bytes`);
num = ut.bytesToNumberBE(key);
}
else {
throw new TypeError('Expected valid private key');
throw new Error('private key must be bytes, hex or bigint, not ' + typeof key);
}
// Useful for curves with cofactor != 1
if (wrapPrivateKey)
num = mod.mod(num, order);
if (!isWithinCurveOrder(num))
throw new Error('Expected private key: 0 < key < n');
num = mod.mod(num, n);
assertGE(num);
return num;
}
/**
* Validates if a scalar ("private number") is valid.
* Scalars are valid only if they are less than curve order.
*/
function normalizeScalar(num) {
if (ut.isPositiveInt(num))
return BigInt(num);
if (typeof num === 'bigint' && isWithinCurveOrder(num))
return num;
throw new TypeError('Expected valid private scalar: 0 < scalar < curve.n');
const pointPrecomputes = new Map();
function assertPrjPoint(other) {
if (!(other instanceof Point))
throw new Error('ProjectivePoint expected');
}

@@ -173,17 +168,32 @@ /**

*/
class ProjectivePoint {
constructor(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
class Point {
constructor(px, py, pz) {
this.px = px;
this.py = py;
this.pz = pz;
if (px == null || !Fp.isValid(px))
throw new Error('x required');
if (py == null || !Fp.isValid(py))
throw new Error('y required');
if (pz == null || !Fp.isValid(pz))
throw new Error('z required');
}
static fromAffine(p) {
if (!(p instanceof Point)) {
throw new TypeError('ProjectivePoint#fromAffine: expected Point');
}
const { x, y } = p || {};
if (!p || !Fp.isValid(x) || !Fp.isValid(y))
throw new Error('invalid affine point');
if (p instanceof Point)
throw new Error('projective point not allowed');
const is0 = (i) => Fp.eql(i, Fp.ZERO);
// fromAffine(x:0, y:0) would produce (x:0, y:0, z:1), but we need (x:0, y:1, z:0)
if (p.equals(Point.ZERO))
return ProjectivePoint.ZERO;
return new ProjectivePoint(p.x, p.y, Fp.ONE);
if (is0(x) && is0(y))
return Point.ZERO;
return new Point(x, y, Fp.ONE);
}
get x() {
return this.toAffine().x;
}
get y() {
return this.toAffine().y;
}
/**

@@ -193,13 +203,52 @@ * Takes a bunch of Projective Points but executes only one

* so this improves performance massively.
* Optimization: converts a list of projective points to a list of identical points with Z=1.
*/
static toAffineBatch(points) {
const toInv = Fp.invertBatch(points.map((p) => p.z));
return points.map((p, i) => p.toAffine(toInv[i]));
static normalizeZ(points) {
const toInv = Fp.invertBatch(points.map((p) => p.pz));
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
}
/**
* Optimization: converts a list of projective points to a list of identical points with Z=1.
* Converts hash string or Uint8Array to Point.
* @param hex short/long ECDSA hex
*/
static normalizeZ(points) {
return ProjectivePoint.toAffineBatch(points).map(ProjectivePoint.fromAffine);
static fromHex(hex) {
const P = Point.fromAffine(CURVE.fromBytes(ensureBytes(hex)));
P.assertValidity();
return P;
}
// Multiplies generator point by privateKey.
static fromPrivateKey(privateKey) {
return Point.BASE.multiply(normalizePrivateKey(privateKey));
}
// "Private method", don't use it directly
_setWindowSize(windowSize) {
this._WINDOW_SIZE = windowSize;
pointPrecomputes.delete(this);
}
// A point on curve is valid if it conforms to equation.
assertValidity() {
// Zero is valid point too!
if (this.is0()) {
if (CURVE.allowInfinityPoint)
return;
throw new Error('bad point: ZERO');
}
// Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
const { x, y } = this.toAffine();
// Check if x, y are valid field elements
if (!Fp.isValid(x) || !Fp.isValid(y))
throw new Error('bad point: x or y not FE');
const left = Fp.sqr(y); // y²
const right = weierstrassEquation(x); // x³ + ax + b
if (!Fp.eql(left, right))
throw new Error('bad point: equation left != right');
if (!this.isTorsionFree())
throw new Error('bad point: not in prime-order subgroup');
}
hasEvenY() {
const { y } = this.toAffine();
if (Fp.isOdd)
return !Fp.isOdd(y);
throw new Error("Field doesn't support isOdd");
}
/**

@@ -210,6 +259,6 @@ * Compare one point to another.

assertPrjPoint(other);
const { x: X1, y: Y1, z: Z1 } = this;
const { x: X2, y: Y2, z: Z2 } = other;
const U1 = Fp.equals(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
const U2 = Fp.equals(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
const { px: X1, py: Y1, pz: Z1 } = this;
const { px: X2, py: Y2, pz: Z2 } = other;
const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
return U1 && U2;

@@ -221,3 +270,3 @@ }

negate() {
return new ProjectivePoint(this.x, Fp.negate(this.y), this.z);
return new Point(this.px, Fp.neg(this.py), this.pz);
}

@@ -231,3 +280,3 @@ // Renes-Costello-Batina exception-free doubling formula.

const b3 = Fp.mul(b, 3n);
const { x: X1, y: Y1, z: Z1 } = this;
const { px: X1, py: Y1, pz: Z1 } = this;
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore

@@ -265,3 +314,3 @@ let t0 = Fp.mul(X1, X1); // step 1

Z3 = Fp.add(Z3, Z3);
return new ProjectivePoint(X3, Y3, Z3);
return new Point(X3, Y3, Z3);
}

@@ -274,4 +323,4 @@ // Renes-Costello-Batina exception-free addition formula.

assertPrjPoint(other);
const { x: X1, y: Y1, z: Z1 } = this;
const { x: X2, y: Y2, z: Z2 } = other;
const { px: X1, py: Y1, pz: Z1 } = this;
const { px: X2, py: Y2, pz: Z2 } = other;
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore

@@ -320,3 +369,3 @@ const a = CURVE.a;

Z3 = Fp.add(Z3, t0); // step 40
return new ProjectivePoint(X3, Y3, Z3);
return new Point(X3, Y3, Z3);
}

@@ -326,2 +375,11 @@ subtract(other) {

}
is0() {
return this.equals(Point.ZERO);
}
wNAF(n) {
return wnaf.wNAFCached(this, pointPrecomputes, n, (comp) => {
const toInv = Fp.invertBatch(comp.map((p) => p.pz));
return comp.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
});
}
/**

@@ -332,16 +390,16 @@ * Non-constant-time multiplication. Uses double-and-add algorithm.

*/
multiplyUnsafe(scalar) {
const P0 = ProjectivePoint.ZERO;
if (typeof scalar === 'bigint' && scalar === _0n)
return P0;
// Will throw on 0
let n = normalizeScalar(scalar);
multiplyUnsafe(n) {
const I = Point.ZERO;
if (n === _0n)
return I;
assertGE(n); // Will throw on 0
if (n === _1n)
return this;
if (!CURVE.endo)
const { endo } = CURVE;
if (!endo)
return wnaf.unsafeLadder(this, n);
// Apply endomorphism
let { k1neg, k1, k2neg, k2 } = CURVE.endo.splitScalar(n);
let k1p = P0;
let k2p = P0;
let { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
let k1p = I;
let k2p = I;
let d = this;

@@ -361,24 +419,6 @@ while (k1 > _0n || k2 > _0n) {

k2p = k2p.negate();
k2p = new ProjectivePoint(Fp.mul(k2p.x, CURVE.endo.beta), k2p.y, k2p.z);
k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
return k1p.add(k2p);
}
/**
* Implements w-ary non-adjacent form for calculating ec multiplication.
*/
wNAF(n, affinePoint) {
if (!affinePoint && this.equals(ProjectivePoint.BASE))
affinePoint = Point.BASE;
const W = (affinePoint && affinePoint._WINDOW_SIZE) || 1;
// Calculate precomputes on a first run, reuse them after
let precomputes = affinePoint && pointPrecomputes.get(affinePoint);
if (!precomputes) {
precomputes = wnaf.precomputeWindow(this, W);
if (affinePoint && W !== 1) {
precomputes = ProjectivePoint.normalizeZ(precomputes);
pointPrecomputes.set(affinePoint, precomputes);
}
}
return wnaf.wNAF(W, precomputes, n);
}
/**
* Constant time multiplication.

@@ -391,15 +431,14 @@ * Uses wNAF method. Windowed method may be 10% faster,

*/
multiply(scalar, affinePoint) {
let n = normalizeScalar(scalar);
// Real point.
let point;
// Fake point, we use it to achieve constant-time multiplication.
let fake;
if (CURVE.endo) {
const { k1neg, k1, k2neg, k2 } = CURVE.endo.splitScalar(n);
let { p: k1p, f: f1p } = this.wNAF(k1, affinePoint);
let { p: k2p, f: f2p } = this.wNAF(k2, affinePoint);
multiply(scalar) {
assertGE(scalar);
let n = scalar;
let point, fake; // Fake point is used to const-time mult
const { endo } = CURVE;
if (endo) {
const { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
let { p: k1p, f: f1p } = this.wNAF(k1);
let { p: k2p, f: f2p } = this.wNAF(k2);
k1p = wnaf.constTimeNegate(k1neg, k1p);
k2p = wnaf.constTimeNegate(k2neg, k2p);
k2p = new ProjectivePoint(Fp.mul(k2p.x, CURVE.endo.beta), k2p.y, k2p.z);
k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
point = k1p.add(k2p);

@@ -409,3 +448,3 @@ fake = f1p.add(f2p);

else {
const { p, f } = this.wNAF(n, affinePoint);
const { p, f } = this.wNAF(n);
point = p;

@@ -415,22 +454,33 @@ fake = f;

// Normalize `z` for both points, but return only real one
return ProjectivePoint.normalizeZ([point, fake])[0];
return Point.normalizeZ([point, fake])[0];
}
/**
* Efficiently calculate `aP + bQ`. Unsafe, can expose private key, if used incorrectly.
* @returns non-zero affine point
*/
multiplyAndAddUnsafe(Q, a, b) {
const G = Point.BASE; // No Strauss-Shamir trick: we have 10% faster G precomputes
const mul = (P, a // Select faster multiply() method
) => (a === _0n || a === _1n || !P.equals(G) ? P.multiplyUnsafe(a) : P.multiply(a));
const sum = mul(this, a).add(mul(Q, b));
return sum.is0() ? undefined : sum;
}
// Converts Projective point to affine (x, y) coordinates.
// Can accept precomputed Z^-1 - for example, from invertBatch.
// (x, y, z) ∋ (x=x/z, y=y/z)
toAffine(invZ) {
const { x, y, z } = this;
const is0 = this.equals(ProjectivePoint.ZERO);
toAffine(iz) {
const { px: x, py: y, pz: z } = this;
const is0 = this.is0();
// If invZ was 0, we return zero point. However we still want to execute
// all operations, so we replace invZ with a random number, 1.
if (invZ == null)
invZ = is0 ? Fp.ONE : Fp.invert(z);
const ax = Fp.mul(x, invZ);
const ay = Fp.mul(y, invZ);
const zz = Fp.mul(z, invZ);
if (iz == null)
iz = is0 ? Fp.ONE : Fp.inv(z);
const ax = Fp.mul(x, iz);
const ay = Fp.mul(y, iz);
const zz = Fp.mul(z, iz);
if (is0)
return Point.ZERO;
if (!Fp.equals(zz, Fp.ONE))
return { x: Fp.ZERO, y: Fp.ZERO };
if (!Fp.eql(zz, Fp.ONE))
throw new Error('invZ was invalid');
return new Point(ax, ay);
return { x: ax, y: ay };
}

@@ -442,3 +492,3 @@ isTorsionFree() {

if (isTorsionFree)
return isTorsionFree(ProjectivePoint, this);
return isTorsionFree(Point, this);
throw new Error('isTorsionFree() has not been declared for the elliptic curve');

@@ -451,158 +501,19 @@ }

if (clearCofactor)
return clearCofactor(ProjectivePoint, this);
return clearCofactor(Point, this);
return this.multiplyUnsafe(CURVE.h);
}
}
ProjectivePoint.BASE = new ProjectivePoint(CURVE.Gx, CURVE.Gy, Fp.ONE);
ProjectivePoint.ZERO = new ProjectivePoint(Fp.ZERO, Fp.ONE, Fp.ZERO);
const _bits = CURVE.nBitLength;
const wnaf = wNAF(ProjectivePoint, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
function assertPrjPoint(other) {
if (!(other instanceof ProjectivePoint))
throw new TypeError('ProjectivePoint expected');
}
// Stores precomputed values for points.
const pointPrecomputes = new WeakMap();
/**
* Default Point works in default aka affine coordinates: (x, y)
*/
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
// "Private method", don't use it directly
_setWindowSize(windowSize) {
this._WINDOW_SIZE = windowSize;
pointPrecomputes.delete(this);
}
// Checks for y % 2 == 0
hasEvenY() {
if (Fp.isOdd)
return !Fp.isOdd(this.y);
throw new Error("Field doesn't support isOdd");
}
/**
* Converts hash string or Uint8Array to Point.
* @param hex short/long ECDSA hex
*/
static fromHex(hex) {
const { x, y } = CURVE.fromBytes(ut.ensureBytes(hex));
const point = new Point(x, y);
point.assertValidity();
return point;
}
// Multiplies generator point by privateKey.
static fromPrivateKey(privateKey) {
return Point.BASE.multiply(normalizePrivateKey(privateKey));
}
toRawBytes(isCompressed = false) {
toRawBytes(isCompressed = true) {
this.assertValidity();
return CURVE.toBytes(Point, this, isCompressed);
}
toHex(isCompressed = false) {
return bytesToHex(this.toRawBytes(isCompressed));
toHex(isCompressed = true) {
return ut.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 at infinity');
}
// Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
const msg = 'Point is not on elliptic curve';
const { x, y } = this;
// Check if x, y are valid field elements
if (!Fp.isValid(x) || !Fp.isValid(y))
throw new Error(msg);
const left = Fp.square(y); // y²
const right = weierstrassEquation(x); // x³ + ax + b
if (!Fp.equals(left, right))
throw new Error(msg);
if (!this.isTorsionFree())
throw new Error('Point must be of prime-order subgroup');
}
equals(other) {
if (!(other instanceof Point))
throw new TypeError('Point#equals: expected Point');
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, Fp.negate(this.y));
}
toProj() {
return ProjectivePoint.fromAffine(this);
}
// Adds point to itself
double() {
return this.toProj().double().toAffine();
}
add(other) {
return this.toProj().add(ProjectivePoint.fromAffine(other)).toAffine();
}
subtract(other) {
return this.add(other.negate());
}
multiply(scalar) {
return this.toProj().multiply(scalar, this).toAffine();
}
multiplyUnsafe(scalar) {
return this.toProj().multiplyUnsafe(scalar).toAffine();
}
clearCofactor() {
return this.toProj().clearCofactor().toAffine();
}
isTorsionFree() {
return this.toProj().isTorsionFree();
}
/**
* Efficiently calculate `aP + bQ`.
* Unsafe, can expose private key, if used incorrectly.
* TODO: Utilize Shamir's trick
* @returns non-zero affine point
*/
multiplyAndAddUnsafe(Q, a, b) {
const P = this.toProj();
const aP = a === _0n || a === _1n || this !== Point.BASE ? P.multiplyUnsafe(a) : P.multiply(a);
const bQ = ProjectivePoint.fromAffine(Q).multiplyUnsafe(b);
const sum = aP.add(bQ);
return sum.equals(ProjectivePoint.ZERO) ? undefined : sum.toAffine();
}
// 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) {
const { mapToCurve } = CURVE;
if (!mapToCurve)
throw new Error('CURVE.mapToCurve() has not been defined');
msg = ut.ensureBytes(msg);
const u = hash_to_field(msg, 2, { ...CURVE.htfDefaults, ...options });
const { x: x0, y: y0 } = mapToCurve(u[0]);
const { x: x1, y: y1 } = mapToCurve(u[1]);
return new Point(x0, y0).add(new Point(x1, y1)).clearCofactor();
}
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
static encodeToCurve(msg, options) {
const { mapToCurve } = CURVE;
if (!mapToCurve)
throw new Error('CURVE.mapToCurve() has not been defined');
msg = ut.ensureBytes(msg);
const u = hash_to_field(msg, 1, { ...CURVE.htfDefaults, ...options });
const { x, y } = mapToCurve(u[0]);
return new Point(x, y).clearCofactor();
}
}
/**
* Base point aka generator. Any public_key = Point.BASE * private_key
*/
Point.BASE = new Point(CURVE.Gx, CURVE.Gy);
/**
* Identity point aka point at infinity. p - p = zero_p; p + zero_p = p
*/
Point.ZERO = new Point(Fp.ZERO, Fp.ZERO);
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
const _bits = CURVE.nBitLength;
const wnaf = wNAF(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
return {
Point: Point,
ProjectivePoint: ProjectivePoint,
ProjectivePoint: Point,
normalizePrivateKey,

@@ -614,4 +525,4 @@ weierstrassEquation,

function validateOpts(curve) {
const opts = ut.validateOpts(curve);
if (typeof opts.hash !== 'function' || !ut.isPositiveInt(opts.hash.outputLen))
const opts = validateAbsOpts(curve);
if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
throw new Error('Invalid hash function');

@@ -625,51 +536,54 @@ if (typeof opts.hmac !== 'function')

}
/**
* 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);
const u8n = (data) => new Uint8Array(data); // creates Uint8Array
const u8fr = (arr) => Uint8Array.from(arr); // another shortcut
function hmacDrbg(hashLen, qByteLen, 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)
let v = u8n(hashLen); // Minimal non-full-spec HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
let k = u8n(hashLen); // Steps B and C of RFC6979 3.2: set hashLen, in our case always same
let i = 0; // Iterations counter, will throw when over 1000
const reset = () => {
v.fill(1);
k.fill(0);
i = 0;
};
const h = (...b) => hmacFn(k, v, ...b); // hmac(k)(v, ...values)
const reseed = (seed = u8n()) => {
// HMAC-DRBG reseed() function. Steps D-G
k = h(u8fr([0x00]), seed); // k = hmac(k || v || 0x00 || seed)
v = h(); // v = hmac(k || 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();
k = h(u8fr([0x01]), seed); // k = hmac(k || v || 0x01 || seed)
v = h(); // v = hmac(k || v)
};
const gen = () => {
// HMAC-DRBG generate() function
if (i++ >= 1000)
throw new Error('drbg: tried 1000 values');
let len = 0;
const out = [];
while (len < this.qByteLen) {
this.v = this.hmacSync(this.v);
const sl = this.v.slice();
while (len < qByteLen) {
v = h();
const sl = v.slice();
out.push(sl);
len += this.v.length;
len += v.length;
}
return ut.concatBytes(...out);
}
};
const genUntil = (seed, pred) => {
reset();
reseed(seed); // Steps D-G
let res = undefined; // Step H: grind until k is in [1..n-1]
while (!(res = pred(gen())))
reseed();
reset();
return res;
};
return genUntil;
}

@@ -683,15 +597,22 @@ export function weierstrass(curveDef) {

function isValidFieldElement(num) {
// 0 is disallowed by arbitrary reasons. Probably because infinity point?
return _0n < num && num < Fp.ORDER;
return _0n < num && num < Fp.ORDER; // 0 is banned since it's not invertible FE
}
const { Point, ProjectivePoint, normalizePrivateKey, weierstrassEquation, isWithinCurveOrder } = weierstrassPoints({
function modN(a) {
return mod.mod(a, CURVE_ORDER);
}
function invN(a) {
return mod.invert(a, CURVE_ORDER);
}
const { ProjectivePoint: Point, normalizePrivateKey, weierstrassEquation, isWithinCurveOrder, } = weierstrassPoints({
...CURVE,
toBytes(c, point, isCompressed) {
const x = Fp.toBytes(point.x);
const a = point.toAffine();
const x = Fp.toBytes(a.x);
const cat = ut.concatBytes;
if (isCompressed) {
// TODO: hasEvenY
return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x);
}
else {
return cat(Uint8Array.from([0x04]), x, Fp.toBytes(point.y));
return cat(Uint8Array.from([0x04]), x, Fp.toBytes(a.y));
}

@@ -701,6 +622,7 @@ },

const len = bytes.length;
const header = bytes[0];
const head = bytes[0];
const tail = bytes.subarray(1);
// this.assertValidity() is done inside of fromHex
if (len === compressedLen && (header === 0x02 || header === 0x03)) {
const x = ut.bytesToNumberBE(bytes.subarray(1));
if (len === compressedLen && (head === 0x02 || head === 0x03)) {
const x = ut.bytesToNumberBE(tail);
if (!isValidFieldElement(x))

@@ -712,10 +634,10 @@ throw new Error('Point is not on curve');

// ECDSA
const isFirstByteOdd = (bytes[0] & 1) === 1;
if (isFirstByteOdd !== isYOdd)
y = Fp.negate(y);
const isHeadOdd = (head & 1) === 1;
if (isHeadOdd !== isYOdd)
y = Fp.neg(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));
else if (len === uncompressedLen && head === 0x04) {
const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));
const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));
return { x, y };

@@ -728,26 +650,3 @@ }

});
// 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) => 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}`);
}
const numToNByteStr = (num) => ut.bytesToHex(ut.numberToBytesBE(num, CURVE.nByteLength));
function isBiggerThanHalfOrder(number) {

@@ -758,18 +657,6 @@ const HALF = CURVE_ORDER >> _1n;

function normalizeS(s) {
return isBiggerThanHalfOrder(s) ? mod.mod(-s, CURVE_ORDER) : s;
return isBiggerThanHalfOrder(s) ? modN(-s) : s;
}
function bits2int_2(bytes) {
const delta = bytes.length * 8 - CURVE.nBitLength;
const num = ut.bytesToNumberBE(bytes);
return delta > 0 ? num >> BigInt(delta) : num;
}
// Ensures ECDSA message hashes are 32 bytes and < curve order
function _truncateHash(hash, truncateOnly = false) {
const h = bits2int_2(hash);
if (truncateOnly)
return h;
const { n } = CURVE;
return h >= n ? h - n : h;
}
const truncateHash = CURVE.truncateHash || _truncateHash;
// slice bytes num
const slcNum = (b, from, to) => ut.bytesToNumberBE(b.slice(from, to));
/**

@@ -787,12 +674,5 @@ * ECDSA signature with its (r, s) properties. Supports DER & compact representations.

static fromCompact(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;
const gl = CURVE.nByteLength * 2; // group length in hex, not ui8a
if (str.length !== 2 * gl)
throw new Error(`${name}: Expected ${gl / 2}-byte hex`);
const slice = (from, to) => ut.hexToNumber(str.slice(from, to));
return new Signature(slice(0, gl), slice(gl, 2 * gl));
const gl = CURVE.nByteLength;
hex = ensureBytes(hex, gl * 2);
return new Signature(slcNum(hex, 0, gl), slcNum(hex, gl, 2 * gl));
}

@@ -802,61 +682,38 @@ // DER encoded ECDSA signature

static fromDER(hex) {
const arr = hex instanceof Uint8Array;
if (typeof hex !== 'string' && !arr)
throw new TypeError(`Signature.fromDER: Expected string or Uint8Array`);
const { r, s } = DER.parseSig(arr ? hex : ut.hexToBytes(hex));
if (typeof hex !== 'string' && !(hex instanceof Uint8Array))
throw new Error(`Signature.fromDER: Expected string or Uint8Array`);
const { r, s } = DER.toSig(ensureBytes(hex));
return new Signature(r, s);
}
assertValidity() {
const { r, s } = this;
if (!isWithinCurveOrder(r))
throw new Error('Invalid Signature: r must be 0 < r < n');
if (!isWithinCurveOrder(s))
throw new Error('Invalid Signature: s must be 0 < s < n');
// can use assertGE here
if (!isWithinCurveOrder(this.r))
throw new Error('r must be 0 < r < n');
if (!isWithinCurveOrder(this.s))
throw new Error('s must be 0 < s < n');
}
copyWithRecoveryBit(recovery) {
addRecoveryBit(recovery) {
return new Signature(this.r, this.s, recovery);
}
/**
* Recovers public key from signature with recovery bit. Throws on invalid hash.
* https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Public_key_recovery
* It's also possible to recover key without bit: try all 4 bit values and check for sig match.
*
* ```
* recover(r, s, h) where
* u1 = hs^-1 mod n
* u2 = sr^-1 mod n
* Q = u1⋅G + u2⋅R
* ```
*
* @param msgHash message hash
* @returns Point corresponding to public key
*/
recoverPublicKey(msgHash) {
const { r, s, recovery } = this;
if (recovery == null)
throw new Error('Cannot recover: recovery bit is not present');
if (![0, 1, 2, 3].includes(recovery))
throw new Error('Cannot recover: invalid recovery bit');
const h = truncateHash(ut.ensureBytes(msgHash));
const { n } = CURVE;
const radj = recovery === 2 || recovery === 3 ? r + n : r;
const { n: N } = CURVE; // ECDSA public key recovery secg.org/sec1-v2.pdf 4.1.6
const { r, s, recovery: rec } = this;
const h = bits2int_modN(ensureBytes(msgHash)); // Truncate hash
if (rec == null || ![0, 1, 2, 3].includes(rec))
throw new Error('recovery id invalid');
const radj = rec === 2 || rec === 3 ? r + N : r;
if (radj >= Fp.ORDER)
throw new Error('Cannot recover: bit 2/3 is invalid with current r');
const rinv = mod.invert(radj, n);
// Q = u1⋅G + u2⋅R
const u1 = mod.mod(-h * rinv, n);
const u2 = mod.mod(s * rinv, n);
const prefix = recovery & 1 ? '03' : '02';
const R = Point.fromHex(prefix + numToFieldStr(radj));
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // unsafe is fine: no priv data leaked
throw new Error('recovery id 2 or 3 invalid');
const prefix = (rec & 1) === 0 ? '02' : '03';
const R = Point.fromHex(prefix + numToNByteStr(radj));
const ir = invN(radj); // r^-1
const u1 = modN(-h * ir); // -hr^-1
const u2 = modN(s * ir); // sr^-1
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
if (!Q)
throw new Error('Cannot recover: point at infinify');
throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
Q.assertValidity();
return Q;
}
/**
* Default signatures are always low-s, to prevent malleability.
* `sign(lowS: true)` always produces low-s sigs.
* `verify(lowS: true)` always fails for high-s.
*/
// Signatures should be low-s, to prevent malleability.
hasHighS() {

@@ -866,5 +723,3 @@ return isBiggerThanHalfOrder(this.s);

normalizeS() {
return this.hasHighS()
? new Signature(this.r, mod.mod(-this.s, CURVE_ORDER), this.recovery)
: this;
return this.hasHighS() ? new Signature(this.r, modN(-this.s), this.recovery) : this;
}

@@ -876,11 +731,3 @@ // DER-encoded

toDERHex() {
const { numberToHexUnpadded: toHex } = ut;
const sHex = DER.slice(toHex(this.s));
const rHex = DER.slice(toHex(this.r));
const sHexL = sHex.length / 2;
const rHexL = rHex.length / 2;
const sLen = toHex(sHexL);
const rLen = toHex(rHexL);
const length = toHex(rHexL + sHexL + 4);
return `30${length}02${rLen}${rHex}02${sLen}${sHex}`;
return DER.hexFromSig({ r: this.r, s: this.s });
}

@@ -892,3 +739,3 @@ // padded bytes of r, then padded bytes of s

toCompactHex() {
return numToFieldStr(this.r) + numToFieldStr(this.s);
return numToNByteStr(this.r) + numToNByteStr(this.s);
}

@@ -906,13 +753,7 @@ }

},
_bigintToBytes: numToField,
_bigintToString: numToFieldStr,
_normalizePrivateKey: normalizePrivateKey,
_normalizePublicKey: normalizePublicKey,
_isWithinCurveOrder: isWithinCurveOrder,
_isValidFieldElement: isValidFieldElement,
_weierstrassEquation: weierstrassEquation,
/**
* Converts some bytes to a valid private key. Needs at least (nBitLength+64) bytes.
*/
hashToPrivateKey: (hash) => numToField(ut.hashToPrivateScalar(hash, CURVE_ORDER)),
hashToPrivateKey: (hash) => ut.numberToBytesBE(mod.hashToPrivateScalar(hash, CURVE_ORDER), CURVE.nByteLength),
/**

@@ -932,6 +773,5 @@ * Produces cryptographically secure private key from random of size (nBitLength+64)

precompute(windowSize = 8, point = Point.BASE) {
const cached = point === Point.BASE ? point : new Point(point.x, point.y);
cached._setWindowSize(windowSize);
cached.multiply(_3n);
return cached;
point._setWindowSize(windowSize);
point.multiply(BigInt(3));
return point;
},

@@ -945,3 +785,3 @@ };

*/
function getPublicKey(privateKey, isCompressed = false) {
function getPublicKey(privateKey, isCompressed = true) {
return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed);

@@ -973,52 +813,68 @@ }

*/
function getSharedSecret(privateA, publicB, isCompressed = false) {
function getSharedSecret(privateA, publicB, isCompressed = true) {
if (isProbPub(privateA))
throw new TypeError('getSharedSecret: first arg must be private key');
throw new Error('first arg must be private key');
if (!isProbPub(publicB))
throw new TypeError('getSharedSecret: second arg must be public key');
const b = normalizePublicKey(publicB);
b.assertValidity();
throw new Error('second arg must be public key');
const b = Point.fromHex(publicB); // check for being on-curve
return b.multiply(normalizePrivateKey(privateA)).toRawBytes(isCompressed);
}
// RFC6979 methods
function bits2int(bytes) {
const { nByteLength } = CURVE;
if (!(bytes instanceof Uint8Array))
throw new Error('Expected Uint8Array');
const slice = bytes.length > nByteLength ? bytes.slice(0, nByteLength) : bytes;
// const slice = bytes; nByteLength; nBitLength;
let num = ut.bytesToNumberBE(slice);
// const { nBitLength } = CURVE;
// const delta = (bytes.length * 8) - nBitLength;
// if (delta > 0) {
// // console.log('bits=', bytes.length*8, 'CURVE n=', nBitLength, 'delta=', delta);
// // console.log(bytes.length, nBitLength, delta);
// // console.log(bytes, new Error().stack);
// num >>= BigInt(delta);
// }
return num;
}
function bits2octets(bytes) {
const z1 = bits2int(bytes);
const z2 = mod.mod(z1, CURVE_ORDER);
return int2octets(z2 < _0n ? z1 : z2);
}
// RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.
// FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which matches bits2int.
// bits2int can produce res>N, we can do mod(res, N) since the bitLen is the same.
// int2octets can't be used; pads small msgs with 0: unacceptatble for trunc as per RFC vectors
const bits2int = CURVE.bits2int ||
function (bytes) {
// For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)
// for some cases, since bytes.length * 8 is not actual bitLength.
const delta = bytes.length * 8 - CURVE.nBitLength; // truncate to nBitLength leftmost bits
const num = ut.bytesToNumberBE(bytes); // check for == u8 done here
return delta > 0 ? num >> BigInt(delta) : num;
};
const bits2int_modN = CURVE.bits2int_modN ||
function (bytes) {
return modN(bits2int(bytes)); // can't use bytesToNumberBE here
};
// NOTE: pads output with zero as per spec
const ORDER_MASK = ut.bitMask(CURVE.nBitLength);
function int2octets(num) {
return numToField(num); // prohibits >nByteLength bytes
if (typeof num !== 'bigint')
throw new Error('Expected bigint');
if (!(_0n <= num && num < ORDER_MASK))
throw new Error(`Expected number < 2^${CURVE.nBitLength}`);
// works with order, can have different size than numToField!
return ut.numberToBytesBE(num, CURVE.nByteLength);
}
// Steps A, D of RFC6979 3.2
// Creates RFC6979 seed; converts msg/privKey to numbers.
function initSigArgs(msgHash, privateKey, extraEntropy) {
// Used only in sign, not in verify.
// NOTE: we cannot assume here that msgHash has same amount of bytes as curve order, this will be wrong at least for P521.
// Also it can be bigger for P224 + SHA256
function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
if (msgHash == null)
throw new Error(`sign: expected valid message hash, not "${msgHash}"`);
if (['recovered', 'canonical'].some((k) => k in opts))
// Ban legacy options
throw new Error('sign() legacy options not supported');
let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
if (prehash)
msgHash = CURVE.hash(ensureBytes(msgHash));
if (lowS == null)
lowS = true; // RFC6979 3.2: we skip step A, because
// Step A is ignored, since we already provide hash instead of msg
const h1 = numToField(truncateHash(ut.ensureBytes(msgHash)));
// NOTE: instead of bits2int, we calling here truncateHash, since we need
// custom truncation for stark. For other curves it is essentially same as calling bits2int + mod
// However, we cannot later call bits2octets (which is truncateHash + int2octets), since nested bits2int is broken
// for curves where nBitLength % 8 !== 0, so we unwrap it here as int2octets call.
// const bits2octets = (bits)=>int2octets(bytesToNumberBE(truncateHash(bits)))
const h1int = bits2int_modN(ensureBytes(msgHash));
const h1octets = int2octets(h1int);
const d = normalizePrivateKey(privateKey);
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
const seedArgs = [int2octets(d), bits2octets(h1)];
// RFC6979 3.6: additional k' could be provided
if (extraEntropy != null) {
if (extraEntropy === true)
extraEntropy = CURVE.randomBytes(Fp.BYTES);
const e = ut.ensureBytes(extraEntropy);
const seedArgs = [int2octets(d), h1octets];
if (ent != null) {
// RFC6979 3.6: additional k' (optional)
if (ent === true)
ent = CURVE.randomBytes(Fp.BYTES);
const e = ensureBytes(ent);
if (e.length !== Fp.BYTES)

@@ -1028,43 +884,30 @@ throw new Error(`sign: Expected ${Fp.BYTES} bytes of extra data`);

}
// seed is constructed from private key and message
// Step D
// V, 0x00 are done in HmacDRBG constructor.
const seed = ut.concatBytes(...seedArgs);
const m = bits2int(h1);
return { seed, m, d };
}
/**
* Converts signature params into point & r/s, checks them for validity.
* k must be in range [1, n-1]
* @param k signature's k param: deterministic in our case, random in non-rfc6979 sigs
* @param m message that would be signed
* @param d private key
* @returns Signature with its point on curve Q OR undefined if params were invalid
*/
function kmdToSig(kBytes, m, d, lowS = true) {
const { n } = CURVE;
const k = truncateHash(kBytes, true);
if (!isWithinCurveOrder(k))
return;
// Important: all mod() calls in the function must be done over `n`
const kinv = mod.invert(k, n);
const q = Point.BASE.multiply(k);
// r = x mod n
const r = mod.mod(q.x, n);
if (r === _0n)
return;
// s = (m + dr)/k mod n where x/k == x*inv(k)
const s = mod.mod(kinv * mod.mod(m + mod.mod(d * r, n), n), n);
if (s === _0n)
return;
// recovery bit is usually 0 or 1; rarely it's 2 or 3, when q.x > n
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n);
let normS = s;
if (lowS && isBiggerThanHalfOrder(s)) {
normS = normalizeS(s);
recovery ^= 1;
const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2
const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
// Converts signature params into point w r/s, checks result for validity.
function k2sig(kBytes) {
// RFC 6979 Section 3.2, step 3: k = bits2int(T)
const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
if (!isWithinCurveOrder(k))
return; // Important: all mod() calls here must be done over N
const ik = invN(k); // k^-1 mod n
const q = Point.BASE.multiply(k).toAffine(); // q = Gk
const r = modN(q.x); // r = q.x mod n
if (r === _0n)
return;
const s = modN(ik * modN(m + modN(d * r))); // s = k^-1(m + rd) mod n
if (s === _0n)
return;
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n); // recovery bit (2 or 3, when q.x > n)
let normS = s;
if (lowS && isBiggerThanHalfOrder(s)) {
normS = normalizeS(s); // if lowS was passed, ensure s is always
recovery ^= 1; // // in the bottom half of N
}
return new Signature(r, normS, recovery); // use normS, not s
}
return new Signature(r, normS, recovery);
return { seed, k2sig };
}
const defaultSigOpts = { lowS: CURVE.lowS };
const defaultSigOpts = { lowS: CURVE.lowS, prehash: false };
const defaultVerOpts = { lowS: CURVE.lowS, prehash: false };
/**

@@ -1078,24 +921,12 @@ * Signs message hash (not message: you need to hash it by yourself).

* ```
* @param opts `lowS, extraEntropy`
* @param opts `lowS, extraEntropy, prehash`
*/
function sign(msgHash, privKey, opts = defaultSigOpts) {
// Steps A, D of RFC6979 3.2.
const { seed, m, d } = initSigArgs(msgHash, privKey, opts.extraEntropy);
// Steps B, C, D, E, F, G
const drbg = new HmacDrbg(CURVE.hash.outputLen, CURVE.nByteLength, CURVE.hmac);
drbg.reseedSync(seed);
// Step H3, repeat until k is in range [1, n-1]
let sig;
while (!(sig = kmdToSig(drbg.generateSync(), m, d, opts.lowS)))
drbg.reseedSync();
return sig;
const { seed, k2sig } = prepSig(msgHash, privKey, opts); // Steps A, D of RFC6979 3.2.
const genUntil = hmacDrbg(CURVE.hash.outputLen, CURVE.nByteLength, CURVE.hmac);
return genUntil(seed, k2sig); // Steps B, C, D, E, F, G
}
/**
* Signs a message (not message hash).
*/
function signUnhashed(msg, privKey, opts = defaultSigOpts) {
return sign(CURVE.hash(ut.ensureBytes(msg)), privKey, opts);
}
// Enable precomputes. Slows down first publicKey computation by 20ms.
Point.BASE._setWindowSize(8);
// utils.precompute(8, ProjectivePoint.BASE)
/**

@@ -1114,20 +945,26 @@ * Verifies a signature against message hash and public key.

*/
function verify(signature, msgHash, publicKey, opts = { lowS: CURVE.lowS }) {
function verify(signature, msgHash, publicKey, opts = defaultVerOpts) {
let P;
let _sig = undefined;
if (publicKey instanceof Point)
throw new Error('publicKey must be hex');
try {
if (signature instanceof Signature) {
signature.assertValidity();
if (signature && typeof signature === 'object' && !(signature instanceof Uint8Array)) {
const { r, s } = signature;
_sig = new Signature(r, s); // assertValidity() is executed on creation
}
else {
// Signature can be represented in 2 ways: compact (64-byte) & DER (variable-length).
// Since DER can also be 64 bytes, we check for it first.
// Signature can be represented in 2 ways: compact (2*nByteLength) & DER (variable-length).
// Since DER can also be 2*nByteLength bytes, we check for it first.
try {
signature = Signature.fromDER(signature);
_sig = Signature.fromDER(signature);
}
catch (derError) {
if (!(derError instanceof DERError))
if (!(derError instanceof DER.Err))
throw derError;
signature = Signature.fromCompact(signature);
_sig = Signature.fromCompact(signature);
}
}
msgHash = ut.ensureBytes(msgHash);
msgHash = ensureBytes(msgHash);
P = Point.fromHex(publicKey);
}

@@ -1137,24 +974,15 @@ catch (error) {

}
if (opts.lowS && signature.hasHighS())
if (opts.lowS && _sig.hasHighS())
return false;
let P;
try {
P = normalizePublicKey(publicKey);
}
catch (error) {
return false;
}
const { n } = CURVE;
const { r, s } = signature;
const h = truncateHash(msgHash);
const sinv = mod.invert(s, n); // s^-1
// R = u1⋅G - u2⋅P
const u1 = mod.mod(h * sinv, n);
const u2 = mod.mod(r * sinv, n);
// Some implementations compare R.x in projective, without inversion.
// The speed-up is <5%, so we don't complicate the code.
const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2);
if (opts.prehash)
msgHash = CURVE.hash(msgHash);
const { r, s } = _sig;
const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
const is = invN(s); // s^-1
const u1 = modN(h * is); // u1 = hs^-1 mod n
const u2 = modN(r * is); // u2 = rs^-1 mod n
const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine(); // R = u1⋅G + u2⋅P
if (!R)
return false;
const v = mod.mod(R.x, n);
const v = modN(R.x);
return v === r;

@@ -1167,6 +995,5 @@ }

sign,
signUnhashed,
verify,
Point,
ProjectivePoint,
// Point,
ProjectivePoint: Point,
Signature,

@@ -1177,3 +1004,3 @@ utils,

// Implementation of the Shallue and van de Woestijne method for any Weierstrass curve
// TODO: check if there is a way to merge this with uvRation in Edwards && move to modular?
// TODO: check if there is a way to merge this with uvRatio in Edwards && move to modular?
// b = True and y = sqrt(u / v) if (u / v) is square in F, and

@@ -1197,3 +1024,3 @@ // b = False and y = sqrt(Z * (u / v)) otherwise.

let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4
let tv3 = Fp.square(tv2); // 3. tv3 = tv2^2
let tv3 = Fp.sqr(tv2); // 3. tv3 = tv2^2
tv3 = Fp.mul(tv3, v); // 4. tv3 = tv3 * v

@@ -1207,3 +1034,3 @@ let tv5 = Fp.mul(u, tv3); // 5. tv5 = u * tv3

tv5 = Fp.pow(tv4, c5); // 11. tv5 = tv4^c5
let isQR = Fp.equals(tv5, Fp.ONE); // 12. isQR = tv5 == 1
let isQR = Fp.eql(tv5, Fp.ONE); // 12. isQR = tv5 == 1
tv2 = Fp.mul(tv3, c7); // 13. tv2 = tv3 * c7

@@ -1217,3 +1044,3 @@ tv5 = Fp.mul(tv4, tv1); // 14. tv5 = tv4 * tv1

let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
const e1 = Fp.equals(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1

@@ -1230,5 +1057,5 @@ tv1 = Fp.mul(tv1, tv1); // 23. tv1 = tv1 * tv1

const c1 = (Fp.ORDER - 3n) / 4n; // 1. c1 = (q - 3) / 4 # Integer arithmetic
const c2 = Fp.sqrt(Fp.negate(Z)); // 2. c2 = sqrt(-Z)
const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z)
sqrtRatio = (u, v) => {
let tv1 = Fp.square(v); // 1. tv1 = v^2
let tv1 = Fp.sqr(v); // 1. tv1 = v^2
const tv2 = Fp.mul(u, v); // 2. tv2 = u * v

@@ -1239,4 +1066,4 @@ tv1 = Fp.mul(tv1, tv2); // 3. tv1 = tv1 * tv2

const y2 = Fp.mul(y1, c2); // 6. y2 = y1 * c2
const tv3 = Fp.mul(Fp.square(y1), v); // 7. tv3 = y1^2; 8. tv3 = tv3 * v
const isQR = Fp.equals(tv3, u); // 9. isQR = tv3 == u
const tv3 = Fp.mul(Fp.sqr(y1), v); // 7. tv3 = y1^2; 8. tv3 = tv3 * v
const isQR = Fp.eql(tv3, u); // 9. isQR = tv3 == u
let y = Fp.cmov(y2, y1, isQR); // 10. y = CMOV(y2, y1, isQR)

@@ -1263,12 +1090,12 @@ return { isValid: isQR, value: y }; // 11. return (isQR, y) isQR ? y : y*c2

let tv1, tv2, tv3, tv4, tv5, tv6, x, y;
tv1 = Fp.square(u); // 1. tv1 = u^2
tv1 = Fp.sqr(u); // 1. tv1 = u^2
tv1 = Fp.mul(tv1, opts.Z); // 2. tv1 = Z * tv1
tv2 = Fp.square(tv1); // 3. tv2 = tv1^2
tv2 = Fp.sqr(tv1); // 3. tv2 = tv1^2
tv2 = Fp.add(tv2, tv1); // 4. tv2 = tv2 + tv1
tv3 = Fp.add(tv2, Fp.ONE); // 5. tv3 = tv2 + 1
tv3 = Fp.mul(tv3, opts.B); // 6. tv3 = B * tv3
tv4 = Fp.cmov(opts.Z, Fp.negate(tv2), !Fp.equals(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
tv4 = Fp.cmov(opts.Z, Fp.neg(tv2), !Fp.eql(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
tv4 = Fp.mul(tv4, opts.A); // 8. tv4 = A * tv4
tv2 = Fp.square(tv3); // 9. tv2 = tv3^2
tv6 = Fp.square(tv4); // 10. tv6 = tv4^2
tv2 = Fp.sqr(tv3); // 9. tv2 = tv3^2
tv6 = Fp.sqr(tv4); // 10. tv6 = tv4^2
tv5 = Fp.mul(tv6, opts.A); // 11. tv5 = A * tv6

@@ -1287,3 +1114,3 @@ tv2 = Fp.add(tv2, tv5); // 12. tv2 = tv2 + tv5

const e1 = Fp.isOdd(u) === Fp.isOdd(y); // 23. e1 = sgn0(u) == sgn0(y)
y = Fp.cmov(Fp.negate(y), y, e1); // 24. y = CMOV(-y, y, e1)
y = Fp.cmov(Fp.neg(y), y, e1); // 24. y = CMOV(-y, y, e1)
x = Fp.div(x, tv4); // 25. x = x / tv4

@@ -1290,0 +1117,0 @@ return { x, y };

@@ -16,3 +16,3 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

import * as mod from './abstract/modular.js';
import { concatBytes, ensureBytes, numberToBytesBE, bytesToNumberBE, bitLen, bitSet, bitGet, bitMask, } from './abstract/utils.js';
import { concatBytes as concatB, ensureBytes, numberToBytesBE, bytesToNumberBE, bitLen, bitSet, bitGet, bitMask, } from './abstract/utils.js';
// Types

@@ -69,5 +69,5 @@ import { mapToCurveSimpleSWU, } from './abstract/weierstrass.js';

isValid: ({ c0, c1 }) => typeof c0 === 'bigint' && typeof c1 === 'bigint',
isZero: ({ c0, c1 }) => Fp.isZero(c0) && Fp.isZero(c1),
equals: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp.equals(c0, r0) && Fp.equals(c1, r1),
negate: ({ c0, c1 }) => ({ c0: Fp.negate(c0), c1: Fp.negate(c1) }),
is0: ({ c0, c1 }) => Fp.is0(c0) && Fp.is0(c1),
eql: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp.eql(c0, r0) && Fp.eql(c1, r1),
neg: ({ c0, c1 }) => ({ c0: Fp.neg(c0), c1: Fp.neg(c1) }),
pow: (num, power) => mod.FpPow(Fp2, num, power),

@@ -79,3 +79,3 @@ invertBatch: (nums) => mod.FpInvertBatch(Fp2, nums),

mul: Fp2Multiply,
square: Fp2Square,
sqr: Fp2Square,
// NonNormalized stuff

@@ -85,6 +85,6 @@ addN: Fp2Add,

mulN: Fp2Multiply,
squareN: Fp2Square,
sqrN: Fp2Square,
// Why inversion for bigint inside Fp instead of Fp2? it is even used in that context?
div: (lhs, rhs) => Fp2.mul(lhs, typeof rhs === 'bigint' ? Fp.invert(Fp.create(rhs)) : Fp2.invert(rhs)),
invert: ({ c0: a, c1: b }) => {
div: (lhs, rhs) => Fp2.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp2.inv(rhs)),
inv: ({ c0: a, c1: b }) => {
// We wish to find the multiplicative inverse of a nonzero

@@ -103,7 +103,7 @@ // element a + bu in Fp2. We leverage an identity

// only a single inversion in Fp.
const factor = Fp.invert(Fp.create(a * a + b * b));
const factor = Fp.inv(Fp.create(a * a + b * b));
return { c0: Fp.mul(factor, Fp.create(a)), c1: Fp.mul(factor, Fp.create(-b)) };
},
sqrt: (num) => {
if (Fp2.equals(num, Fp2.ZERO))
if (Fp2.eql(num, Fp2.ZERO))
return Fp2.ZERO; // Algo doesn't handles this case

@@ -117,5 +117,5 @@ // TODO: Optimize this line. It's extremely slow.

const candidateSqrt = Fp2.pow(num, (Fp2.ORDER + 8n) / 16n);
const check = Fp2.div(Fp2.square(candidateSqrt), num); // candidateSqrt.square().div(this);
const check = Fp2.div(Fp2.sqr(candidateSqrt), num); // candidateSqrt.square().div(this);
const R = FP2_ROOTS_OF_UNITY;
const divisor = [R[0], R[2], R[4], R[6]].find((r) => Fp2.equals(r, check));
const divisor = [R[0], R[2], R[4], R[6]].find((r) => Fp2.eql(r, check));
if (!divisor)

@@ -128,3 +128,3 @@ throw new Error('No root');

const x1 = Fp2.div(candidateSqrt, root);
const x2 = Fp2.negate(x1);
const x2 = Fp2.neg(x1);
const { re: re1, im: im1 } = Fp2.reim(x1);

@@ -150,3 +150,3 @@ const { re: re2, im: im2 } = Fp2.reim(x2);

},
toBytes: ({ c0, c1 }) => concatBytes(Fp.toBytes(c0), Fp.toBytes(c1)),
toBytes: ({ c0, c1 }) => concatB(Fp.toBytes(c0), Fp.toBytes(c1)),
cmov: ({ c0, c1 }, { c0: r0, c1: r1 }, c) => ({

@@ -241,6 +241,6 @@ c0: Fp.cmov(c0, r0, c),

const Fp6Square = ({ c0, c1, c2 }) => {
let t0 = Fp2.square(c0); // c0²
let t0 = Fp2.sqr(c0); // c0²
let t1 = Fp2.mul(Fp2.mul(c0, c1), 2n); // 2 * c0 * c1
let t3 = Fp2.mul(Fp2.mul(c1, c2), 2n); // 2 * c1 * c2
let t4 = Fp2.square(c2); // c2²
let t4 = Fp2.sqr(c2); // c2²
return {

@@ -250,3 +250,3 @@ c0: Fp2.add(Fp2.mulByNonresidue(t3), t0),

// T1 + (c0 - c1 + c2)² + T3 - T0 - T4
c2: Fp2.sub(Fp2.sub(Fp2.add(Fp2.add(t1, Fp2.square(Fp2.add(Fp2.sub(c0, c1), c2))), t3), t0), t4),
c2: Fp2.sub(Fp2.sub(Fp2.add(Fp2.add(t1, Fp2.sqr(Fp2.add(Fp2.sub(c0, c1), c2))), t3), t0), t4),
};

@@ -263,5 +263,5 @@ };

isValid: ({ c0, c1, c2 }) => Fp2.isValid(c0) && Fp2.isValid(c1) && Fp2.isValid(c2),
isZero: ({ c0, c1, c2 }) => Fp2.isZero(c0) && Fp2.isZero(c1) && Fp2.isZero(c2),
negate: ({ c0, c1, c2 }) => ({ c0: Fp2.negate(c0), c1: Fp2.negate(c1), c2: Fp2.negate(c2) }),
equals: ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) => Fp2.equals(c0, r0) && Fp2.equals(c1, r1) && Fp2.equals(c2, r2),
is0: ({ c0, c1, c2 }) => Fp2.is0(c0) && Fp2.is0(c1) && Fp2.is0(c2),
neg: ({ c0, c1, c2 }) => ({ c0: Fp2.neg(c0), c1: Fp2.neg(c1), c2: Fp2.neg(c2) }),
eql: ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) => Fp2.eql(c0, r0) && Fp2.eql(c1, r1) && Fp2.eql(c2, r2),
sqrt: () => {

@@ -271,3 +271,3 @@ throw new Error('Not implemented');

// Do we need division by bigint at all? Should be done via order:
div: (lhs, rhs) => Fp6.mul(lhs, typeof rhs === 'bigint' ? Fp.invert(Fp.create(rhs)) : Fp6.invert(rhs)),
div: (lhs, rhs) => Fp6.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp6.inv(rhs)),
pow: (num, power) => mod.FpPow(Fp6, num, power),

@@ -279,3 +279,3 @@ invertBatch: (nums) => mod.FpInvertBatch(Fp6, nums),

mul: Fp6Multiply,
square: Fp6Square,
sqr: Fp6Square,
// NonNormalized stuff

@@ -285,9 +285,9 @@ addN: Fp6Add,

mulN: Fp6Multiply,
squareN: Fp6Square,
invert: ({ c0, c1, c2 }) => {
let t0 = Fp2.sub(Fp2.square(c0), Fp2.mulByNonresidue(Fp2.mul(c2, c1))); // c0² - c2 * c1 * (u + 1)
let t1 = Fp2.sub(Fp2.mulByNonresidue(Fp2.square(c2)), Fp2.mul(c0, c1)); // c2² * (u + 1) - c0 * c1
let t2 = Fp2.sub(Fp2.square(c1), Fp2.mul(c0, c2)); // c1² - c0 * c2
sqrN: Fp6Square,
inv: ({ c0, c1, c2 }) => {
let t0 = Fp2.sub(Fp2.sqr(c0), Fp2.mulByNonresidue(Fp2.mul(c2, c1))); // c0² - c2 * c1 * (u + 1)
let t1 = Fp2.sub(Fp2.mulByNonresidue(Fp2.sqr(c2)), Fp2.mul(c0, c1)); // c2² * (u + 1) - c0 * c1
let t2 = Fp2.sub(Fp2.sqr(c1), Fp2.mul(c0, c2)); // c1² - c0 * c2
// 1/(((c2 * T1 + c1 * T2) * v) + c0 * T0)
let t4 = Fp2.invert(Fp2.add(Fp2.mulByNonresidue(Fp2.add(Fp2.mul(c2, t1), Fp2.mul(c1, t2))), Fp2.mul(c0, t0)));
let t4 = Fp2.inv(Fp2.add(Fp2.mulByNonresidue(Fp2.add(Fp2.mul(c2, t1), Fp2.mul(c1, t2))), Fp2.mul(c0, t0)));
return { c0: Fp2.mul(t4, t0), c1: Fp2.mul(t4, t1), c2: Fp2.mul(t4, t2) };

@@ -305,3 +305,3 @@ },

},
toBytes: ({ c0, c1, c2 }) => concatBytes(Fp2.toBytes(c0), Fp2.toBytes(c1), Fp2.toBytes(c2)),
toBytes: ({ c0, c1, c2 }) => concatB(Fp2.toBytes(c0), Fp2.toBytes(c1), Fp2.toBytes(c2)),
cmov: ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }, c) => ({

@@ -434,7 +434,7 @@ c0: Fp2.cmov(c0, r0, c),

function Fp4Square(a, b) {
const a2 = Fp2.square(a);
const b2 = Fp2.square(b);
const a2 = Fp2.sqr(a);
const b2 = Fp2.sqr(b);
return {
first: Fp2.add(Fp2.mulByNonresidue(b2), a2),
second: Fp2.sub(Fp2.sub(Fp2.square(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
second: Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
};

@@ -451,13 +451,13 @@ }

isValid: ({ c0, c1 }) => Fp6.isValid(c0) && Fp6.isValid(c1),
isZero: ({ c0, c1 }) => Fp6.isZero(c0) && Fp6.isZero(c1),
negate: ({ c0, c1 }) => ({ c0: Fp6.negate(c0), c1: Fp6.negate(c1) }),
equals: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp6.equals(c0, r0) && Fp6.equals(c1, r1),
is0: ({ c0, c1 }) => Fp6.is0(c0) && Fp6.is0(c1),
neg: ({ c0, c1 }) => ({ c0: Fp6.neg(c0), c1: Fp6.neg(c1) }),
eql: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp6.eql(c0, r0) && Fp6.eql(c1, r1),
sqrt: () => {
throw new Error('Not implemented');
},
invert: ({ c0, c1 }) => {
let t = Fp6.invert(Fp6.sub(Fp6.square(c0), Fp6.mulByNonresidue(Fp6.square(c1)))); // 1 / (c0² - c1² * v)
return { c0: Fp6.mul(c0, t), c1: Fp6.negate(Fp6.mul(c1, t)) }; // ((C0 * T) * T) + (-C1 * T) * w
inv: ({ c0, c1 }) => {
let t = Fp6.inv(Fp6.sub(Fp6.sqr(c0), Fp6.mulByNonresidue(Fp6.sqr(c1)))); // 1 / (c0² - c1² * v)
return { c0: Fp6.mul(c0, t), c1: Fp6.neg(Fp6.mul(c1, t)) }; // ((C0 * T) * T) + (-C1 * T) * w
},
div: (lhs, rhs) => Fp12.mul(lhs, typeof rhs === 'bigint' ? Fp.invert(Fp.create(rhs)) : Fp12.invert(rhs)),
div: (lhs, rhs) => Fp12.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp12.inv(rhs)),
pow: (num, power) => mod.FpPow(Fp12, num, power),

@@ -469,3 +469,3 @@ invertBatch: (nums) => mod.FpInvertBatch(Fp12, nums),

mul: Fp12Multiply,
square: Fp12Square,
sqr: Fp12Square,
// NonNormalized stuff

@@ -475,3 +475,3 @@ addN: Fp12Add,

mulN: Fp12Multiply,
squareN: Fp12Square,
sqrN: Fp12Square,
// Bytes utils

@@ -486,3 +486,3 @@ fromBytes: (b) => {

},
toBytes: ({ c0, c1 }) => concatBytes(Fp6.toBytes(c0), Fp6.toBytes(c1)),
toBytes: ({ c0, c1 }) => concatB(Fp6.toBytes(c0), Fp6.toBytes(c1)),
cmov: ({ c0, c1 }, { c0: r0, c1: r1 }, c) => ({

@@ -531,3 +531,3 @@ c0: Fp6.cmov(c0, r0, c),

}),
conjugate: ({ c0, c1 }) => ({ c0, c1: Fp6.negate(c1) }),
conjugate: ({ c0, c1 }) => ({ c0, c1: Fp6.neg(c1) }),
// A cyclotomic group is a subgroup of Fp^n defined by

@@ -811,3 +811,3 @@ // GΦₙ(p) = {α ∈ Fpⁿ : α^Φₙ(p) = 1}

function psi2(x, y) {
return [Fp2.mul(x, PSI2_C1), Fp2.negate(y)];
return [Fp2.mul(x, PSI2_C1), Fp2.neg(y)];
}

@@ -834,2 +834,3 @@ function G2psi2(c, P) {

DST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
encodeDST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
// p: the characteristic of F

@@ -901,3 +902,3 @@ // where F is a finite field of characteristic p and order q = p^m

const cubicRootOfUnityModP = 0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffen;
const phi = new c(Fp.mul(point.x, cubicRootOfUnityModP), point.y, point.z);
const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz);
// todo: unroll

@@ -944,3 +945,3 @@ const xP = point.multiplyUnsafe(bls12_381.CURVE.x).negate(); // [x]P

if ((y * 2n) / P !== aflag)
y = Fp.negate(y);
y = Fp.neg(y);
return { x: Fp.create(x), y: Fp.create(y) };

@@ -951,3 +952,3 @@ }

if ((bytes[0] & (1 << 6)) !== 0)
return bls12_381.G1.Point.ZERO;
return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
const x = bytesToNumberBE(bytes.slice(0, Fp.BYTES));

@@ -963,3 +964,3 @@ const y = bytesToNumberBE(bytes.slice(Fp.BYTES));

const isZero = point.equals(c.ZERO);
const { x, y } = point;
const { x, y } = point.toAffine();
if (isCompressed) {

@@ -977,7 +978,7 @@ if (isZero)

// 2x PUBLIC_KEY_LENGTH
const x = concatBytes(new Uint8Array([0x40]), new Uint8Array(2 * Fp.BYTES - 1));
const x = concatB(new Uint8Array([0x40]), new Uint8Array(2 * Fp.BYTES - 1));
return x;
}
else {
return concatBytes(numberToBytesBE(x, Fp.BYTES), numberToBytesBE(y, Fp.BYTES));
return concatB(numberToBytesBE(x, Fp.BYTES), numberToBytesBE(y, Fp.BYTES));
}

@@ -1052,2 +1053,4 @@ }

const bitS = m_byte & 0x20; // sign bit
const L = Fp.BYTES;
const slc = (b, from, to) => bytesToNumberBE(b.slice(from, to));
if (bytes.length === 96 && bitC) {

@@ -1064,4 +1067,4 @@ const { b } = bls12_381.CURVE.G2;

}
const x_1 = bytesToNumberBE(bytes.slice(0, Fp.BYTES));
const x_0 = bytesToNumberBE(bytes.slice(Fp.BYTES));
const x_1 = slc(bytes, 0, L);
const x_0 = slc(bytes, L, 2 * L);
const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });

@@ -1071,3 +1074,3 @@ const right = Fp2.add(Fp2.pow(x, 3n), b); // y² = x³ + 4 * (u+1) = x³ + b

const Y_bit = y.c1 === 0n ? (y.c0 * 2n) / P : (y.c1 * 2n) / P ? 1n : 0n;
y = bitS > 0 && Y_bit > 0 ? y : Fp2.negate(y);
y = bitS > 0 && Y_bit > 0 ? y : Fp2.neg(y);
return { x, y };

@@ -1080,6 +1083,6 @@ }

}
const x1 = bytesToNumberBE(bytes.slice(0, Fp.BYTES));
const x0 = bytesToNumberBE(bytes.slice(Fp.BYTES, 2 * Fp.BYTES));
const y1 = bytesToNumberBE(bytes.slice(2 * Fp.BYTES, 3 * Fp.BYTES));
const y0 = bytesToNumberBE(bytes.slice(3 * Fp.BYTES));
const x1 = slc(bytes, 0, L);
const x0 = slc(bytes, L, 2 * L);
const y1 = slc(bytes, 2 * L, 3 * L);
const y0 = slc(bytes, 3 * L, 4 * L);
return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };

@@ -1093,7 +1096,7 @@ }

const isZero = point.equals(c.ZERO);
const { x, y } = point;
const { x, y } = point.toAffine();
if (isCompressed) {
const P = Fp.ORDER;
if (isZero)
return concatBytes(COMPRESSED_ZERO, numberToBytesBE(0n, Fp.BYTES));
return concatB(COMPRESSED_ZERO, numberToBytesBE(0n, Fp.BYTES));
const flag = Boolean(y.c1 === 0n ? (y.c0 * 2n) / P : (y.c1 * 2n) / P);

@@ -1103,10 +1106,10 @@ // set compressed & sign bits (looks like different offsets than for G1/Fp?)

x_1 = bitSet(x_1, S_BIT_POS, true);
return concatBytes(numberToBytesBE(x_1, Fp.BYTES), numberToBytesBE(x.c0, Fp.BYTES));
return concatB(numberToBytesBE(x_1, Fp.BYTES), numberToBytesBE(x.c0, Fp.BYTES));
}
else {
if (isZero)
return concatBytes(new Uint8Array([0x40]), new Uint8Array(4 * Fp.BYTES - 1)); // bytes[0] |= 1 << 6;
return concatB(new Uint8Array([0x40]), new Uint8Array(4 * Fp.BYTES - 1)); // bytes[0] |= 1 << 6;
const { re: x0, im: x1 } = Fp2.reim(x);
const { re: y0, im: y1 } = Fp2.reim(y);
return concatBytes(numberToBytesBE(x1, Fp.BYTES), numberToBytesBE(x0, Fp.BYTES), numberToBytesBE(y1, Fp.BYTES), numberToBytesBE(y0, Fp.BYTES));
return concatB(numberToBytesBE(x1, Fp.BYTES), numberToBytesBE(x0, Fp.BYTES), numberToBytesBE(y1, Fp.BYTES), numberToBytesBE(y0, Fp.BYTES));
}

@@ -1127,3 +1130,3 @@ },

if (bflag1 === 1n)
return bls12_381.G2.Point.ZERO;
return bls12_381.G2.ProjectivePoint.ZERO;
const x1 = Fp.create(z1 & Fp.MASK);

@@ -1144,4 +1147,5 @@ const x2 = Fp.create(z2);

if (isGreater || isZero)
y = Fp2.negate(y);
const point = new bls12_381.G2.Point(x, y);
y = Fp2.neg(y);
const point = bls12_381.G2.ProjectivePoint.fromAffine({ x, y });
// console.log('Signature.decode', point);
point.assertValidity();

@@ -1153,6 +1157,7 @@ return point;

point.assertValidity();
if (point.equals(bls12_381.G2.Point.ZERO))
return concatBytes(COMPRESSED_ZERO, numberToBytesBE(0n, Fp.BYTES));
const { re: x0, im: x1 } = Fp2.reim(point.x);
const { re: y0, im: y1 } = Fp2.reim(point.y);
if (point.equals(bls12_381.G2.ProjectivePoint.ZERO))
return concatB(COMPRESSED_ZERO, numberToBytesBE(0n, Fp.BYTES));
const a = point.toAffine();
const { re: x0, im: x1 } = Fp2.reim(a.x);
const { re: y0, im: y1 } = Fp2.reim(a.y);
const tmp = y1 > 0n ? y1 * 2n : y0 * 2n;

@@ -1162,3 +1167,3 @@ const aflag1 = Boolean((tmp / Fp.ORDER) & 1n);

const z2 = x0;
return concatBytes(numberToBytesBE(z1, Fp.BYTES), numberToBytesBE(z2, Fp.BYTES));
return concatB(numberToBytesBE(z1, Fp.BYTES), numberToBytesBE(z2, Fp.BYTES));
},

@@ -1165,0 +1170,0 @@ },

/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import { sha256 } from '@noble/hashes/sha256';
import { weierstrass } from './abstract/weierstrass.js';
import { sha256 } from '@noble/hashes/sha256';
import { getHash } from './_shortw_utils.js';

@@ -5,0 +5,0 @@ import { Fp } from './abstract/modular.js';

@@ -8,2 +8,3 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

import { ensureBytes, equalBytes, bytesToHex, bytesToNumberLE, numberToBytesLE, } from './abstract/utils.js';
import * as htf from './abstract/hash-to-curve.js';
/**

@@ -83,2 +84,52 @@ * ed25519 Twisted Edwards curve with following addons:

const Fp = Field(ED25519_P, undefined, true);
const ED25519_DEF = {
// Param: a
a: BigInt(-1),
// Equal to -121665/121666 over finite field.
// Negative number is P - number, and division is invert(number, P)
d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
// Finite field 𝔽p over which we'll do calculations; 2n ** 255n - 19n
Fp,
// Subgroup order: how many points ed25519 has
// 2n ** 252n + 27742317777372353535851937790883648493n;
n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
// Cofactor
h: BigInt(8),
// Base point (x, y) aka generator point
Gx: BigInt('15112221349535400772501151409588531511454012693041857206046113283949847762202'),
Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'),
hash: sha512,
randomBytes,
adjustScalarBytes,
// dom2
// Ratio of u to v. Allows us to combine inversion and square root. Uses algo from RFC8032 5.1.3.
// Constant-time, u/√v
uvRatio,
};
export const ed25519 = twistedEdwards(ED25519_DEF);
function ed25519_domain(data, ctx, phflag) {
if (ctx.length > 255)
throw new Error('Context is too big');
return concatBytes(utf8ToBytes('SigEd25519 no Ed25519 collisions'), new Uint8Array([phflag ? 1 : 0, ctx.length]), ctx, data);
}
export const ed25519ctx = twistedEdwards({ ...ED25519_DEF, domain: ed25519_domain });
export const ed25519ph = twistedEdwards({
...ED25519_DEF,
domain: ed25519_domain,
preHash: sha512,
});
export const x25519 = montgomery({
P: ED25519_P,
a24: BigInt('121665'),
montgomeryBits: 255,
nByteLength: 32,
Gu: '0900000000000000000000000000000000000000000000000000000000000000',
powPminus2: (x) => {
const P = ED25519_P;
// x^(p-2) aka x^(2^255-21)
const { pow_p_5_8, b2 } = ed25519_pow_2_252_3(x);
return mod(pow2(pow_p_5_8, BigInt(3), P) * b2, P);
},
adjustScalarBytes,
});
// Hash To Curve Elligator2 Map (NOTE: different from ristretto255 elligator)

@@ -89,3 +140,3 @@ // NOTE: very important part is usage of FpSqrtEven for ELL2_C1_EDWARDS, since

const ELL2_C2 = Fp.pow(_2n, ELL2_C1); // 2. c2 = 2^c1
const ELL2_C3 = Fp.sqrt(Fp.negate(Fp.ONE)); // 3. c3 = sqrt(-1)
const ELL2_C3 = Fp.sqrt(Fp.neg(Fp.ONE)); // 3. c3 = sqrt(-1)
const ELL2_C4 = (Fp.ORDER - BigInt(5)) / BigInt(8); // 4. c4 = (q - 5) / 8 # Integer arithmetic

@@ -95,7 +146,7 @@ const ELL2_J = BigInt(486662);

function map_to_curve_elligator2_curve25519(u) {
let tv1 = Fp.square(u); // 1. tv1 = u^2
let tv1 = Fp.sqr(u); // 1. tv1 = u^2
tv1 = Fp.mul(tv1, _2n); // 2. tv1 = 2 * tv1
let xd = Fp.add(tv1, Fp.ONE); // 3. xd = tv1 + 1 # Nonzero: -1 is square (mod p), tv1 is not
let x1n = Fp.negate(ELL2_J); // 4. x1n = -J # x1 = x1n / xd = -J / (1 + 2 * u^2)
let tv2 = Fp.square(xd); // 5. tv2 = xd^2
let x1n = Fp.neg(ELL2_J); // 4. x1n = -J # x1 = x1n / xd = -J / (1 + 2 * u^2)
let tv2 = Fp.sqr(xd); // 5. tv2 = xd^2
let gxd = Fp.mul(tv2, xd); // 6. gxd = tv2 * xd # gxd = xd^3

@@ -106,4 +157,4 @@ let gx1 = Fp.mul(tv1, ELL2_J); // 7. gx1 = J * tv1 # x1n + J * xd

gx1 = Fp.mul(gx1, x1n); // 10. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
let tv3 = Fp.square(gxd); // 11. tv3 = gxd^2
tv2 = Fp.square(tv3); // 12. tv2 = tv3^2 # gxd^4
let tv3 = Fp.sqr(gxd); // 11. tv3 = gxd^2
tv2 = Fp.sqr(tv3); // 12. tv2 = tv3^2 # gxd^4
tv3 = Fp.mul(tv3, gxd); // 13. tv3 = tv3 * gxd # gxd^3

@@ -115,5 +166,5 @@ tv3 = Fp.mul(tv3, gx1); // 14. tv3 = tv3 * gx1 # gx1 * gxd^3

let y12 = Fp.mul(y11, ELL2_C3); // 18. y12 = y11 * c3
tv2 = Fp.square(y11); // 19. tv2 = y11^2
tv2 = Fp.sqr(y11); // 19. tv2 = y11^2
tv2 = Fp.mul(tv2, gxd); // 20. tv2 = tv2 * gxd
let e1 = Fp.equals(tv2, gx1); // 21. e1 = tv2 == gx1
let e1 = Fp.eql(tv2, gx1); // 21. e1 = tv2 == gx1
let y1 = Fp.cmov(y12, y11, e1); // 22. y1 = CMOV(y12, y11, e1) # If g(x1) is square, this is its sqrt

@@ -125,16 +176,16 @@ let x2n = Fp.mul(x1n, tv1); // 23. x2n = x1n * tv1 # x2 = x2n / xd = 2 * u^2 * x1n / xd

let gx2 = Fp.mul(gx1, tv1); // 27. gx2 = gx1 * tv1 # g(x2) = gx2 / gxd = 2 * u^2 * g(x1)
tv2 = Fp.square(y21); // 28. tv2 = y21^2
tv2 = Fp.sqr(y21); // 28. tv2 = y21^2
tv2 = Fp.mul(tv2, gxd); // 29. tv2 = tv2 * gxd
let e2 = Fp.equals(tv2, gx2); // 30. e2 = tv2 == gx2
let e2 = Fp.eql(tv2, gx2); // 30. e2 = tv2 == gx2
let y2 = Fp.cmov(y22, y21, e2); // 31. y2 = CMOV(y22, y21, e2) # If g(x2) is square, this is its sqrt
tv2 = Fp.square(y1); // 32. tv2 = y1^2
tv2 = Fp.sqr(y1); // 32. tv2 = y1^2
tv2 = Fp.mul(tv2, gxd); // 33. tv2 = tv2 * gxd
let e3 = Fp.equals(tv2, gx1); // 34. e3 = tv2 == gx1
let e3 = Fp.eql(tv2, gx1); // 34. e3 = tv2 == gx1
let xn = Fp.cmov(x2n, x1n, e3); // 35. xn = CMOV(x2n, x1n, e3) # If e3, x = x1, else x = x2
let y = Fp.cmov(y2, y1, e3); // 36. y = CMOV(y2, y1, e3) # If e3, y = y1, else y = y2
let e4 = Fp.isOdd(y); // 37. e4 = sgn0(y) == 1 # Fix sign of y
y = Fp.cmov(y, Fp.negate(y), e3 !== e4); // 38. y = CMOV(y, -y, e3 XOR e4)
y = Fp.cmov(y, Fp.neg(y), e3 !== e4); // 38. y = CMOV(y, -y, e3 XOR e4)
return { xMn: xn, xMd: xd, yMn: y, yMd: 1n }; // 39. return (xn, xd, y, 1)
}
const ELL2_C1_EDWARDS = FpSqrtEven(Fp, Fp.negate(BigInt(486664))); // sgn0(c1) MUST equal 0
const ELL2_C1_EDWARDS = FpSqrtEven(Fp, Fp.neg(BigInt(486664))); // sgn0(c1) MUST equal 0
function map_to_curve_elligator2_edwards25519(u) {

@@ -148,3 +199,3 @@ const { xMn, xMd, yMn, yMd } = map_to_curve_elligator2_curve25519(u); // 1. (xMn, xMd, yMn, yMd) = map_to_curve_elligator2_curve25519(u)

let tv1 = Fp.mul(xd, yd); // 7. tv1 = xd * yd
let e = Fp.equals(tv1, Fp.ZERO); // 8. e = tv1 == 0
let e = Fp.eql(tv1, Fp.ZERO); // 8. e = tv1 == 0
xn = Fp.cmov(xn, Fp.ZERO, e); // 9. xn = CMOV(xn, 0, e)

@@ -157,64 +208,15 @@ xd = Fp.cmov(xd, Fp.ONE, e); // 10. xd = CMOV(xd, 1, e)

}
const ED25519_DEF = {
// Param: a
a: BigInt(-1),
// Equal to -121665/121666 over finite field.
// Negative number is P - number, and division is invert(number, P)
d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
// Finite field 𝔽p over which we'll do calculations; 2n ** 255n - 19n
Fp,
// Subgroup order: how many points ed25519 has
// 2n ** 252n + 27742317777372353535851937790883648493n;
n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
// Cofactor
h: BigInt(8),
// Base point (x, y) aka generator point
Gx: BigInt('15112221349535400772501151409588531511454012693041857206046113283949847762202'),
Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'),
const { hashToCurve, encodeToCurve } = htf.hashToCurve(ed25519.ExtendedPoint, (scalars) => map_to_curve_elligator2_edwards25519(scalars[0]), {
DST: 'edwards25519_XMD:SHA-512_ELL2_RO_',
encodeDST: 'edwards25519_XMD:SHA-512_ELL2_NU_',
p: Fp.ORDER,
m: 1,
k: 128,
expand: 'xmd',
hash: sha512,
randomBytes,
adjustScalarBytes,
// dom2
// Ratio of u to v. Allows us to combine inversion and square root. Uses algo from RFC8032 5.1.3.
// Constant-time, u/√v
uvRatio,
htfDefaults: {
DST: 'edwards25519_XMD:SHA-512_ELL2_RO_',
p: Fp.ORDER,
m: 1,
k: 128,
expand: 'xmd',
hash: sha512,
},
mapToCurve: (scalars) => map_to_curve_elligator2_edwards25519(scalars[0]),
};
export const ed25519 = twistedEdwards(ED25519_DEF);
function ed25519_domain(data, ctx, phflag) {
if (ctx.length > 255)
throw new Error('Context is too big');
return concatBytes(utf8ToBytes('SigEd25519 no Ed25519 collisions'), new Uint8Array([phflag ? 1 : 0, ctx.length]), ctx, data);
}
export const ed25519ctx = twistedEdwards({ ...ED25519_DEF, domain: ed25519_domain });
export const ed25519ph = twistedEdwards({
...ED25519_DEF,
domain: ed25519_domain,
preHash: sha512,
});
export const x25519 = montgomery({
P: ED25519_P,
a24: BigInt('121665'),
montgomeryBits: 255,
nByteLength: 32,
Gu: '0900000000000000000000000000000000000000000000000000000000000000',
powPminus2: (x) => {
const P = ED25519_P;
// x^(p-2) aka x^(2^255-21)
const { pow_p_5_8, b2 } = ed25519_pow_2_252_3(x);
return mod(pow2(pow_p_5_8, BigInt(3), P) * b2, P);
},
adjustScalarBytes,
});
export { hashToCurve, encodeToCurve };
function assertRstPoint(other) {
if (!(other instanceof RistrettoPoint))
throw new TypeError('RistrettoPoint expected');
throw new Error('RistrettoPoint expected');
}

@@ -328,3 +330,3 @@ // √(-1) aka √(a) aka 2^((p-1)/4)

toRawBytes() {
let { x, y, z, t } = this.ep;
let { ex: x, ey: y, ez: z, et: t } = this.ep;
const P = ed25519.CURVE.Fp.ORDER;

@@ -367,8 +369,8 @@ const mod = ed25519.CURVE.Fp.create;

assertRstPoint(other);
const a = this.ep;
const b = other.ep;
const { ex: X1, ey: Y1 } = this.ep;
const { ex: X2, ey: Y2 } = this.ep;
const mod = ed25519.CURVE.Fp.create;
// (x1 * y2 == y1 * x2) | (y1 * y2 == x1 * x2)
const one = mod(a.x * b.y) === mod(a.y * b.x);
const two = mod(a.y * b.y) === mod(a.x * b.x);
const one = mod(X1 * Y2) === mod(Y1 * X2);
const two = mod(Y1 * Y2) === mod(X1 * X2);
return one || two;

@@ -375,0 +377,0 @@ }

@@ -7,2 +7,3 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

import { montgomery } from './abstract/montgomery.js';
import * as htf from './abstract/hash-to-curve.js';
/**

@@ -50,75 +51,2 @@ * Edwards448 (not Ed448-Goldilocks) curve with following addons:

const Fp = Field(ed448P, 456, true);
// Hash To Curve Elligator2 Map
const ELL2_C1 = (Fp.ORDER - BigInt(3)) / BigInt(4); // 1. c1 = (q - 3) / 4 # Integer arithmetic
const ELL2_J = BigInt(156326);
function map_to_curve_elligator2_curve448(u) {
let tv1 = Fp.square(u); // 1. tv1 = u^2
let e1 = Fp.equals(tv1, Fp.ONE); // 2. e1 = tv1 == 1
tv1 = Fp.cmov(tv1, Fp.ZERO, e1); // 3. tv1 = CMOV(tv1, 0, e1) # If Z * u^2 == -1, set tv1 = 0
let xd = Fp.sub(Fp.ONE, tv1); // 4. xd = 1 - tv1
let x1n = Fp.negate(ELL2_J); // 5. x1n = -J
let tv2 = Fp.square(xd); // 6. tv2 = xd^2
let gxd = Fp.mul(tv2, xd); // 7. gxd = tv2 * xd # gxd = xd^3
let gx1 = Fp.mul(tv1, Fp.negate(ELL2_J)); // 8. gx1 = -J * tv1 # x1n + J * xd
gx1 = Fp.mul(gx1, x1n); // 9. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd
gx1 = Fp.add(gx1, tv2); // 10. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2
gx1 = Fp.mul(gx1, x1n); // 11. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
let tv3 = Fp.square(gxd); // 12. tv3 = gxd^2
tv2 = Fp.mul(gx1, gxd); // 13. tv2 = gx1 * gxd # gx1 * gxd
tv3 = Fp.mul(tv3, tv2); // 14. tv3 = tv3 * tv2 # gx1 * gxd^3
let y1 = Fp.pow(tv3, ELL2_C1); // 15. y1 = tv3^c1 # (gx1 * gxd^3)^((p - 3) / 4)
y1 = Fp.mul(y1, tv2); // 16. y1 = y1 * tv2 # gx1 * gxd * (gx1 * gxd^3)^((p - 3) / 4)
let x2n = Fp.mul(x1n, Fp.negate(tv1)); // 17. x2n = -tv1 * x1n # x2 = x2n / xd = -1 * u^2 * x1n / xd
let y2 = Fp.mul(y1, u); // 18. y2 = y1 * u
y2 = Fp.cmov(y2, Fp.ZERO, e1); // 19. y2 = CMOV(y2, 0, e1)
tv2 = Fp.square(y1); // 20. tv2 = y1^2
tv2 = Fp.mul(tv2, gxd); // 21. tv2 = tv2 * gxd
let e2 = Fp.equals(tv2, gx1); // 22. e2 = tv2 == gx1
let xn = Fp.cmov(x2n, x1n, e2); // 23. xn = CMOV(x2n, x1n, e2) # If e2, x = x1, else x = x2
let y = Fp.cmov(y2, y1, e2); // 24. y = CMOV(y2, y1, e2) # If e2, y = y1, else y = y2
let e3 = Fp.isOdd(y); // 25. e3 = sgn0(y) == 1 # Fix sign of y
y = Fp.cmov(y, Fp.negate(y), e2 !== e3); // 26. y = CMOV(y, -y, e2 XOR e3)
return { xn, xd, yn: y, yd: Fp.ONE }; // 27. return (xn, xd, y, 1)
}
function map_to_curve_elligator2_edwards448(u) {
let { xn, xd, yn, yd } = map_to_curve_elligator2_curve448(u); // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
let xn2 = Fp.square(xn); // 2. xn2 = xn^2
let xd2 = Fp.square(xd); // 3. xd2 = xd^2
let xd4 = Fp.square(xd2); // 4. xd4 = xd2^2
let yn2 = Fp.square(yn); // 5. yn2 = yn^2
let yd2 = Fp.square(yd); // 6. yd2 = yd^2
let xEn = Fp.sub(xn2, xd2); // 7. xEn = xn2 - xd2
let tv2 = Fp.sub(xEn, xd2); // 8. tv2 = xEn - xd2
xEn = Fp.mul(xEn, xd2); // 9. xEn = xEn * xd2
xEn = Fp.mul(xEn, yd); // 10. xEn = xEn * yd
xEn = Fp.mul(xEn, yn); // 11. xEn = xEn * yn
xEn = Fp.mul(xEn, 4n); // 12. xEn = xEn * 4
tv2 = Fp.mul(tv2, xn2); // 13. tv2 = tv2 * xn2
tv2 = Fp.mul(tv2, yd2); // 14. tv2 = tv2 * yd2
let tv3 = Fp.mul(yn2, 4n); // 15. tv3 = 4 * yn2
let tv1 = Fp.add(tv3, yd2); // 16. tv1 = tv3 + yd2
tv1 = Fp.mul(tv1, xd4); // 17. tv1 = tv1 * xd4
let xEd = Fp.add(tv1, tv2); // 18. xEd = tv1 + tv2
tv2 = Fp.mul(tv2, xn); // 19. tv2 = tv2 * xn
let tv4 = Fp.mul(xn, xd4); // 20. tv4 = xn * xd4
let yEn = Fp.sub(tv3, yd2); // 21. yEn = tv3 - yd2
yEn = Fp.mul(yEn, tv4); // 22. yEn = yEn * tv4
yEn = Fp.sub(yEn, tv2); // 23. yEn = yEn - tv2
tv1 = Fp.add(xn2, xd2); // 24. tv1 = xn2 + xd2
tv1 = Fp.mul(tv1, xd2); // 25. tv1 = tv1 * xd2
tv1 = Fp.mul(tv1, xd); // 26. tv1 = tv1 * xd
tv1 = Fp.mul(tv1, yn2); // 27. tv1 = tv1 * yn2
tv1 = Fp.mul(tv1, BigInt(-2)); // 28. tv1 = -2 * tv1
let yEd = Fp.add(tv2, tv1); // 29. yEd = tv2 + tv1
tv4 = Fp.mul(tv4, yd2); // 30. tv4 = tv4 * yd2
yEd = Fp.add(yEd, tv4); // 31. yEd = yEd + tv4
tv1 = Fp.mul(xEd, yEd); // 32. tv1 = xEd * yEd
let e = Fp.equals(tv1, Fp.ZERO); // 33. e = tv1 == 0
xEn = Fp.cmov(xEn, Fp.ZERO, e); // 34. xEn = CMOV(xEn, 0, e)
xEd = Fp.cmov(xEd, Fp.ONE, e); // 35. xEd = CMOV(xEd, 1, e)
yEn = Fp.cmov(yEn, Fp.ONE, e); // 36. yEn = CMOV(yEn, 1, e)
yEd = Fp.cmov(yEd, Fp.ONE, e); // 37. yEd = CMOV(yEd, 1, e)
const inv = Fp.invertBatch([xEd, yEd]); // batch division
return { x: Fp.mul(xEn, inv[0]), y: Fp.mul(yEn, inv[1]) }; // 38. return (xEn, xEd, yEn, yEd)
}
const ED448_DEF = {

@@ -171,11 +99,2 @@ // Param: a

},
htfDefaults: {
DST: 'edwards448_XOF:SHAKE256_ELL2_RO_',
p: Fp.ORDER,
m: 1,
k: 224,
expand: 'xof',
hash: shake256,
},
mapToCurve: (scalars) => map_to_curve_elligator2_edwards448(scalars[0]),
};

@@ -213,1 +132,84 @@ export const ed448 = twistedEdwards(ED448_DEF);

});
// Hash To Curve Elligator2 Map
const ELL2_C1 = (Fp.ORDER - BigInt(3)) / BigInt(4); // 1. c1 = (q - 3) / 4 # Integer arithmetic
const ELL2_J = BigInt(156326);
function map_to_curve_elligator2_curve448(u) {
let tv1 = Fp.sqr(u); // 1. tv1 = u^2
let e1 = Fp.eql(tv1, Fp.ONE); // 2. e1 = tv1 == 1
tv1 = Fp.cmov(tv1, Fp.ZERO, e1); // 3. tv1 = CMOV(tv1, 0, e1) # If Z * u^2 == -1, set tv1 = 0
let xd = Fp.sub(Fp.ONE, tv1); // 4. xd = 1 - tv1
let x1n = Fp.neg(ELL2_J); // 5. x1n = -J
let tv2 = Fp.sqr(xd); // 6. tv2 = xd^2
let gxd = Fp.mul(tv2, xd); // 7. gxd = tv2 * xd # gxd = xd^3
let gx1 = Fp.mul(tv1, Fp.neg(ELL2_J)); // 8. gx1 = -J * tv1 # x1n + J * xd
gx1 = Fp.mul(gx1, x1n); // 9. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd
gx1 = Fp.add(gx1, tv2); // 10. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2
gx1 = Fp.mul(gx1, x1n); // 11. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
let tv3 = Fp.sqr(gxd); // 12. tv3 = gxd^2
tv2 = Fp.mul(gx1, gxd); // 13. tv2 = gx1 * gxd # gx1 * gxd
tv3 = Fp.mul(tv3, tv2); // 14. tv3 = tv3 * tv2 # gx1 * gxd^3
let y1 = Fp.pow(tv3, ELL2_C1); // 15. y1 = tv3^c1 # (gx1 * gxd^3)^((p - 3) / 4)
y1 = Fp.mul(y1, tv2); // 16. y1 = y1 * tv2 # gx1 * gxd * (gx1 * gxd^3)^((p - 3) / 4)
let x2n = Fp.mul(x1n, Fp.neg(tv1)); // 17. x2n = -tv1 * x1n # x2 = x2n / xd = -1 * u^2 * x1n / xd
let y2 = Fp.mul(y1, u); // 18. y2 = y1 * u
y2 = Fp.cmov(y2, Fp.ZERO, e1); // 19. y2 = CMOV(y2, 0, e1)
tv2 = Fp.sqr(y1); // 20. tv2 = y1^2
tv2 = Fp.mul(tv2, gxd); // 21. tv2 = tv2 * gxd
let e2 = Fp.eql(tv2, gx1); // 22. e2 = tv2 == gx1
let xn = Fp.cmov(x2n, x1n, e2); // 23. xn = CMOV(x2n, x1n, e2) # If e2, x = x1, else x = x2
let y = Fp.cmov(y2, y1, e2); // 24. y = CMOV(y2, y1, e2) # If e2, y = y1, else y = y2
let e3 = Fp.isOdd(y); // 25. e3 = sgn0(y) == 1 # Fix sign of y
y = Fp.cmov(y, Fp.neg(y), e2 !== e3); // 26. y = CMOV(y, -y, e2 XOR e3)
return { xn, xd, yn: y, yd: Fp.ONE }; // 27. return (xn, xd, y, 1)
}
function map_to_curve_elligator2_edwards448(u) {
let { xn, xd, yn, yd } = map_to_curve_elligator2_curve448(u); // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
let xn2 = Fp.sqr(xn); // 2. xn2 = xn^2
let xd2 = Fp.sqr(xd); // 3. xd2 = xd^2
let xd4 = Fp.sqr(xd2); // 4. xd4 = xd2^2
let yn2 = Fp.sqr(yn); // 5. yn2 = yn^2
let yd2 = Fp.sqr(yd); // 6. yd2 = yd^2
let xEn = Fp.sub(xn2, xd2); // 7. xEn = xn2 - xd2
let tv2 = Fp.sub(xEn, xd2); // 8. tv2 = xEn - xd2
xEn = Fp.mul(xEn, xd2); // 9. xEn = xEn * xd2
xEn = Fp.mul(xEn, yd); // 10. xEn = xEn * yd
xEn = Fp.mul(xEn, yn); // 11. xEn = xEn * yn
xEn = Fp.mul(xEn, 4n); // 12. xEn = xEn * 4
tv2 = Fp.mul(tv2, xn2); // 13. tv2 = tv2 * xn2
tv2 = Fp.mul(tv2, yd2); // 14. tv2 = tv2 * yd2
let tv3 = Fp.mul(yn2, 4n); // 15. tv3 = 4 * yn2
let tv1 = Fp.add(tv3, yd2); // 16. tv1 = tv3 + yd2
tv1 = Fp.mul(tv1, xd4); // 17. tv1 = tv1 * xd4
let xEd = Fp.add(tv1, tv2); // 18. xEd = tv1 + tv2
tv2 = Fp.mul(tv2, xn); // 19. tv2 = tv2 * xn
let tv4 = Fp.mul(xn, xd4); // 20. tv4 = xn * xd4
let yEn = Fp.sub(tv3, yd2); // 21. yEn = tv3 - yd2
yEn = Fp.mul(yEn, tv4); // 22. yEn = yEn * tv4
yEn = Fp.sub(yEn, tv2); // 23. yEn = yEn - tv2
tv1 = Fp.add(xn2, xd2); // 24. tv1 = xn2 + xd2
tv1 = Fp.mul(tv1, xd2); // 25. tv1 = tv1 * xd2
tv1 = Fp.mul(tv1, xd); // 26. tv1 = tv1 * xd
tv1 = Fp.mul(tv1, yn2); // 27. tv1 = tv1 * yn2
tv1 = Fp.mul(tv1, BigInt(-2)); // 28. tv1 = -2 * tv1
let yEd = Fp.add(tv2, tv1); // 29. yEd = tv2 + tv1
tv4 = Fp.mul(tv4, yd2); // 30. tv4 = tv4 * yd2
yEd = Fp.add(yEd, tv4); // 31. yEd = yEd + tv4
tv1 = Fp.mul(xEd, yEd); // 32. tv1 = xEd * yEd
let e = Fp.eql(tv1, Fp.ZERO); // 33. e = tv1 == 0
xEn = Fp.cmov(xEn, Fp.ZERO, e); // 34. xEn = CMOV(xEn, 0, e)
xEd = Fp.cmov(xEd, Fp.ONE, e); // 35. xEd = CMOV(xEd, 1, e)
yEn = Fp.cmov(yEn, Fp.ONE, e); // 36. yEn = CMOV(yEn, 1, e)
yEd = Fp.cmov(yEd, Fp.ONE, e); // 37. yEd = CMOV(yEd, 1, e)
const inv = Fp.invertBatch([xEd, yEd]); // batch division
return { x: Fp.mul(xEn, inv[0]), y: Fp.mul(yEn, inv[1]) }; // 38. return (xEn, xEd, yEn, yEd)
}
const { hashToCurve, encodeToCurve } = htf.hashToCurve(ed448.ExtendedPoint, (scalars) => map_to_curve_elligator2_edwards448(scalars[0]), {
DST: 'edwards448_XOF:SHAKE256_ELL2_RO_',
encodeDST: 'edwards448_XOF:SHAKE256_ELL2_NU_',
p: Fp.ORDER,
m: 1,
k: 224,
expand: 'xof',
hash: shake256,
});
export { hashToCurve, encodeToCurve };

@@ -36,3 +36,3 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

// NOTE: returns ExtendedPoint, in case it will be multiplied later
let p = jubjub.ExtendedPoint.fromAffine(jubjub.Point.fromHex(h.digest()));
let p = jubjub.ExtendedPoint.fromHex(h.digest());
// NOTE: cannot replace with isSmallOrder, returns Point*8

@@ -39,0 +39,0 @@ p = p.multiply(jubjub.CURVE.h);

@@ -6,2 +6,3 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
import * as htf from './abstract/hash-to-curve.js';
// NIST secp256r1 aka P256

@@ -30,12 +31,13 @@ // https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-256

lowS: false,
mapToCurve: (scalars) => mapSWU(scalars[0]),
htfDefaults: {
DST: 'P256_XMD:SHA-256_SSWU_RO_',
p: Fp.ORDER,
m: 1,
k: 128,
expand: 'xmd',
hash: sha256,
},
}, sha256);
export const secp256r1 = P256;
const { hashToCurve, encodeToCurve } = htf.hashToCurve(secp256r1.ProjectivePoint, (scalars) => mapSWU(scalars[0]), {
DST: 'P256_XMD:SHA-256_SSWU_RO_',
encodeDST: 'P256_XMD:SHA-256_SSWU_NU_',
p: Fp.ORDER,
m: 1,
k: 128,
expand: 'xmd',
hash: sha256,
});
export { hashToCurve, encodeToCurve };

@@ -6,2 +6,3 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
import * as htf from './abstract/hash-to-curve.js';
// NIST secp384r1 aka P384

@@ -35,12 +36,13 @@ // https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-384

lowS: false,
mapToCurve: (scalars) => mapSWU(scalars[0]),
htfDefaults: {
DST: 'P384_XMD:SHA-384_SSWU_RO_',
p: Fp.ORDER,
m: 1,
k: 192,
expand: 'xmd',
hash: sha384,
},
}, sha384);
export const secp384r1 = P384;
const { hashToCurve, encodeToCurve } = htf.hashToCurve(secp384r1.ProjectivePoint, (scalars) => mapSWU(scalars[0]), {
DST: 'P384_XMD:SHA-384_SSWU_RO_',
encodeDST: 'P384_XMD:SHA-384_SSWU_NU_',
p: Fp.ORDER,
m: 1,
k: 192,
expand: 'xmd',
hash: sha384,
});
export { hashToCurve, encodeToCurve };

@@ -7,2 +7,3 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
import * as htf from './abstract/hash-to-curve.js';
// NIST secp521r1 aka P521

@@ -36,4 +37,3 @@ // Note that it's 521, which differs from 512 of its hash function.

lowS: false,
// P521 keys could be 130, 131, 132 bytes - which doesn't play nicely.
// We ensure all keys are 132 bytes.
// P521 keys could be 130, 131, 132 bytes. We normalize to 132 bytes.
// Does not replace validation; invalid keys would still be rejected.

@@ -48,14 +48,15 @@ normalizePrivateKey(key) {

}
return key.padStart(66 * 2, '0');
return key.padStart(66 * 2, '0'); // ensure it's always 132 bytes
},
mapToCurve: (scalars) => mapSWU(scalars[0]),
htfDefaults: {
DST: 'P521_XMD:SHA-512_SSWU_RO_',
p: Fp.ORDER,
m: 1,
k: 256,
expand: 'xmd',
hash: sha512,
},
}, sha512);
export const secp521r1 = P521;
const { hashToCurve, encodeToCurve } = htf.hashToCurve(secp521r1.ProjectivePoint, (scalars) => mapSWU(scalars[0]), {
DST: 'P521_XMD:SHA-512_SSWU_RO_',
encodeDST: 'P521_XMD:SHA-512_SSWU_NU_',
p: Fp.ORDER,
m: 1,
k: 256,
expand: 'xmd',
hash: sha512,
});
export { hashToCurve, encodeToCurve };

@@ -6,5 +6,5 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
import { ensureBytes, concatBytes, hexToBytes, bytesToNumberBE, } from './abstract/utils.js';
import { ensureBytes, concatBytes, bytesToNumberBE as bytesToNum, numberToBytesBE, } from './abstract/utils.js';
import { randomBytes } from '@noble/hashes/utils';
import { isogenyMap } from './abstract/hash-to-curve.js';
import * as htf from './abstract/hash-to-curve.js';
/**

@@ -23,6 +23,3 @@ * secp256k1 belongs to Koblitz curves: it has efficiently computable endomorphism.

/**
* Allows to compute square root √y 2x faster.
* To calculate √y, we need to exponentiate it to a very big number:
* `y² = x³ + ax + b; y = y² ^ (p+1)/4`
* We are unwrapping the loop and multiplying it bit-by-bit.
* √n = n^((p+1)/4) for fields p = 3 mod 4. We unwrap the loop and multiply bit-by-bit.
* (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00]

@@ -50,3 +47,3 @@ */

const root = pow2(t2, _2n, P);
if (!Fp.equals(Fp.square(root), y))
if (!Fp.eql(Fp.sqr(root), y))
throw new Error('Cannot find square root');

@@ -56,36 +53,2 @@ return root;

const Fp = Field(secp256k1P, undefined, undefined, { sqrt: sqrtMod });
const isoMap = isogenyMap(Fp, [
// xNum
[
'0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa8c7',
'0x7d3d4c80bc321d5b9f315cea7fd44c5d595d2fc0bf63b92dfff1044f17c6581',
'0x534c328d23f234e6e2a413deca25caece4506144037c40314ecbd0b53d9dd262',
'0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa88c',
],
// xDen
[
'0xd35771193d94918a9ca34ccbb7b640dd86cd409542f8487d9fe6b745781eb49b',
'0xedadc6f64383dc1df7c4b2d51b54225406d36b641f5e41bbc52a56612a8c6d14',
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
],
// yNum
[
'0x4bda12f684bda12f684bda12f684bda12f684bda12f684bda12f684b8e38e23c',
'0xc75e0c32d5cb7c0fa9d0a54b12a0a6d5647ab046d686da6fdffc90fc201d71a3',
'0x29a6194691f91a73715209ef6512e576722830a201be2018a765e85a9ecee931',
'0x2f684bda12f684bda12f684bda12f684bda12f684bda12f684bda12f38e38d84',
],
// yDen
[
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff93b',
'0x7a06534bb8bdb49fd5e9e6632722c2989467c1bfc8e8d978dfb425d2685c2573',
'0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f',
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
],
].map((i) => i.map((j) => BigInt(j))));
const mapSWU = mapToCurveSimpleSWU(Fp, {
A: BigInt('0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533'),
B: BigInt('1771'),
Z: Fp.create(BigInt('-11')),
});
export const secp256k1 = createCurve({

@@ -133,47 +96,9 @@ // Params: a, b

},
mapToCurve: (scalars) => {
const { x, y } = mapSWU(Fp.create(scalars[0]));
return isoMap(x, y);
},
htfDefaults: {
DST: 'secp256k1_XMD:SHA-256_SSWU_RO_',
p: Fp.ORDER,
m: 1,
k: 128,
expand: 'xmd',
hash: sha256,
},
}, sha256);
// Schnorr
// Schnorr signatures are superior to ECDSA from above.
// Below is Schnorr-specific code as per BIP0340.
// https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
const _0n = BigInt(0);
const numTo32b = secp256k1.utils._bigintToBytes;
const numTo32bStr = secp256k1.utils._bigintToString;
const normalizePrivateKey = secp256k1.utils._normalizePrivateKey;
// TODO: export?
function normalizePublicKey(publicKey) {
if (publicKey instanceof secp256k1.Point) {
publicKey.assertValidity();
return publicKey;
}
else {
const bytes = ensureBytes(publicKey);
// Schnorr is 32 bytes
if (bytes.length !== 32)
throw new Error('Schnorr pubkeys must be 32 bytes');
const x = bytesToNumberBE(bytes);
if (!isValidFieldElement(x))
throw new Error('Point is not on curve');
const y2 = secp256k1.utils._weierstrassEquation(x); // y² = x³ + ax + b
let y = sqrtMod(y2); // y = y² ^ (p+1)/4
const isYOdd = (y & _1n) === _1n;
// Schnorr
if (isYOdd)
y = secp256k1.CURVE.Fp.negate(y);
const point = new secp256k1.Point(x, y);
point.assertValidity();
return point;
}
}
const isWithinCurveOrder = secp256k1.utils._isWithinCurveOrder;
const isValidFieldElement = secp256k1.utils._isValidFieldElement;
const fe = (x) => typeof x === 'bigint' && _0n < x && x < secp256k1P;
const ge = (x) => typeof x === 'bigint' && _0n < x && x < secp256k1N;
const TAGS = {

@@ -186,3 +111,3 @@ challenge: 'BIP0340/challenge',

const TAGGED_HASH_PREFIXES = {};
export function taggedHash(tag, ...messages) {
function taggedHash(tag, ...messages) {
let tagP = TAGGED_HASH_PREFIXES[tag];

@@ -197,40 +122,33 @@ if (tagP === undefined) {

const toRawX = (point) => point.toRawBytes(true).slice(1);
// Schnorr signatures are superior to ECDSA from above.
// Below is Schnorr-specific code as per BIP0340.
function schnorrChallengeFinalize(ch) {
return mod(bytesToNumberBE(ch), secp256k1.CURVE.n);
}
// Do we need this at all for Schnorr?
class SchnorrSignature {
constructor(r, s) {
this.r = r;
this.s = s;
this.assertValidity();
}
static fromHex(hex) {
const bytes = ensureBytes(hex);
const len = 32; // group length
if (bytes.length !== 2 * len)
throw new TypeError(`SchnorrSignature.fromHex: expected ${2 * len} bytes, not ${bytes.length}`);
const r = bytesToNumberBE(bytes.subarray(0, len));
const s = bytesToNumberBE(bytes.subarray(len, 2 * len));
return new SchnorrSignature(r, s);
}
assertValidity() {
const { r, s } = this;
if (!isValidFieldElement(r) || !isWithinCurveOrder(s))
throw new Error('Invalid signature');
}
toHex() {
return numTo32bStr(this.r) + numTo32bStr(this.s);
}
toRawBytes() {
return hexToBytes(this.toHex());
}
}
const numTo32b = (n) => numberToBytesBE(n, 32);
const modN = (x) => mod(x, secp256k1N);
const _Point = secp256k1.ProjectivePoint;
const Gmul = (priv) => _Point.fromPrivateKey(priv);
const GmulAdd = (Q, a, b) => _Point.BASE.multiplyAndAddUnsafe(Q, a, b);
function schnorrGetScalar(priv) {
const point = secp256k1.Point.fromPrivateKey(priv);
const scalar = point.hasEvenY() ? priv : secp256k1.CURVE.n - priv;
// Let d' = int(sk)
// Fail if d' = 0 or d' ≥ n
// Let P = d'⋅G
// Let d = d' if has_even_y(P), otherwise let d = n - d' .
const point = Gmul(priv);
const scalar = point.hasEvenY() ? priv : modN(-priv);
return { point, scalar, x: toRawX(point) };
}
function lift_x(x) {
if (!fe(x))
throw new Error('bad x: need 0 < x < p'); // Fail if x ≥ p.
const c = mod(x * x * x + BigInt(7), secp256k1P); // Let c = x³ + 7 mod p.
let y = sqrtMod(c); // Let y = c^(p+1)/4 mod p.
if (y % 2n !== 0n)
y = mod(-y, secp256k1P); // Return the unique point P such that x(P) = x and
const p = new _Point(x, y, _1n); // y(P) = y if y mod 2 = 0 or y(P) = p-y otherwise.
p.assertValidity();
return p;
}
function challenge(...args) {
return modN(bytesToNum(taggedHash(TAGS.challenge, ...args)));
}
function schnorrGetPublicKey(privateKey) {
return toRawX(Gmul(privateKey)); // Let d' = int(sk). Fail if d' = 0 or d' ≥ n. Return bytes(d'⋅G)
}
/**

@@ -245,19 +163,19 @@ * Synchronously creates Schnorr signature. Improved security: verifies itself before

if (message == null)
throw new TypeError(`sign: Expected valid message, not "${message}"`);
throw new Error(`sign: Expected valid message, not "${message}"`);
const m = ensureBytes(message);
// checks for isWithinCurveOrder
const { x: px, scalar: d } = schnorrGetScalar(normalizePrivateKey(privateKey));
const rand = ensureBytes(auxRand);
if (rand.length !== 32)
throw new TypeError('sign: Expected 32 bytes of aux randomness');
const tag = taggedHash;
const t0h = tag(TAGS.aux, rand);
const t = numTo32b(d ^ bytesToNumberBE(t0h));
const k0h = tag(TAGS.nonce, t, px, m);
const k0 = mod(bytesToNumberBE(k0h), secp256k1.CURVE.n);
if (k0 === _0n)
throw new Error('sign: Creation of signature failed. k is zero');
const { point: R, x: rx, scalar: k } = schnorrGetScalar(k0);
const e = schnorrChallengeFinalize(tag(TAGS.challenge, rx, px, m));
const sig = new SchnorrSignature(R.x, mod(k + e * d, secp256k1.CURVE.n)).toRawBytes();
const { x: px, scalar: d } = schnorrGetScalar(bytesToNum(ensureBytes(privateKey, 32)));
const a = ensureBytes(auxRand, 32); // Auxiliary random data a: a 32-byte array
// TODO: replace with proper xor?
const t = numTo32b(d ^ bytesToNum(taggedHash(TAGS.aux, a))); // Let t be the byte-wise xor of bytes(d) and hash/aux(a)
const rand = taggedHash(TAGS.nonce, t, px, m); // Let rand = hash/nonce(t || bytes(P) || m)
const k_ = modN(bytesToNum(rand)); // Let k' = int(rand) mod n
if (k_ === _0n)
throw new Error('sign failed: k is zero'); // Fail if k' = 0.
const { point: R, x: rx, scalar: k } = schnorrGetScalar(k_); // Let R = k'⋅G.
const e = challenge(rx, px, m); // Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
const sig = new Uint8Array(64); // Let sig = bytes(R) || bytes((k + ed) mod n).
sig.set(numTo32b(R.px), 0);
sig.set(numTo32b(modN(k + e * d)), 32);
// If Verify(bytes(P), m, sig) (see below) returns failure, abort
if (!schnorrVerify(sig, m, px))

@@ -272,17 +190,16 @@ throw new Error('sign: Invalid signature produced');

try {
const raw = signature instanceof SchnorrSignature;
const sig = raw ? signature : SchnorrSignature.fromHex(signature);
if (raw)
sig.assertValidity(); // just in case
const { r, s } = sig;
const P = lift_x(bytesToNum(ensureBytes(publicKey, 32))); // P = lift_x(int(pk)); fail if that fails
const sig = ensureBytes(signature, 64);
const r = bytesToNum(sig.subarray(0, 32)); // Let r = int(sig[0:32]); fail if r ≥ p.
if (!fe(r))
return false;
const s = bytesToNum(sig.subarray(32, 64)); // Let s = int(sig[32:64]); fail if s ≥ n.
if (!ge(s))
return false;
const m = ensureBytes(message);
const P = normalizePublicKey(publicKey);
const e = schnorrChallengeFinalize(taggedHash(TAGS.challenge, numTo32b(r), toRawX(P), m));
// Finalize
// R = s⋅G - e⋅P
// -eP == (n-e)P
const R = secp256k1.Point.BASE.multiplyAndAddUnsafe(P, normalizePrivateKey(s), mod(-e, secp256k1.CURVE.n));
if (!R || !R.hasEvenY() || R.x !== r)
return false;
return true;
const e = challenge(numTo32b(r), toRawX(P), m); // int(challenge(bytes(r)||bytes(P)||m)) mod n
const R = GmulAdd(P, s, modN(-e)); // R = s⋅G - e⋅P
if (!R || !R.hasEvenY() || R.toAffine().x !== r)
return false; // -eP == (n-e)P
return true; // Fail if is_infinite(R) / not has_even_y(R) / x(R) ≠ r.
}

@@ -294,7 +211,54 @@ catch (error) {

export const schnorr = {
Signature: SchnorrSignature,
// Schnorr's pubkey is just `x` of Point (BIP340)
getPublicKey: (privateKey) => toRawX(secp256k1.Point.fromPrivateKey(privateKey)),
getPublicKey: schnorrGetPublicKey,
sign: schnorrSign,
verify: schnorrVerify,
utils: { lift_x, int: bytesToNum, taggedHash },
};
const isoMap = htf.isogenyMap(Fp, [
// xNum
[
'0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa8c7',
'0x7d3d4c80bc321d5b9f315cea7fd44c5d595d2fc0bf63b92dfff1044f17c6581',
'0x534c328d23f234e6e2a413deca25caece4506144037c40314ecbd0b53d9dd262',
'0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa88c',
],
// xDen
[
'0xd35771193d94918a9ca34ccbb7b640dd86cd409542f8487d9fe6b745781eb49b',
'0xedadc6f64383dc1df7c4b2d51b54225406d36b641f5e41bbc52a56612a8c6d14',
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
],
// yNum
[
'0x4bda12f684bda12f684bda12f684bda12f684bda12f684bda12f684b8e38e23c',
'0xc75e0c32d5cb7c0fa9d0a54b12a0a6d5647ab046d686da6fdffc90fc201d71a3',
'0x29a6194691f91a73715209ef6512e576722830a201be2018a765e85a9ecee931',
'0x2f684bda12f684bda12f684bda12f684bda12f684bda12f684bda12f38e38d84',
],
// yDen
[
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff93b',
'0x7a06534bb8bdb49fd5e9e6632722c2989467c1bfc8e8d978dfb425d2685c2573',
'0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f',
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
],
].map((i) => i.map((j) => BigInt(j))));
const mapSWU = mapToCurveSimpleSWU(Fp, {
A: BigInt('0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533'),
B: BigInt('1771'),
Z: Fp.create(BigInt('-11')),
});
const { hashToCurve, encodeToCurve } = htf.hashToCurve(secp256k1.ProjectivePoint, (scalars) => {
const { x, y } = mapSWU(Fp.create(scalars[0]));
return isoMap(x, y);
}, {
DST: 'secp256k1_XMD:SHA-256_SSWU_RO_',
encodeDST: 'secp256k1_XMD:SHA-256_SSWU_NU_',
p: Fp.ORDER,
m: 1,
k: 128,
expand: 'xmd',
hash: sha256,
});
export { hashToCurve, encodeToCurve };

@@ -6,4 +6,6 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

import * as cutils from './abstract/utils.js';
import { Fp } from './abstract/modular.js';
import { Fp, mod, validateField } from './abstract/modular.js';
import { getHash } from './_shortw_utils.js';
import * as poseidon from './abstract/poseidon.js';
import { utf8ToBytes } from '@noble/hashes/utils';
// Stark-friendly elliptic curve

@@ -13,2 +15,11 @@ // https://docs.starkware.co/starkex/stark-curve.html

const nBitLength = 252;
// Copy-pasted from weierstrass.ts
function bits2int(bytes) {
const delta = bytes.length * 8 - nBitLength;
const num = cutils.bytesToNumberBE(bytes);
return delta > 0 ? num >> BigInt(delta) : num;
}
function bits2int_modN(bytes) {
return mod(bits2int(bytes), CURVE_N);
}
export const starkCurve = weierstrass({

@@ -31,23 +42,18 @@ // Params: a, b

...getHash(sha256),
truncateHash: (hash, truncateOnly = false) => {
// TODO: cleanup, ugly code
// Fix truncation
if (!truncateOnly) {
let hashS = bytesToNumber0x(hash).toString(16);
if (hashS.length === 63) {
hashS += '0';
hash = hexToBytes0x(hashS);
}
// Custom truncation routines for stark curve
bits2int: (bytes) => {
while (bytes[0] === 0)
bytes = bytes.subarray(1);
return bits2int(bytes);
},
bits2int_modN: (bytes) => {
let hashS = cutils.bytesToNumberBE(bytes).toString(16);
if (hashS.length === 63) {
hashS += '0';
bytes = hexToBytes0x(hashS);
}
// Truncate zero bytes on left (compat with elliptic)
while (hash[0] === 0)
hash = hash.subarray(1);
const byteLength = hash.length;
const delta = byteLength * 8 - nBitLength; // size of curve.n (252 bits)
let h = hash.length ? bytesToNumber0x(hash) : 0n;
if (delta > 0)
h = h >> BigInt(delta);
if (!truncateOnly && h >= CURVE_N)
h -= CURVE_N;
return h;
while (bytes[0] === 0)
bytes = bytes.subarray(1);
return bits2int_modN(bytes);
},

@@ -58,3 +64,3 @@ });

if (typeof hex !== 'string') {
throw new TypeError('hexToBytes: expected string, got ' + typeof hex);
throw new Error('hexToBytes: expected string, got ' + typeof hex);
}

@@ -79,3 +85,3 @@ hex = strip0x(hex);

if (typeof hex !== 'string') {
throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
throw new Error('hexToNumber: expected string, got ' + typeof hex);
}

@@ -95,3 +101,3 @@ // Big Endian

function normalizePrivateKey(privKey) {
return cutils.bytesToHex(ensureBytes0x(privKey)).padStart(32 * 2, '0');
return cutils.bytesToHex(ensureBytes0x(privKey)).padStart(64, '0');
}

@@ -113,5 +119,5 @@ function getPublicKey0x(privKey, isCompressed) {

}
const { CURVE, Point, ProjectivePoint, Signature } = starkCurve;
const { CURVE, ProjectivePoint, Signature } = starkCurve;
export const utils = starkCurve.utils;
export { CURVE, Point, Signature, ProjectivePoint, getPublicKey0x as getPublicKey, getSharedSecret0x as getSharedSecret, sign0x as sign, verify0x as verify, };
export { CURVE, Signature, ProjectivePoint, getPublicKey0x as getPublicKey, getSharedSecret0x as getSharedSecret, sign0x as sign, verify0x as verify, };
const stripLeadingZeros = (s) => s.replace(/^0+/gm, '');

@@ -126,3 +132,3 @@ export const bytesToHexEth = (uint8a) => `0x${stripLeadingZeros(cutils.bytesToHex(uint8a))}`;

indexHex = '0' + indexHex;
return bytesToNumber0x(sha256(cutils.concatBytes(key, hexToBytes0x(indexHex))));
return sha256Num(cutils.concatBytes(key, hexToBytes0x(indexHex)));
}

@@ -132,4 +138,3 @@ export function grindKey(seed) {

const sha256mask = 2n ** 256n;
const Fn = Fp(CURVE.n);
const limit = sha256mask - Fn.create(sha256mask);
const limit = sha256mask - mod(sha256mask, CURVE_N);
for (let i = 0;; i++) {

@@ -139,3 +144,3 @@ const key = hashKeyWithIndex(_seed, i);

if (key < limit)
return Fn.create(key).toString(16);
return mod(key, CURVE_N).toString(16);
}

@@ -155,4 +160,4 @@ }

export function getAccountPath(layer, application, ethereumAddress, index) {
const layerNum = int31(bytesToNumber0x(sha256(layer)));
const applicationNum = int31(bytesToNumber0x(sha256(application)));
const layerNum = int31(sha256Num(layer));
const applicationNum = int31(sha256Num(application));
const eth = hexToNumber0x(ethereumAddress);

@@ -163,10 +168,10 @@ return `m/2645'/${layerNum}'/${applicationNum}'/${int31(eth)}'/${int31(eth >> 31n)}'/${index}`;

const PEDERSEN_POINTS_AFFINE = [
new Point(2089986280348253421170679821480865132823066470938446095505822317253594081284n, 1713931329540660377023406109199410414810705867260802078187082345529207694986n),
new Point(996781205833008774514500082376783249102396023663454813447423147977397232763n, 1668503676786377725805489344771023921079126552019160156920634619255970485781n),
new Point(2251563274489750535117886426533222435294046428347329203627021249169616184184n, 1798716007562728905295480679789526322175868328062420237419143593021674992973n),
new Point(2138414695194151160943305727036575959195309218611738193261179310511854807447n, 113410276730064486255102093846540133784865286929052426931474106396135072156n),
new Point(2379962749567351885752724891227938183011949129833673362440656643086021394946n, 776496453633298175483985398648758586525933812536653089401905292063708816422n),
new ProjectivePoint(2089986280348253421170679821480865132823066470938446095505822317253594081284n, 1713931329540660377023406109199410414810705867260802078187082345529207694986n, 1n),
new ProjectivePoint(996781205833008774514500082376783249102396023663454813447423147977397232763n, 1668503676786377725805489344771023921079126552019160156920634619255970485781n, 1n),
new ProjectivePoint(2251563274489750535117886426533222435294046428347329203627021249169616184184n, 1798716007562728905295480679789526322175868328062420237419143593021674992973n, 1n),
new ProjectivePoint(2138414695194151160943305727036575959195309218611738193261179310511854807447n, 113410276730064486255102093846540133784865286929052426931474106396135072156n, 1n),
new ProjectivePoint(2379962749567351885752724891227938183011949129833673362440656643086021394946n, 776496453633298175483985398648758586525933812536653089401905292063708816422n, 1n),
];
// for (const p of PEDERSEN_POINTS) p._setWindowSize(8);
const PEDERSEN_POINTS = PEDERSEN_POINTS_AFFINE.map(ProjectivePoint.fromAffine);
const PEDERSEN_POINTS = PEDERSEN_POINTS_AFFINE;
function pedersenPrecompute(p1, p2) {

@@ -210,3 +215,3 @@ const out = [];

const pt = constants[j];
if (pt.x === point.x)
if (pt.px === point.px)
throw new Error('Same point');

@@ -224,3 +229,3 @@ if ((x & 1n) !== 0n)

point = pedersenSingle(point, y, PEDERSEN_POINTS2);
return bytesToHexEth(point.toAffine().toRawBytes(true).slice(1));
return bytesToHexEth(point.toRawBytes(true).slice(1));
}

@@ -238,3 +243,62 @@ export function hashChain(data, fn = pedersen) {

export const computeHashOnElements = (data, fn = pedersen) => [0, ...data, data.length].reduce((x, y) => fn(x, y));
const MASK_250 = 2n ** 250n - 1n;
const MASK_250 = cutils.bitMask(250);
export const keccak = (data) => bytesToNumber0x(keccak_256(data)) & MASK_250;
const sha256Num = (data) => cutils.bytesToNumberBE(sha256(data));
// Poseidon hash
export const Fp253 = Fp(BigInt('14474011154664525231415395255581126252639794253786371766033694892385558855681')); // 2^253 + 2^199 + 1
export const Fp251 = Fp(BigInt('3618502788666131213697322783095070105623107215331596699973092056135872020481')); // 2^251 + 17 * 2^192 + 1
function poseidonRoundConstant(Fp, name, idx) {
const val = Fp.fromBytes(sha256(utf8ToBytes(`${name}${idx}`)));
return Fp.create(val);
}
// NOTE: doesn't check eiginvalues and possible can create unsafe matrix. But any filtration here will break compatibility with starknet
// Please use only if you really know what you doing.
// https://eprint.iacr.org/2019/458.pdf Section 2.3 (Avoiding Insecure Matrices)
export function _poseidonMDS(Fp, name, m, attempt = 0) {
const x_values = [];
const y_values = [];
for (let i = 0; i < m; i++) {
x_values.push(poseidonRoundConstant(Fp, `${name}x`, attempt * m + i));
y_values.push(poseidonRoundConstant(Fp, `${name}y`, attempt * m + i));
}
if (new Set([...x_values, ...y_values]).size !== 2 * m)
throw new Error('X and Y values are not distinct');
return x_values.map((x) => y_values.map((y) => Fp.inv(Fp.sub(x, y))));
}
const MDS_SMALL = [
[3, 1, 1],
[1, -1, 1],
[1, 1, -2],
].map((i) => i.map(BigInt));
export function poseidonBasic(opts, mds) {
validateField(opts.Fp);
if (!Number.isSafeInteger(opts.rate) || !Number.isSafeInteger(opts.capacity))
throw new Error(`Wrong poseidon opts: ${opts}`);
const m = opts.rate + opts.capacity;
const rounds = opts.roundsFull + opts.roundsPartial;
const roundConstants = [];
for (let i = 0; i < rounds; i++) {
const row = [];
for (let j = 0; j < m; j++)
row.push(poseidonRoundConstant(opts.Fp, 'Hades', m * i + j));
roundConstants.push(row);
}
return poseidon.poseidon({
...opts,
t: m,
sboxPower: 3,
reversePartialPowIdx: true,
mds,
roundConstants,
});
}
export function poseidonCreate(opts, mdsAttempt = 0) {
const m = opts.rate + opts.capacity;
if (!Number.isSafeInteger(mdsAttempt))
throw new Error(`Wrong mdsAttempt=${mdsAttempt}`);
return poseidonBasic(opts, _poseidonMDS(opts.Fp, 'HadesMDS', m, mdsAttempt));
}
export const poseidonSmall = poseidonBasic({ Fp: Fp251, rate: 2, capacity: 1, roundsFull: 8, roundsPartial: 83 }, MDS_SMALL);
export function poseidonHash(x, y, fn = poseidonSmall) {
return fn([x, y, 2n])[0];
}

@@ -7,3 +7,3 @@ /**

export declare const jubjub: import("./abstract/edwards.js").CurveFn;
export declare function groupHash(tag: Uint8Array, personalization: Uint8Array): import("./abstract/edwards.js").ExtendedPointType;
export declare function findGroupHash(m: Uint8Array, personalization: Uint8Array): import("./abstract/edwards.js").ExtendedPointType;
export declare function groupHash(tag: Uint8Array, personalization: Uint8Array): import("./abstract/edwards.js").ExtPointType;
export declare function findGroupHash(m: Uint8Array, personalization: Uint8Array): import("./abstract/edwards.js").ExtPointType;

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

// NOTE: returns ExtendedPoint, in case it will be multiplied later
let p = exports.jubjub.ExtendedPoint.fromAffine(exports.jubjub.Point.fromHex(h.digest()));
let p = exports.jubjub.ExtendedPoint.fromHex(h.digest());
// NOTE: cannot replace with isSmallOrder, returns Point*8

@@ -42,0 +42,0 @@ p = p.multiply(exports.jubjub.CURVE.h);

@@ -26,9 +26,4 @@ export declare const P192: Readonly<{

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -38,22 +33,16 @@ readonly hash: import("./abstract/utils.js").CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;
getPublicKey: (privateKey: import("./abstract/utils.js").PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
signUnhashed: (msg: Uint8Array, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
verify: (signature: import("./abstract/utils.js").Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
lowS?: boolean | undefined;
} | undefined) => boolean;
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
verify: (signature: import("./abstract/utils.js").Hex | {
r: bigint;
s: bigint;
}, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: import("./abstract/utils.js").PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: import("./abstract/utils.js").PrivKey): boolean;

@@ -89,9 +78,4 @@ hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -101,22 +85,16 @@ readonly hash: import("./abstract/utils.js").CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;
getPublicKey: (privateKey: import("./abstract/utils.js").PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
signUnhashed: (msg: Uint8Array, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
verify: (signature: import("./abstract/utils.js").Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
lowS?: boolean | undefined;
} | undefined) => boolean;
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
verify: (signature: import("./abstract/utils.js").Hex | {
r: bigint;
s: bigint;
}, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: import("./abstract/utils.js").PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: import("./abstract/utils.js").PrivKey): boolean;

@@ -123,0 +101,0 @@ hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;

@@ -26,9 +26,4 @@ export declare const P224: Readonly<{

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -38,22 +33,16 @@ readonly hash: import("./abstract/utils.js").CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;
getPublicKey: (privateKey: import("./abstract/utils.js").PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
signUnhashed: (msg: Uint8Array, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
verify: (signature: import("./abstract/utils.js").Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
lowS?: boolean | undefined;
} | undefined) => boolean;
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
verify: (signature: import("./abstract/utils.js").Hex | {
r: bigint;
s: bigint;
}, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: import("./abstract/utils.js").PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: import("./abstract/utils.js").PrivKey): boolean;

@@ -89,9 +78,4 @@ hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -101,22 +85,16 @@ readonly hash: import("./abstract/utils.js").CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;
getPublicKey: (privateKey: import("./abstract/utils.js").PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
signUnhashed: (msg: Uint8Array, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
verify: (signature: import("./abstract/utils.js").Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
lowS?: boolean | undefined;
} | undefined) => boolean;
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
verify: (signature: import("./abstract/utils.js").Hex | {
r: bigint;
s: bigint;
}, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: import("./abstract/utils.js").PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: import("./abstract/utils.js").PrivKey): boolean;

@@ -123,0 +101,0 @@ hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;

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

import * as htf from './abstract/hash-to-curve.js';
export declare const P256: Readonly<{

@@ -26,9 +27,4 @@ create: (hash: import("./abstract/utils.js").CHash) => import("./abstract/weierstrass.js").CurveFn;

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -38,22 +34,16 @@ readonly hash: import("./abstract/utils.js").CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;
getPublicKey: (privateKey: import("./abstract/utils.js").PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
signUnhashed: (msg: Uint8Array, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
verify: (signature: import("./abstract/utils.js").Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
lowS?: boolean | undefined;
} | undefined) => boolean;
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
verify: (signature: import("./abstract/utils.js").Hex | {
r: bigint;
s: bigint;
}, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: import("./abstract/utils.js").PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: import("./abstract/utils.js").PrivKey): boolean;

@@ -89,9 +79,4 @@ hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -101,22 +86,16 @@ readonly hash: import("./abstract/utils.js").CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;
getPublicKey: (privateKey: import("./abstract/utils.js").PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
signUnhashed: (msg: Uint8Array, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
verify: (signature: import("./abstract/utils.js").Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
lowS?: boolean | undefined;
} | undefined) => boolean;
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
verify: (signature: import("./abstract/utils.js").Hex | {
r: bigint;
s: bigint;
}, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: import("./abstract/utils.js").PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: import("./abstract/utils.js").PrivKey): boolean;

@@ -127,1 +106,3 @@ hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;

}>;
declare const hashToCurve: (msg: import("./abstract/utils.js").Hex, options?: htf.htfBasicOpts | undefined) => htf.H2CPoint<bigint>, encodeToCurve: (msg: import("./abstract/utils.js").Hex, options?: htf.htfBasicOpts | undefined) => htf.H2CPoint<bigint>;
export { hashToCurve, encodeToCurve };
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.secp256r1 = exports.P256 = void 0;
exports.encodeToCurve = exports.hashToCurve = exports.secp256r1 = exports.P256 = void 0;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

@@ -9,2 +9,3 @@ const _shortw_utils_js_1 = require("./_shortw_utils.js");

const weierstrass_js_1 = require("./abstract/weierstrass.js");
const htf = require("./abstract/hash-to-curve.js");
// NIST secp256r1 aka P256

@@ -33,12 +34,14 @@ // https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-256

lowS: false,
mapToCurve: (scalars) => mapSWU(scalars[0]),
htfDefaults: {
DST: 'P256_XMD:SHA-256_SSWU_RO_',
p: Fp.ORDER,
m: 1,
k: 128,
expand: 'xmd',
hash: sha256_1.sha256,
},
}, sha256_1.sha256);
exports.secp256r1 = exports.P256;
const { hashToCurve, encodeToCurve } = htf.hashToCurve(exports.secp256r1.ProjectivePoint, (scalars) => mapSWU(scalars[0]), {
DST: 'P256_XMD:SHA-256_SSWU_RO_',
encodeDST: 'P256_XMD:SHA-256_SSWU_NU_',
p: Fp.ORDER,
m: 1,
k: 128,
expand: 'xmd',
hash: sha256_1.sha256,
});
exports.hashToCurve = hashToCurve;
exports.encodeToCurve = encodeToCurve;

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

import * as htf from './abstract/hash-to-curve.js';
export declare const P384: Readonly<{

@@ -26,9 +27,4 @@ create: (hash: import("./abstract/utils.js").CHash) => import("./abstract/weierstrass.js").CurveFn;

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -38,22 +34,16 @@ readonly hash: import("./abstract/utils.js").CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;
getPublicKey: (privateKey: import("./abstract/utils.js").PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
signUnhashed: (msg: Uint8Array, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
verify: (signature: import("./abstract/utils.js").Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
lowS?: boolean | undefined;
} | undefined) => boolean;
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
verify: (signature: import("./abstract/utils.js").Hex | {
r: bigint;
s: bigint;
}, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: import("./abstract/utils.js").PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: import("./abstract/utils.js").PrivKey): boolean;

@@ -89,9 +79,4 @@ hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -101,22 +86,16 @@ readonly hash: import("./abstract/utils.js").CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;
getPublicKey: (privateKey: import("./abstract/utils.js").PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
signUnhashed: (msg: Uint8Array, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
verify: (signature: import("./abstract/utils.js").Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
lowS?: boolean | undefined;
} | undefined) => boolean;
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
verify: (signature: import("./abstract/utils.js").Hex | {
r: bigint;
s: bigint;
}, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: import("./abstract/utils.js").PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: import("./abstract/utils.js").PrivKey): boolean;

@@ -127,1 +106,3 @@ hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;

}>;
declare const hashToCurve: (msg: import("./abstract/utils.js").Hex, options?: htf.htfBasicOpts | undefined) => htf.H2CPoint<bigint>, encodeToCurve: (msg: import("./abstract/utils.js").Hex, options?: htf.htfBasicOpts | undefined) => htf.H2CPoint<bigint>;
export { hashToCurve, encodeToCurve };
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.secp384r1 = exports.P384 = void 0;
exports.encodeToCurve = exports.hashToCurve = exports.secp384r1 = exports.P384 = void 0;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

@@ -9,2 +9,3 @@ const _shortw_utils_js_1 = require("./_shortw_utils.js");

const weierstrass_js_1 = require("./abstract/weierstrass.js");
const htf = require("./abstract/hash-to-curve.js");
// NIST secp384r1 aka P384

@@ -38,12 +39,14 @@ // https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-384

lowS: false,
mapToCurve: (scalars) => mapSWU(scalars[0]),
htfDefaults: {
DST: 'P384_XMD:SHA-384_SSWU_RO_',
p: Fp.ORDER,
m: 1,
k: 192,
expand: 'xmd',
hash: sha512_1.sha384,
},
}, sha512_1.sha384);
exports.secp384r1 = exports.P384;
const { hashToCurve, encodeToCurve } = htf.hashToCurve(exports.secp384r1.ProjectivePoint, (scalars) => mapSWU(scalars[0]), {
DST: 'P384_XMD:SHA-384_SSWU_RO_',
encodeDST: 'P384_XMD:SHA-384_SSWU_NU_',
p: Fp.ORDER,
m: 1,
k: 192,
expand: 'xmd',
hash: sha512_1.sha384,
});
exports.hashToCurve = hashToCurve;
exports.encodeToCurve = encodeToCurve;
import { PrivKey } from './abstract/utils.js';
import * as htf from './abstract/hash-to-curve.js';
export declare const P521: Readonly<{

@@ -27,9 +28,4 @@ create: (hash: import("./abstract/utils.js").CHash) => import("./abstract/weierstrass.js").CurveFn;

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -39,22 +35,16 @@ readonly hash: import("./abstract/utils.js").CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
signUnhashed: (msg: Uint8Array, privKey: PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
verify: (signature: import("./abstract/utils.js").Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
lowS?: boolean | undefined;
} | undefined) => boolean;
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
verify: (signature: import("./abstract/utils.js").Hex | {
r: bigint;
s: bigint;
}, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: PrivKey): boolean;

@@ -90,9 +80,4 @@ hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -102,22 +87,16 @@ readonly hash: import("./abstract/utils.js").CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
signUnhashed: (msg: Uint8Array, privKey: PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
verify: (signature: import("./abstract/utils.js").Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
lowS?: boolean | undefined;
} | undefined) => boolean;
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
verify: (signature: import("./abstract/utils.js").Hex | {
r: bigint;
s: bigint;
}, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: PrivKey): boolean;

@@ -128,1 +107,3 @@ hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;

}>;
declare const hashToCurve: (msg: import("./abstract/utils.js").Hex, options?: htf.htfBasicOpts | undefined) => htf.H2CPoint<bigint>, encodeToCurve: (msg: import("./abstract/utils.js").Hex, options?: htf.htfBasicOpts | undefined) => htf.H2CPoint<bigint>;
export { hashToCurve, encodeToCurve };
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.secp521r1 = exports.P521 = void 0;
exports.encodeToCurve = exports.hashToCurve = exports.secp521r1 = exports.P521 = void 0;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

@@ -10,2 +10,3 @@ const _shortw_utils_js_1 = require("./_shortw_utils.js");

const weierstrass_js_1 = require("./abstract/weierstrass.js");
const htf = require("./abstract/hash-to-curve.js");
// NIST secp521r1 aka P521

@@ -39,4 +40,3 @@ // Note that it's 521, which differs from 512 of its hash function.

lowS: false,
// P521 keys could be 130, 131, 132 bytes - which doesn't play nicely.
// We ensure all keys are 132 bytes.
// P521 keys could be 130, 131, 132 bytes. We normalize to 132 bytes.
// Does not replace validation; invalid keys would still be rejected.

@@ -51,14 +51,16 @@ normalizePrivateKey(key) {

}
return key.padStart(66 * 2, '0');
return key.padStart(66 * 2, '0'); // ensure it's always 132 bytes
},
mapToCurve: (scalars) => mapSWU(scalars[0]),
htfDefaults: {
DST: 'P521_XMD:SHA-512_SSWU_RO_',
p: Fp.ORDER,
m: 1,
k: 256,
expand: 'xmd',
hash: sha512_1.sha512,
},
}, sha512_1.sha512);
exports.secp521r1 = exports.P521;
const { hashToCurve, encodeToCurve } = htf.hashToCurve(exports.secp521r1.ProjectivePoint, (scalars) => mapSWU(scalars[0]), {
DST: 'P521_XMD:SHA-512_SSWU_RO_',
encodeDST: 'P521_XMD:SHA-512_SSWU_NU_',
p: Fp.ORDER,
m: 1,
k: 256,
expand: 'xmd',
hash: sha512_1.sha512,
});
exports.hashToCurve = hashToCurve;
exports.encodeToCurve = encodeToCurve;

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

import { PointType } from './abstract/weierstrass.js';
import { Hex, PrivKey } from './abstract/utils.js';
import { ProjPointType as PointType } from './abstract/weierstrass.js';
import { Hex, bytesToNumberBE as bytesToNum, PrivKey } from './abstract/utils.js';
import * as htf from './abstract/hash-to-curve.js';
export declare const secp256k1: Readonly<{

@@ -28,9 +29,4 @@ create: (hash: import("./abstract/utils.js").CHash) => import("./abstract/weierstrass.js").CurveFn;

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: PointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: PointType<bigint>) => PointType<bigint>) | undefined;
lowS: boolean;

@@ -40,22 +36,16 @@ readonly hash: import("./abstract/utils.js").CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>;
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean | undefined) => Uint8Array;
sign: (msgHash: Hex, privKey: PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
signUnhashed: (msg: Uint8Array, privKey: PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
verify: (signature: Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
lowS?: boolean | undefined;
} | undefined) => boolean;
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
verify: (signature: Hex | {
r: bigint;
s: bigint;
}, msgHash: Hex, publicKey: Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: PrivKey): boolean;

@@ -66,12 +56,5 @@ hashToPrivateKey: (hash: Hex) => Uint8Array;

}>;
export declare function taggedHash(tag: string, ...messages: Uint8Array[]): Uint8Array;
declare class SchnorrSignature {
readonly r: bigint;
readonly s: bigint;
constructor(r: bigint, s: bigint);
static fromHex(hex: Hex): SchnorrSignature;
assertValidity(): void;
toHex(): string;
toRawBytes(): Uint8Array;
}
declare function taggedHash(tag: string, ...messages: Uint8Array[]): Uint8Array;
declare function lift_x(x: bigint): PointType<bigint>;
declare function schnorrGetPublicKey(privateKey: PrivKey): Uint8Array;
/**

@@ -84,3 +67,3 @@ * Synchronously creates Schnorr signature. Improved security: verifies itself before

*/
declare function schnorrSign(message: Hex, privateKey: PrivKey, auxRand?: Hex): Uint8Array;
declare function schnorrSign(message: Hex, privateKey: Hex, auxRand?: Hex): Uint8Array;
/**

@@ -91,7 +74,12 @@ * Verifies Schnorr signature synchronously.

export declare const schnorr: {
Signature: typeof SchnorrSignature;
getPublicKey: (privateKey: PrivKey) => Uint8Array;
getPublicKey: typeof schnorrGetPublicKey;
sign: typeof schnorrSign;
verify: typeof schnorrVerify;
utils: {
lift_x: typeof lift_x;
int: typeof bytesToNum;
taggedHash: typeof taggedHash;
};
};
export {};
declare const hashToCurve: (msg: Hex, options?: htf.htfBasicOpts | undefined) => htf.H2CPoint<bigint>, encodeToCurve: (msg: Hex, options?: htf.htfBasicOpts | undefined) => htf.H2CPoint<bigint>;
export { hashToCurve, encodeToCurve };
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.schnorr = exports.taggedHash = exports.secp256k1 = void 0;
exports.encodeToCurve = exports.hashToCurve = exports.schnorr = exports.secp256k1 = void 0;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

@@ -11,3 +11,3 @@ const sha256_1 = require("@noble/hashes/sha256");

const utils_1 = require("@noble/hashes/utils");
const hash_to_curve_js_1 = require("./abstract/hash-to-curve.js");
const htf = require("./abstract/hash-to-curve.js");
/**

@@ -26,6 +26,3 @@ * secp256k1 belongs to Koblitz curves: it has efficiently computable endomorphism.

/**
* Allows to compute square root √y 2x faster.
* To calculate √y, we need to exponentiate it to a very big number:
* `y² = x³ + ax + b; y = y² ^ (p+1)/4`
* We are unwrapping the loop and multiplying it bit-by-bit.
* √n = n^((p+1)/4) for fields p = 3 mod 4. We unwrap the loop and multiply bit-by-bit.
* (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00]

@@ -53,3 +50,3 @@ */

const root = (0, modular_js_1.pow2)(t2, _2n, P);
if (!Fp.equals(Fp.square(root), y))
if (!Fp.eql(Fp.sqr(root), y))
throw new Error('Cannot find square root');

@@ -59,36 +56,2 @@ return root;

const Fp = (0, modular_js_1.Fp)(secp256k1P, undefined, undefined, { sqrt: sqrtMod });
const isoMap = (0, hash_to_curve_js_1.isogenyMap)(Fp, [
// xNum
[
'0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa8c7',
'0x7d3d4c80bc321d5b9f315cea7fd44c5d595d2fc0bf63b92dfff1044f17c6581',
'0x534c328d23f234e6e2a413deca25caece4506144037c40314ecbd0b53d9dd262',
'0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa88c',
],
// xDen
[
'0xd35771193d94918a9ca34ccbb7b640dd86cd409542f8487d9fe6b745781eb49b',
'0xedadc6f64383dc1df7c4b2d51b54225406d36b641f5e41bbc52a56612a8c6d14',
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
],
// yNum
[
'0x4bda12f684bda12f684bda12f684bda12f684bda12f684bda12f684b8e38e23c',
'0xc75e0c32d5cb7c0fa9d0a54b12a0a6d5647ab046d686da6fdffc90fc201d71a3',
'0x29a6194691f91a73715209ef6512e576722830a201be2018a765e85a9ecee931',
'0x2f684bda12f684bda12f684bda12f684bda12f684bda12f684bda12f38e38d84',
],
// yDen
[
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff93b',
'0x7a06534bb8bdb49fd5e9e6632722c2989467c1bfc8e8d978dfb425d2685c2573',
'0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f',
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
],
].map((i) => i.map((j) => BigInt(j))));
const mapSWU = (0, weierstrass_js_1.mapToCurveSimpleSWU)(Fp, {
A: BigInt('0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533'),
B: BigInt('1771'),
Z: Fp.create(BigInt('-11')),
});
exports.secp256k1 = (0, _shortw_utils_js_1.createCurve)({

@@ -136,47 +99,9 @@ // Params: a, b

},
mapToCurve: (scalars) => {
const { x, y } = mapSWU(Fp.create(scalars[0]));
return isoMap(x, y);
},
htfDefaults: {
DST: 'secp256k1_XMD:SHA-256_SSWU_RO_',
p: Fp.ORDER,
m: 1,
k: 128,
expand: 'xmd',
hash: sha256_1.sha256,
},
}, sha256_1.sha256);
// Schnorr
// Schnorr signatures are superior to ECDSA from above.
// Below is Schnorr-specific code as per BIP0340.
// https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
const _0n = BigInt(0);
const numTo32b = exports.secp256k1.utils._bigintToBytes;
const numTo32bStr = exports.secp256k1.utils._bigintToString;
const normalizePrivateKey = exports.secp256k1.utils._normalizePrivateKey;
// TODO: export?
function normalizePublicKey(publicKey) {
if (publicKey instanceof exports.secp256k1.Point) {
publicKey.assertValidity();
return publicKey;
}
else {
const bytes = (0, utils_js_1.ensureBytes)(publicKey);
// Schnorr is 32 bytes
if (bytes.length !== 32)
throw new Error('Schnorr pubkeys must be 32 bytes');
const x = (0, utils_js_1.bytesToNumberBE)(bytes);
if (!isValidFieldElement(x))
throw new Error('Point is not on curve');
const y2 = exports.secp256k1.utils._weierstrassEquation(x); // y² = x³ + ax + b
let y = sqrtMod(y2); // y = y² ^ (p+1)/4
const isYOdd = (y & _1n) === _1n;
// Schnorr
if (isYOdd)
y = exports.secp256k1.CURVE.Fp.negate(y);
const point = new exports.secp256k1.Point(x, y);
point.assertValidity();
return point;
}
}
const isWithinCurveOrder = exports.secp256k1.utils._isWithinCurveOrder;
const isValidFieldElement = exports.secp256k1.utils._isValidFieldElement;
const fe = (x) => typeof x === 'bigint' && _0n < x && x < secp256k1P;
const ge = (x) => typeof x === 'bigint' && _0n < x && x < secp256k1N;
const TAGS = {

@@ -198,42 +123,34 @@ challenge: 'BIP0340/challenge',

}
exports.taggedHash = taggedHash;
const toRawX = (point) => point.toRawBytes(true).slice(1);
// Schnorr signatures are superior to ECDSA from above.
// Below is Schnorr-specific code as per BIP0340.
function schnorrChallengeFinalize(ch) {
return (0, modular_js_1.mod)((0, utils_js_1.bytesToNumberBE)(ch), exports.secp256k1.CURVE.n);
}
// Do we need this at all for Schnorr?
class SchnorrSignature {
constructor(r, s) {
this.r = r;
this.s = s;
this.assertValidity();
}
static fromHex(hex) {
const bytes = (0, utils_js_1.ensureBytes)(hex);
const len = 32; // group length
if (bytes.length !== 2 * len)
throw new TypeError(`SchnorrSignature.fromHex: expected ${2 * len} bytes, not ${bytes.length}`);
const r = (0, utils_js_1.bytesToNumberBE)(bytes.subarray(0, len));
const s = (0, utils_js_1.bytesToNumberBE)(bytes.subarray(len, 2 * len));
return new SchnorrSignature(r, s);
}
assertValidity() {
const { r, s } = this;
if (!isValidFieldElement(r) || !isWithinCurveOrder(s))
throw new Error('Invalid signature');
}
toHex() {
return numTo32bStr(this.r) + numTo32bStr(this.s);
}
toRawBytes() {
return (0, utils_js_1.hexToBytes)(this.toHex());
}
}
const numTo32b = (n) => (0, utils_js_1.numberToBytesBE)(n, 32);
const modN = (x) => (0, modular_js_1.mod)(x, secp256k1N);
const _Point = exports.secp256k1.ProjectivePoint;
const Gmul = (priv) => _Point.fromPrivateKey(priv);
const GmulAdd = (Q, a, b) => _Point.BASE.multiplyAndAddUnsafe(Q, a, b);
function schnorrGetScalar(priv) {
const point = exports.secp256k1.Point.fromPrivateKey(priv);
const scalar = point.hasEvenY() ? priv : exports.secp256k1.CURVE.n - priv;
// Let d' = int(sk)
// Fail if d' = 0 or d' ≥ n
// Let P = d'⋅G
// Let d = d' if has_even_y(P), otherwise let d = n - d' .
const point = Gmul(priv);
const scalar = point.hasEvenY() ? priv : modN(-priv);
return { point, scalar, x: toRawX(point) };
}
function lift_x(x) {
if (!fe(x))
throw new Error('bad x: need 0 < x < p'); // Fail if x ≥ p.
const c = (0, modular_js_1.mod)(x * x * x + BigInt(7), secp256k1P); // Let c = x³ + 7 mod p.
let y = sqrtMod(c); // Let y = c^(p+1)/4 mod p.
if (y % 2n !== 0n)
y = (0, modular_js_1.mod)(-y, secp256k1P); // Return the unique point P such that x(P) = x and
const p = new _Point(x, y, _1n); // y(P) = y if y mod 2 = 0 or y(P) = p-y otherwise.
p.assertValidity();
return p;
}
function challenge(...args) {
return modN((0, utils_js_1.bytesToNumberBE)(taggedHash(TAGS.challenge, ...args)));
}
function schnorrGetPublicKey(privateKey) {
return toRawX(Gmul(privateKey)); // Let d' = int(sk). Fail if d' = 0 or d' ≥ n. Return bytes(d'⋅G)
}
/**

@@ -248,19 +165,19 @@ * Synchronously creates Schnorr signature. Improved security: verifies itself before

if (message == null)
throw new TypeError(`sign: Expected valid message, not "${message}"`);
throw new Error(`sign: Expected valid message, not "${message}"`);
const m = (0, utils_js_1.ensureBytes)(message);
// checks for isWithinCurveOrder
const { x: px, scalar: d } = schnorrGetScalar(normalizePrivateKey(privateKey));
const rand = (0, utils_js_1.ensureBytes)(auxRand);
if (rand.length !== 32)
throw new TypeError('sign: Expected 32 bytes of aux randomness');
const tag = taggedHash;
const t0h = tag(TAGS.aux, rand);
const t = numTo32b(d ^ (0, utils_js_1.bytesToNumberBE)(t0h));
const k0h = tag(TAGS.nonce, t, px, m);
const k0 = (0, modular_js_1.mod)((0, utils_js_1.bytesToNumberBE)(k0h), exports.secp256k1.CURVE.n);
if (k0 === _0n)
throw new Error('sign: Creation of signature failed. k is zero');
const { point: R, x: rx, scalar: k } = schnorrGetScalar(k0);
const e = schnorrChallengeFinalize(tag(TAGS.challenge, rx, px, m));
const sig = new SchnorrSignature(R.x, (0, modular_js_1.mod)(k + e * d, exports.secp256k1.CURVE.n)).toRawBytes();
const { x: px, scalar: d } = schnorrGetScalar((0, utils_js_1.bytesToNumberBE)((0, utils_js_1.ensureBytes)(privateKey, 32)));
const a = (0, utils_js_1.ensureBytes)(auxRand, 32); // Auxiliary random data a: a 32-byte array
// TODO: replace with proper xor?
const t = numTo32b(d ^ (0, utils_js_1.bytesToNumberBE)(taggedHash(TAGS.aux, a))); // Let t be the byte-wise xor of bytes(d) and hash/aux(a)
const rand = taggedHash(TAGS.nonce, t, px, m); // Let rand = hash/nonce(t || bytes(P) || m)
const k_ = modN((0, utils_js_1.bytesToNumberBE)(rand)); // Let k' = int(rand) mod n
if (k_ === _0n)
throw new Error('sign failed: k is zero'); // Fail if k' = 0.
const { point: R, x: rx, scalar: k } = schnorrGetScalar(k_); // Let R = k'⋅G.
const e = challenge(rx, px, m); // Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
const sig = new Uint8Array(64); // Let sig = bytes(R) || bytes((k + ed) mod n).
sig.set(numTo32b(R.px), 0);
sig.set(numTo32b(modN(k + e * d)), 32);
// If Verify(bytes(P), m, sig) (see below) returns failure, abort
if (!schnorrVerify(sig, m, px))

@@ -275,17 +192,16 @@ throw new Error('sign: Invalid signature produced');

try {
const raw = signature instanceof SchnorrSignature;
const sig = raw ? signature : SchnorrSignature.fromHex(signature);
if (raw)
sig.assertValidity(); // just in case
const { r, s } = sig;
const P = lift_x((0, utils_js_1.bytesToNumberBE)((0, utils_js_1.ensureBytes)(publicKey, 32))); // P = lift_x(int(pk)); fail if that fails
const sig = (0, utils_js_1.ensureBytes)(signature, 64);
const r = (0, utils_js_1.bytesToNumberBE)(sig.subarray(0, 32)); // Let r = int(sig[0:32]); fail if r ≥ p.
if (!fe(r))
return false;
const s = (0, utils_js_1.bytesToNumberBE)(sig.subarray(32, 64)); // Let s = int(sig[32:64]); fail if s ≥ n.
if (!ge(s))
return false;
const m = (0, utils_js_1.ensureBytes)(message);
const P = normalizePublicKey(publicKey);
const e = schnorrChallengeFinalize(taggedHash(TAGS.challenge, numTo32b(r), toRawX(P), m));
// Finalize
// R = s⋅G - e⋅P
// -eP == (n-e)P
const R = exports.secp256k1.Point.BASE.multiplyAndAddUnsafe(P, normalizePrivateKey(s), (0, modular_js_1.mod)(-e, exports.secp256k1.CURVE.n));
if (!R || !R.hasEvenY() || R.x !== r)
return false;
return true;
const e = challenge(numTo32b(r), toRawX(P), m); // int(challenge(bytes(r)||bytes(P)||m)) mod n
const R = GmulAdd(P, s, modN(-e)); // R = s⋅G - e⋅P
if (!R || !R.hasEvenY() || R.toAffine().x !== r)
return false; // -eP == (n-e)P
return true; // Fail if is_infinite(R) / not has_even_y(R) / x(R) ≠ r.
}

@@ -297,7 +213,55 @@ catch (error) {

exports.schnorr = {
Signature: SchnorrSignature,
// Schnorr's pubkey is just `x` of Point (BIP340)
getPublicKey: (privateKey) => toRawX(exports.secp256k1.Point.fromPrivateKey(privateKey)),
getPublicKey: schnorrGetPublicKey,
sign: schnorrSign,
verify: schnorrVerify,
utils: { lift_x, int: utils_js_1.bytesToNumberBE, taggedHash },
};
const isoMap = htf.isogenyMap(Fp, [
// xNum
[
'0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa8c7',
'0x7d3d4c80bc321d5b9f315cea7fd44c5d595d2fc0bf63b92dfff1044f17c6581',
'0x534c328d23f234e6e2a413deca25caece4506144037c40314ecbd0b53d9dd262',
'0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa88c',
],
// xDen
[
'0xd35771193d94918a9ca34ccbb7b640dd86cd409542f8487d9fe6b745781eb49b',
'0xedadc6f64383dc1df7c4b2d51b54225406d36b641f5e41bbc52a56612a8c6d14',
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
],
// yNum
[
'0x4bda12f684bda12f684bda12f684bda12f684bda12f684bda12f684b8e38e23c',
'0xc75e0c32d5cb7c0fa9d0a54b12a0a6d5647ab046d686da6fdffc90fc201d71a3',
'0x29a6194691f91a73715209ef6512e576722830a201be2018a765e85a9ecee931',
'0x2f684bda12f684bda12f684bda12f684bda12f684bda12f684bda12f38e38d84',
],
// yDen
[
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff93b',
'0x7a06534bb8bdb49fd5e9e6632722c2989467c1bfc8e8d978dfb425d2685c2573',
'0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f',
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
],
].map((i) => i.map((j) => BigInt(j))));
const mapSWU = (0, weierstrass_js_1.mapToCurveSimpleSWU)(Fp, {
A: BigInt('0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533'),
B: BigInt('1771'),
Z: Fp.create(BigInt('-11')),
});
const { hashToCurve, encodeToCurve } = htf.hashToCurve(exports.secp256k1.ProjectivePoint, (scalars) => {
const { x, y } = mapSWU(Fp.create(scalars[0]));
return isoMap(x, y);
}, {
DST: 'secp256k1_XMD:SHA-256_SSWU_RO_',
encodeDST: 'secp256k1_XMD:SHA-256_SSWU_NU_',
p: Fp.ORDER,
m: 1,
k: 128,
expand: 'xmd',
hash: sha256_1.sha256,
});
exports.hashToCurve = hashToCurve;
exports.encodeToCurve = encodeToCurve;

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

import { ProjectivePointType } from './abstract/weierstrass.js';
import { ProjPointType } from './abstract/weierstrass.js';
import * as cutils from './abstract/utils.js';
declare type ProjectivePoint = ProjectivePointType<bigint>;
import { Field } from './abstract/modular.js';
declare type ProjectivePoint = ProjPointType<bigint>;
export declare const starkCurve: import("./abstract/weierstrass.js").CurveFn;

@@ -12,3 +13,3 @@ declare function getPublicKey0x(privKey: Hex, isCompressed?: boolean): Uint8Array;

readonly nByteLength: number;
readonly Fp: import("./abstract/modular.js").Field<bigint>;
readonly Fp: Field<bigint>;
readonly n: bigint;

@@ -33,9 +34,4 @@ readonly h: bigint;

} | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: ProjectivePointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: ProjectivePointType<bigint>) => ProjectivePointType<bigint>) | undefined;
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
readonly mapToCurve?: ((scalar: bigint[]) => {
x: bigint;
y: bigint;
}) | undefined;
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: ProjPointType<bigint>) => boolean) | undefined;
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: ProjPointType<bigint>) => ProjPointType<bigint>) | undefined;
lowS: boolean;

@@ -45,12 +41,7 @@ readonly hash: cutils.CHash;

readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
}>, Point: import("./abstract/weierstrass.js").PointConstructor<bigint>, ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, Signature: import("./abstract/weierstrass.js").SignatureConstructor;
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
}>, ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>, Signature: import("./abstract/weierstrass.js").SignatureConstructor;
export declare const utils: {
_bigintToBytes: (num: bigint) => Uint8Array;
_bigintToString: (num: bigint) => string;
_normalizePrivateKey: (key: cutils.PrivKey) => bigint;
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
_isWithinCurveOrder: (num: bigint) => boolean;
_isValidFieldElement: (num: bigint) => boolean;
_weierstrassEquation: (x: bigint) => bigint;
isValidPrivateKey(privateKey: cutils.PrivKey): boolean;

@@ -60,3 +51,3 @@ hashToPrivateKey: (hash: cutils.Hex) => Uint8Array;

};
export { CURVE, Point, Signature, ProjectivePoint, getPublicKey0x as getPublicKey, getSharedSecret0x as getSharedSecret, sign0x as sign, verify0x as verify, };
export { CURVE, Signature, ProjectivePoint, getPublicKey0x as getPublicKey, getSharedSecret0x as getSharedSecret, sign0x as sign, verify0x as verify, };
export declare const bytesToHexEth: (uint8a: Uint8Array) => string;

@@ -75,1 +66,27 @@ export declare const strip0x: (hex: string) => string;

export declare const keccak: (data: Uint8Array) => bigint;
export declare const Fp253: Readonly<Field<bigint> & Required<Pick<Field<bigint>, "isOdd">>>;
export declare const Fp251: Readonly<Field<bigint> & Required<Pick<Field<bigint>, "isOdd">>>;
export declare function _poseidonMDS(Fp: Field<bigint>, name: string, m: number, attempt?: number): bigint[][];
export declare type PoseidonOpts = {
Fp: Field<bigint>;
rate: number;
capacity: number;
roundsFull: number;
roundsPartial: number;
};
export declare function poseidonBasic(opts: PoseidonOpts, mds: bigint[][]): {
(values: bigint[]): bigint[];
roundConstants: bigint[][];
};
export declare function poseidonCreate(opts: PoseidonOpts, mdsAttempt?: number): {
(values: bigint[]): bigint[];
roundConstants: bigint[][];
};
export declare const poseidonSmall: {
(values: bigint[]): bigint[];
roundConstants: bigint[][];
};
export declare function poseidonHash(x: bigint, y: bigint, fn?: {
(values: bigint[]): bigint[];
roundConstants: bigint[][];
}): bigint;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.keccak = exports.computeHashOnElements = exports.hashChain = exports.pedersen = exports.getAccountPath = exports.ethSigToPrivate = exports.getStarkKey = exports.grindKey = exports.numberToHexEth = exports.strip0x = exports.bytesToHexEth = exports.verify = exports.sign = exports.getSharedSecret = exports.getPublicKey = exports.ProjectivePoint = exports.Signature = exports.Point = exports.CURVE = exports.utils = exports.starkCurve = void 0;
exports.poseidonHash = exports.poseidonSmall = exports.poseidonCreate = exports.poseidonBasic = exports._poseidonMDS = exports.Fp251 = exports.Fp253 = exports.keccak = exports.computeHashOnElements = exports.hashChain = exports.pedersen = exports.getAccountPath = exports.ethSigToPrivate = exports.getStarkKey = exports.grindKey = exports.numberToHexEth = exports.strip0x = exports.bytesToHexEth = exports.verify = exports.sign = exports.getSharedSecret = exports.getPublicKey = exports.ProjectivePoint = exports.Signature = exports.CURVE = exports.utils = exports.starkCurve = void 0;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */

@@ -11,2 +11,4 @@ const sha3_1 = require("@noble/hashes/sha3");

const _shortw_utils_js_1 = require("./_shortw_utils.js");
const poseidon = require("./abstract/poseidon.js");
const utils_1 = require("@noble/hashes/utils");
// Stark-friendly elliptic curve

@@ -16,2 +18,11 @@ // https://docs.starkware.co/starkex/stark-curve.html

const nBitLength = 252;
// Copy-pasted from weierstrass.ts
function bits2int(bytes) {
const delta = bytes.length * 8 - nBitLength;
const num = cutils.bytesToNumberBE(bytes);
return delta > 0 ? num >> BigInt(delta) : num;
}
function bits2int_modN(bytes) {
return (0, modular_js_1.mod)(bits2int(bytes), CURVE_N);
}
exports.starkCurve = (0, weierstrass_js_1.weierstrass)({

@@ -34,23 +45,18 @@ // Params: a, b

...(0, _shortw_utils_js_1.getHash)(sha256_1.sha256),
truncateHash: (hash, truncateOnly = false) => {
// TODO: cleanup, ugly code
// Fix truncation
if (!truncateOnly) {
let hashS = bytesToNumber0x(hash).toString(16);
if (hashS.length === 63) {
hashS += '0';
hash = hexToBytes0x(hashS);
}
// Custom truncation routines for stark curve
bits2int: (bytes) => {
while (bytes[0] === 0)
bytes = bytes.subarray(1);
return bits2int(bytes);
},
bits2int_modN: (bytes) => {
let hashS = cutils.bytesToNumberBE(bytes).toString(16);
if (hashS.length === 63) {
hashS += '0';
bytes = hexToBytes0x(hashS);
}
// Truncate zero bytes on left (compat with elliptic)
while (hash[0] === 0)
hash = hash.subarray(1);
const byteLength = hash.length;
const delta = byteLength * 8 - nBitLength; // size of curve.n (252 bits)
let h = hash.length ? bytesToNumber0x(hash) : 0n;
if (delta > 0)
h = h >> BigInt(delta);
if (!truncateOnly && h >= CURVE_N)
h -= CURVE_N;
return h;
while (bytes[0] === 0)
bytes = bytes.subarray(1);
return bits2int_modN(bytes);
},

@@ -61,3 +67,3 @@ });

if (typeof hex !== 'string') {
throw new TypeError('hexToBytes: expected string, got ' + typeof hex);
throw new Error('hexToBytes: expected string, got ' + typeof hex);
}

@@ -82,3 +88,3 @@ hex = (0, exports.strip0x)(hex);

if (typeof hex !== 'string') {
throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
throw new Error('hexToNumber: expected string, got ' + typeof hex);
}

@@ -98,3 +104,3 @@ // Big Endian

function normalizePrivateKey(privKey) {
return cutils.bytesToHex(ensureBytes0x(privKey)).padStart(32 * 2, '0');
return cutils.bytesToHex(ensureBytes0x(privKey)).padStart(64, '0');
}

@@ -120,5 +126,4 @@ function getPublicKey0x(privKey, isCompressed) {

exports.verify = verify0x;
const { CURVE, Point, ProjectivePoint, Signature } = exports.starkCurve;
const { CURVE, ProjectivePoint, Signature } = exports.starkCurve;
exports.CURVE = CURVE;
exports.Point = Point;
exports.ProjectivePoint = ProjectivePoint;

@@ -139,3 +144,3 @@ exports.Signature = Signature;

indexHex = '0' + indexHex;
return bytesToNumber0x((0, sha256_1.sha256)(cutils.concatBytes(key, hexToBytes0x(indexHex))));
return sha256Num(cutils.concatBytes(key, hexToBytes0x(indexHex)));
}

@@ -145,4 +150,3 @@ function grindKey(seed) {

const sha256mask = 2n ** 256n;
const Fn = (0, modular_js_1.Fp)(CURVE.n);
const limit = sha256mask - Fn.create(sha256mask);
const limit = sha256mask - (0, modular_js_1.mod)(sha256mask, CURVE_N);
for (let i = 0;; i++) {

@@ -152,3 +156,3 @@ const key = hashKeyWithIndex(_seed, i);

if (key < limit)
return Fn.create(key).toString(16);
return (0, modular_js_1.mod)(key, CURVE_N).toString(16);
}

@@ -171,4 +175,4 @@ }

function getAccountPath(layer, application, ethereumAddress, index) {
const layerNum = int31(bytesToNumber0x((0, sha256_1.sha256)(layer)));
const applicationNum = int31(bytesToNumber0x((0, sha256_1.sha256)(application)));
const layerNum = int31(sha256Num(layer));
const applicationNum = int31(sha256Num(application));
const eth = hexToNumber0x(ethereumAddress);

@@ -180,10 +184,10 @@ return `m/2645'/${layerNum}'/${applicationNum}'/${int31(eth)}'/${int31(eth >> 31n)}'/${index}`;

const PEDERSEN_POINTS_AFFINE = [
new Point(2089986280348253421170679821480865132823066470938446095505822317253594081284n, 1713931329540660377023406109199410414810705867260802078187082345529207694986n),
new Point(996781205833008774514500082376783249102396023663454813447423147977397232763n, 1668503676786377725805489344771023921079126552019160156920634619255970485781n),
new Point(2251563274489750535117886426533222435294046428347329203627021249169616184184n, 1798716007562728905295480679789526322175868328062420237419143593021674992973n),
new Point(2138414695194151160943305727036575959195309218611738193261179310511854807447n, 113410276730064486255102093846540133784865286929052426931474106396135072156n),
new Point(2379962749567351885752724891227938183011949129833673362440656643086021394946n, 776496453633298175483985398648758586525933812536653089401905292063708816422n),
new ProjectivePoint(2089986280348253421170679821480865132823066470938446095505822317253594081284n, 1713931329540660377023406109199410414810705867260802078187082345529207694986n, 1n),
new ProjectivePoint(996781205833008774514500082376783249102396023663454813447423147977397232763n, 1668503676786377725805489344771023921079126552019160156920634619255970485781n, 1n),
new ProjectivePoint(2251563274489750535117886426533222435294046428347329203627021249169616184184n, 1798716007562728905295480679789526322175868328062420237419143593021674992973n, 1n),
new ProjectivePoint(2138414695194151160943305727036575959195309218611738193261179310511854807447n, 113410276730064486255102093846540133784865286929052426931474106396135072156n, 1n),
new ProjectivePoint(2379962749567351885752724891227938183011949129833673362440656643086021394946n, 776496453633298175483985398648758586525933812536653089401905292063708816422n, 1n),
];
// for (const p of PEDERSEN_POINTS) p._setWindowSize(8);
const PEDERSEN_POINTS = PEDERSEN_POINTS_AFFINE.map(ProjectivePoint.fromAffine);
const PEDERSEN_POINTS = PEDERSEN_POINTS_AFFINE;
function pedersenPrecompute(p1, p2) {

@@ -227,3 +231,3 @@ const out = [];

const pt = constants[j];
if (pt.x === point.x)
if (pt.px === point.px)
throw new Error('Same point');

@@ -241,3 +245,3 @@ if ((x & 1n) !== 0n)

point = pedersenSingle(point, y, PEDERSEN_POINTS2);
return (0, exports.bytesToHexEth)(point.toAffine().toRawBytes(true).slice(1));
return (0, exports.bytesToHexEth)(point.toRawBytes(true).slice(1));
}

@@ -258,4 +262,67 @@ exports.pedersen = pedersen;

exports.computeHashOnElements = computeHashOnElements;
const MASK_250 = 2n ** 250n - 1n;
const MASK_250 = cutils.bitMask(250);
const keccak = (data) => bytesToNumber0x((0, sha3_1.keccak_256)(data)) & MASK_250;
exports.keccak = keccak;
const sha256Num = (data) => cutils.bytesToNumberBE((0, sha256_1.sha256)(data));
// Poseidon hash
exports.Fp253 = (0, modular_js_1.Fp)(BigInt('14474011154664525231415395255581126252639794253786371766033694892385558855681')); // 2^253 + 2^199 + 1
exports.Fp251 = (0, modular_js_1.Fp)(BigInt('3618502788666131213697322783095070105623107215331596699973092056135872020481')); // 2^251 + 17 * 2^192 + 1
function poseidonRoundConstant(Fp, name, idx) {
const val = Fp.fromBytes((0, sha256_1.sha256)((0, utils_1.utf8ToBytes)(`${name}${idx}`)));
return Fp.create(val);
}
// NOTE: doesn't check eiginvalues and possible can create unsafe matrix. But any filtration here will break compatibility with starknet
// Please use only if you really know what you doing.
// https://eprint.iacr.org/2019/458.pdf Section 2.3 (Avoiding Insecure Matrices)
function _poseidonMDS(Fp, name, m, attempt = 0) {
const x_values = [];
const y_values = [];
for (let i = 0; i < m; i++) {
x_values.push(poseidonRoundConstant(Fp, `${name}x`, attempt * m + i));
y_values.push(poseidonRoundConstant(Fp, `${name}y`, attempt * m + i));
}
if (new Set([...x_values, ...y_values]).size !== 2 * m)
throw new Error('X and Y values are not distinct');
return x_values.map((x) => y_values.map((y) => Fp.inv(Fp.sub(x, y))));
}
exports._poseidonMDS = _poseidonMDS;
const MDS_SMALL = [
[3, 1, 1],
[1, -1, 1],
[1, 1, -2],
].map((i) => i.map(BigInt));
function poseidonBasic(opts, mds) {
(0, modular_js_1.validateField)(opts.Fp);
if (!Number.isSafeInteger(opts.rate) || !Number.isSafeInteger(opts.capacity))
throw new Error(`Wrong poseidon opts: ${opts}`);
const m = opts.rate + opts.capacity;
const rounds = opts.roundsFull + opts.roundsPartial;
const roundConstants = [];
for (let i = 0; i < rounds; i++) {
const row = [];
for (let j = 0; j < m; j++)
row.push(poseidonRoundConstant(opts.Fp, 'Hades', m * i + j));
roundConstants.push(row);
}
return poseidon.poseidon({
...opts,
t: m,
sboxPower: 3,
reversePartialPowIdx: true,
mds,
roundConstants,
});
}
exports.poseidonBasic = poseidonBasic;
function poseidonCreate(opts, mdsAttempt = 0) {
const m = opts.rate + opts.capacity;
if (!Number.isSafeInteger(mdsAttempt))
throw new Error(`Wrong mdsAttempt=${mdsAttempt}`);
return poseidonBasic(opts, _poseidonMDS(opts.Fp, 'HadesMDS', m, mdsAttempt));
}
exports.poseidonCreate = poseidonCreate;
exports.poseidonSmall = poseidonBasic({ Fp: exports.Fp251, rate: 2, capacity: 1, roundsFull: 8, roundsPartial: 83 }, MDS_SMALL);
function poseidonHash(x, y, fn = exports.poseidonSmall) {
return fn([x, y, 2n])[0];
}
exports.poseidonHash = poseidonHash;
{
"name": "@noble/curves",
"version": "0.5.2",
"version": "0.6.0",
"description": "Minimal, auditable JS implementation of elliptic curve cryptography",

@@ -9,3 +9,3 @@ "files": [

"scripts": {
"bench": "node benchmark/index.js",
"bench": "cd benchmark; node index.js",
"build": "tsc && tsc -p tsconfig.esm.json",

@@ -36,3 +36,3 @@ "build:release": "rollup -c rollup.config.js",

"micro-should": "0.3.0",
"prettier": "2.6.2",
"prettier": "2.8.3",
"rollup": "2.75.5",

@@ -78,6 +78,6 @@ "typescript": "4.7.3"

},
"./abstract/group": {
"types": "./lib/abstract/group.d.ts",
"import": "./lib/esm/abstract/group.js",
"default": "./lib/abstract/group.js"
"./abstract/curve": {
"types": "./lib/abstract/curve.d.ts",
"import": "./lib/esm/abstract/curve.js",
"default": "./lib/abstract/curve.js"
},

@@ -89,2 +89,7 @@ "./abstract/utils": {

},
"./abstract/poseidon": {
"types": "./lib/abstract/poseidon.d.ts",
"import": "./lib/esm/abstract/poseidon.js",
"default": "./lib/abstract/poseidon.js"
},
"./_shortw_utils": {

@@ -196,2 +201,2 @@ "types": "./lib/_shortw_utils.d.ts",

]
}
}

@@ -9,3 +9,5 @@ # noble-curves

for encoding or hashing an arbitrary string to a point on an elliptic curve
- Auditable, [fast](#speed)
- [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash
- Auditable
- 🏎 [Ultra-fast](#speed), hand-optimized for caveats of JS engines
- 🔍 Unique tests ensure correctness. Wycheproof vectors included

@@ -28,3 +30,2 @@ - 🔻 Tree-shaking-friendly: there is no entry point, which ensures small size of your app

which had security audits and were developed from 2019 to 2022.
The goal is to replace them with lean UMD builds based on single-codebase noble-curves.

@@ -93,2 +94,3 @@ ### This library belongs to _noble_ crypto

- [abstract/hash-to-curve: Hashing strings to curve points](#abstracthash-to-curve-hashing-strings-to-curve-points)
- [abstract/poseidon: Poseidon hash](#abstractposeidon-poseidon-hash)
- [abstract/modular](#abstractmodular)

@@ -308,9 +310,8 @@ - [abstract/utils](#abstractutils)

getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
getSharedSecret: (privateA: PrivKey, publicB: PubKey, isCompressed?: boolean) => Uint8Array;
getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
signUnhashed: (msg: Uint8Array, privKey: PrivKey, opts?: SignOpts) => SignatureType;
verify: (
signature: Hex | SignatureType,
msgHash: Hex,
publicKey: PubKey,
publicKey: Hex,
opts?: { lowS?: boolean }

@@ -377,2 +378,26 @@ ) => boolean;

### abstract/poseidon: Poseidon hash
Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash.
There are many poseidon instances with different constants. We don't provide them,
but we provide ability to specify them manually. For actual usage, check out
stark curve source code.
```ts
import { poseidon } from '@noble/curves/abstract/poseidon';
type PoseidonOpts = {
Fp: Field<bigint>;
t: number;
roundsFull: number;
roundsPartial: number;
sboxPower?: number;
reversePartialPowIdx?: boolean; // Hack for stark
mds: bigint[][];
roundConstants: bigint[][];
};
const instance = poseidon(opts: PoseidonOpts);
```
### abstract/modular

@@ -467,2 +492,21 @@

## Upgrading
Differences from @noble/secp256k1 1.7:
1. Different double() formula (but same addition)
2. Different sqrt() function
3. DRBG supports outputLen bigger than outputLen of hmac
4. Support for different hash functions
Differences from @noble/ed25519 1.7:
1. Variable field element lengths between EDDSA/ECDH:
EDDSA (RFC8032) is 456 bits / 57 bytes, ECDH (RFC7748) is 448 bits / 56 bytes
2. Different addition formula (doubling is same)
3. uvRatio differs between curves (half-expected, not only pow fn changes)
4. Point decompression code is different (unexpected), now using generalized formula
5. Domain function was no-op for ed25519, but adds some data even with empty context for ed448
## Contributing & testing

@@ -469,0 +513,0 @@

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