secp256k1 & other implementations: reduce bundle size by 20% by using PURE.
PURE annotation helps bundlers during tree-shaking and eliminates dead code. * secp256k1: 75.4kb => 62.3kb * ed25519: 67.5kb => 51.1kb * ed448: 55.1kb => 44.0kb * p256: 67.8kb => 59.8kb * p384: 75.4kb => 67.4kb * p521: 75.8kb => 67.8kb
This commit is contained in:
parent
648fd2cc07
commit
ff5b231e31
@ -12,7 +12,7 @@ import {
|
||||
Hex,
|
||||
numberToBytesLE,
|
||||
} from './abstract/utils.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
import { createHasher, htfBasicOpts, expand_message_xmd } from './abstract/hash-to-curve.js';
|
||||
import { AffinePoint } from './abstract/curve.js';
|
||||
|
||||
/**
|
||||
@ -142,7 +142,8 @@ export const ed25519ph = twistedEdwards({
|
||||
prehash: sha512,
|
||||
});
|
||||
|
||||
export const x25519 = montgomery({
|
||||
export const x25519 = /* @__PURE__ */ (() =>
|
||||
montgomery({
|
||||
P: ED25519_P,
|
||||
a: BigInt(486662),
|
||||
montgomeryBits: 255, // n is 253 bits
|
||||
@ -156,7 +157,7 @@ export const x25519 = montgomery({
|
||||
},
|
||||
adjustScalarBytes,
|
||||
randomBytes,
|
||||
});
|
||||
}))();
|
||||
|
||||
/**
|
||||
* Converts ed25519 public key to x25519 public key. Uses formula:
|
||||
@ -260,7 +261,8 @@ function map_to_curve_elligator2_edwards25519(u: bigint) {
|
||||
return { x: Fp.mul(xn, inv[0]), y: Fp.mul(yn, inv[1]) }; // 13. return (xn, xd, yn, yd)
|
||||
}
|
||||
|
||||
const { hashToCurve, encodeToCurve } = htf.createHasher(
|
||||
const htf = /* @__PURE__ */ (() =>
|
||||
createHasher(
|
||||
ed25519.ExtendedPoint,
|
||||
(scalars: bigint[]) => map_to_curve_elligator2_edwards25519(scalars[0]),
|
||||
{
|
||||
@ -272,17 +274,16 @@ const { hashToCurve, encodeToCurve } = htf.createHasher(
|
||||
expand: 'xmd',
|
||||
hash: sha512,
|
||||
}
|
||||
);
|
||||
export { hashToCurve, encodeToCurve };
|
||||
))();
|
||||
export const hashToCurve = /* @__PURE__ */ (() => htf.hashToCurve)();
|
||||
export const encodeToCurve = /* @__PURE__ */ (() => htf.encodeToCurve)();
|
||||
|
||||
function assertRstPoint(other: unknown) {
|
||||
if (!(other instanceof RistrettoPoint)) throw new Error('RistrettoPoint expected');
|
||||
if (!(other instanceof RistPoint)) throw new Error('RistrettoPoint expected');
|
||||
}
|
||||
|
||||
// √(-1) aka √(a) aka 2^((p-1)/4)
|
||||
const SQRT_M1 = BigInt(
|
||||
'19681161376707505956807079304988542015446066515923890162744021073123829784752'
|
||||
);
|
||||
const SQRT_M1 = ED25519_SQRT_M1;
|
||||
// √(ad - 1)
|
||||
const SQRT_AD_MINUS_ONE = BigInt(
|
||||
'25063068953384623474111414158702152701244531502492656460079210482610430750235'
|
||||
@ -339,16 +340,15 @@ function calcElligatorRistrettoMap(r0: bigint): ExtendedPoint {
|
||||
* but it should work in its own namespace: do not combine those two.
|
||||
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448
|
||||
*/
|
||||
export class RistrettoPoint {
|
||||
static BASE = new RistrettoPoint(ed25519.ExtendedPoint.BASE);
|
||||
static ZERO = new RistrettoPoint(ed25519.ExtendedPoint.ZERO);
|
||||
|
||||
class RistPoint {
|
||||
static BASE: RistPoint;
|
||||
static ZERO: RistPoint;
|
||||
// Private property to discourage combining ExtendedPoint + RistrettoPoint
|
||||
// Always use Ristretto encoding/decoding instead.
|
||||
constructor(private readonly ep: ExtendedPoint) {}
|
||||
|
||||
static fromAffine(ap: AffinePoint<bigint>) {
|
||||
return new RistrettoPoint(ed25519.ExtendedPoint.fromAffine(ap));
|
||||
return new RistPoint(ed25519.ExtendedPoint.fromAffine(ap));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -358,13 +358,13 @@ export class RistrettoPoint {
|
||||
* https://ristretto.group/formulas/elligator.html
|
||||
* @param hex 64-byte output of a hash function
|
||||
*/
|
||||
static hashToCurve(hex: Hex): RistrettoPoint {
|
||||
static hashToCurve(hex: Hex): RistPoint {
|
||||
hex = ensureBytes('ristrettoHash', hex, 64);
|
||||
const r1 = bytes255ToNumberLE(hex.slice(0, 32));
|
||||
const R1 = calcElligatorRistrettoMap(r1);
|
||||
const r2 = bytes255ToNumberLE(hex.slice(32, 64));
|
||||
const R2 = calcElligatorRistrettoMap(r2);
|
||||
return new RistrettoPoint(R1.add(R2));
|
||||
return new RistPoint(R1.add(R2));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -372,7 +372,7 @@ export class RistrettoPoint {
|
||||
* https://ristretto.group/formulas/decoding.html
|
||||
* @param hex Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
|
||||
*/
|
||||
static fromHex(hex: Hex): RistrettoPoint {
|
||||
static fromHex(hex: Hex): RistPoint {
|
||||
hex = ensureBytes('ristrettoHex', hex, 32);
|
||||
const { a, d } = ed25519.CURVE;
|
||||
const P = ed25519.CURVE.Fp.ORDER;
|
||||
@ -396,7 +396,7 @@ export class RistrettoPoint {
|
||||
const y = mod(u1 * Dy); // 11
|
||||
const t = mod(x * y); // 12
|
||||
if (!isValid || isNegativeLE(t, P) || y === _0n) throw new Error(emsg);
|
||||
return new RistrettoPoint(new ed25519.ExtendedPoint(x, y, _1n, t));
|
||||
return new RistPoint(new ed25519.ExtendedPoint(x, y, _1n, t));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -440,7 +440,7 @@ export class RistrettoPoint {
|
||||
}
|
||||
|
||||
// Compare one point to another.
|
||||
equals(other: RistrettoPoint): boolean {
|
||||
equals(other: RistPoint): boolean {
|
||||
assertRstPoint(other);
|
||||
const { ex: X1, ey: Y1 } = this.ep;
|
||||
const { ex: X2, ey: Y2 } = other.ep;
|
||||
@ -451,31 +451,36 @@ export class RistrettoPoint {
|
||||
return one || two;
|
||||
}
|
||||
|
||||
add(other: RistrettoPoint): RistrettoPoint {
|
||||
add(other: RistPoint): RistPoint {
|
||||
assertRstPoint(other);
|
||||
return new RistrettoPoint(this.ep.add(other.ep));
|
||||
return new RistPoint(this.ep.add(other.ep));
|
||||
}
|
||||
|
||||
subtract(other: RistrettoPoint): RistrettoPoint {
|
||||
subtract(other: RistPoint): RistPoint {
|
||||
assertRstPoint(other);
|
||||
return new RistrettoPoint(this.ep.subtract(other.ep));
|
||||
return new RistPoint(this.ep.subtract(other.ep));
|
||||
}
|
||||
|
||||
multiply(scalar: bigint): RistrettoPoint {
|
||||
return new RistrettoPoint(this.ep.multiply(scalar));
|
||||
multiply(scalar: bigint): RistPoint {
|
||||
return new RistPoint(this.ep.multiply(scalar));
|
||||
}
|
||||
|
||||
multiplyUnsafe(scalar: bigint): RistrettoPoint {
|
||||
return new RistrettoPoint(this.ep.multiplyUnsafe(scalar));
|
||||
multiplyUnsafe(scalar: bigint): RistPoint {
|
||||
return new RistPoint(this.ep.multiplyUnsafe(scalar));
|
||||
}
|
||||
}
|
||||
export const RistrettoPoint = /* @__PURE__ */ (() => {
|
||||
if (!RistPoint.BASE) RistPoint.BASE = new RistPoint(ed25519.ExtendedPoint.BASE);
|
||||
if (!RistPoint.ZERO) RistPoint.ZERO = new RistPoint(ed25519.ExtendedPoint.ZERO);
|
||||
return RistPoint;
|
||||
})();
|
||||
|
||||
// https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/14/
|
||||
// Appendix B. Hashing to ristretto255
|
||||
export const hash_to_ristretto255 = (msg: Uint8Array, options: htf.htfBasicOpts) => {
|
||||
export const hash_to_ristretto255 = (msg: Uint8Array, options: htfBasicOpts) => {
|
||||
const d = options.DST;
|
||||
const DST = typeof d === 'string' ? utf8ToBytes(d) : d;
|
||||
const uniform_bytes = htf.expand_message_xmd(msg, DST, 64, sha512);
|
||||
const P = RistrettoPoint.hashToCurve(uniform_bytes);
|
||||
const uniform_bytes = expand_message_xmd(msg, DST, 64, sha512);
|
||||
const P = RistPoint.hashToCurve(uniform_bytes);
|
||||
return P;
|
||||
};
|
||||
|
15
src/ed448.ts
15
src/ed448.ts
@ -4,7 +4,7 @@ import { concatBytes, randomBytes, utf8ToBytes, wrapConstructor } from '@noble/h
|
||||
import { twistedEdwards } from './abstract/edwards.js';
|
||||
import { mod, pow2, Field } from './abstract/modular.js';
|
||||
import { montgomery } from './abstract/montgomery.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
import { createHasher } from './abstract/hash-to-curve.js';
|
||||
|
||||
/**
|
||||
* Edwards448 (not Ed448-Goldilocks) curve with following addons:
|
||||
@ -122,7 +122,8 @@ export const ed448 = twistedEdwards(ED448_DEF);
|
||||
// NOTE: there is no ed448ctx, since ed448 supports ctx by default
|
||||
export const ed448ph = twistedEdwards({ ...ED448_DEF, prehash: shake256_64 });
|
||||
|
||||
export const x448 = montgomery({
|
||||
export const x448 = /* @__PURE__ */ (() =>
|
||||
montgomery({
|
||||
a: BigInt(156326),
|
||||
montgomeryBits: 448,
|
||||
nByteLength: 57,
|
||||
@ -136,7 +137,7 @@ export const x448 = montgomery({
|
||||
},
|
||||
adjustScalarBytes,
|
||||
randomBytes,
|
||||
});
|
||||
}))();
|
||||
|
||||
/**
|
||||
* Converts edwards448 public key to x448 public key. Uses formula:
|
||||
@ -228,7 +229,8 @@ function map_to_curve_elligator2_edwards448(u: bigint) {
|
||||
return { x: Fp.mul(xEn, inv[0]), y: Fp.mul(yEn, inv[1]) }; // 38. return (xEn, xEd, yEn, yEd)
|
||||
}
|
||||
|
||||
const { hashToCurve, encodeToCurve } = htf.createHasher(
|
||||
const htf = /* @__PURE__ */ (() =>
|
||||
createHasher(
|
||||
ed448.ExtendedPoint,
|
||||
(scalars: bigint[]) => map_to_curve_elligator2_edwards448(scalars[0]),
|
||||
{
|
||||
@ -240,5 +242,6 @@ const { hashToCurve, encodeToCurve } = htf.createHasher(
|
||||
expand: 'xof',
|
||||
hash: shake256,
|
||||
}
|
||||
);
|
||||
export { hashToCurve, encodeToCurve };
|
||||
))();
|
||||
export const hashToCurve = /* @__PURE__ */ (() => htf.hashToCurve)();
|
||||
export const encodeToCurve = /* @__PURE__ */ (() => htf.encodeToCurve)();
|
||||
|
27
src/p256.ts
27
src/p256.ts
@ -3,7 +3,7 @@ import { createCurve } from './_shortw_utils.js';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { Field } from './abstract/modular.js';
|
||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
import { createHasher } from './abstract/hash-to-curve.js';
|
||||
|
||||
// NIST secp256r1 aka p256
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-256
|
||||
@ -12,12 +12,6 @@ const Fp = Field(BigInt('0xffffffff00000001000000000000000000000000fffffffffffff
|
||||
const CURVE_A = Fp.create(BigInt('-3'));
|
||||
const CURVE_B = BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b');
|
||||
|
||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
||||
A: CURVE_A,
|
||||
B: CURVE_B,
|
||||
Z: Fp.create(BigInt('-10')),
|
||||
});
|
||||
|
||||
// prettier-ignore
|
||||
export const p256 = createCurve({
|
||||
a: CURVE_A, // Equation params: a, b
|
||||
@ -33,10 +27,15 @@ export const p256 = createCurve({
|
||||
} as const, sha256);
|
||||
export const secp256r1 = p256;
|
||||
|
||||
const { hashToCurve, encodeToCurve } = htf.createHasher(
|
||||
secp256r1.ProjectivePoint,
|
||||
(scalars: bigint[]) => mapSWU(scalars[0]),
|
||||
{
|
||||
const mapSWU = /* @__PURE__ */ (() =>
|
||||
mapToCurveSimpleSWU(Fp, {
|
||||
A: CURVE_A,
|
||||
B: CURVE_B,
|
||||
Z: Fp.create(BigInt('-10')),
|
||||
}))();
|
||||
|
||||
const htf = /* @__PURE__ */ (() =>
|
||||
createHasher(secp256r1.ProjectivePoint, (scalars: bigint[]) => mapSWU(scalars[0]), {
|
||||
DST: 'P256_XMD:SHA-256_SSWU_RO_',
|
||||
encodeDST: 'P256_XMD:SHA-256_SSWU_NU_',
|
||||
p: Fp.ORDER,
|
||||
@ -44,6 +43,6 @@ const { hashToCurve, encodeToCurve } = htf.createHasher(
|
||||
k: 128,
|
||||
expand: 'xmd',
|
||||
hash: sha256,
|
||||
}
|
||||
);
|
||||
export { hashToCurve, encodeToCurve };
|
||||
}))();
|
||||
export const hashToCurve = /* @__PURE__ */ (() => htf.hashToCurve)();
|
||||
export const encodeToCurve = /* @__PURE__ */ (() => htf.encodeToCurve)();
|
||||
|
19
src/p384.ts
19
src/p384.ts
@ -3,7 +3,7 @@ import { createCurve } from './_shortw_utils.js';
|
||||
import { sha384 } from '@noble/hashes/sha512';
|
||||
import { Field } from './abstract/modular.js';
|
||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
import { createHasher } from './abstract/hash-to-curve.js';
|
||||
|
||||
// NIST secp384r1 aka p384
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-384
|
||||
@ -31,16 +31,15 @@ export const p384 = createCurve({
|
||||
} as const, sha384);
|
||||
export const secp384r1 = p384;
|
||||
|
||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
||||
const mapSWU = /* @__PURE__ */ (() =>
|
||||
mapToCurveSimpleSWU(Fp, {
|
||||
A: CURVE_A,
|
||||
B: CURVE_B,
|
||||
Z: Fp.create(BigInt('-12')),
|
||||
});
|
||||
}))();
|
||||
|
||||
const { hashToCurve, encodeToCurve } = htf.createHasher(
|
||||
secp384r1.ProjectivePoint,
|
||||
(scalars: bigint[]) => mapSWU(scalars[0]),
|
||||
{
|
||||
const htf = /* @__PURE__ */ (() =>
|
||||
createHasher(secp384r1.ProjectivePoint, (scalars: bigint[]) => mapSWU(scalars[0]), {
|
||||
DST: 'P384_XMD:SHA-384_SSWU_RO_',
|
||||
encodeDST: 'P384_XMD:SHA-384_SSWU_NU_',
|
||||
p: Fp.ORDER,
|
||||
@ -48,6 +47,6 @@ const { hashToCurve, encodeToCurve } = htf.createHasher(
|
||||
k: 192,
|
||||
expand: 'xmd',
|
||||
hash: sha384,
|
||||
}
|
||||
);
|
||||
export { hashToCurve, encodeToCurve };
|
||||
}))();
|
||||
export const hashToCurve = /* @__PURE__ */ (() => htf.hashToCurve)();
|
||||
export const encodeToCurve = /* @__PURE__ */ (() => htf.encodeToCurve)();
|
||||
|
19
src/p521.ts
19
src/p521.ts
@ -3,7 +3,7 @@ import { createCurve } from './_shortw_utils.js';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { Field } from './abstract/modular.js';
|
||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
import { createHasher } from './abstract/hash-to-curve.js';
|
||||
|
||||
// NIST secp521r1 aka p521
|
||||
// Note that it's 521, which differs from 512 of its hash function.
|
||||
@ -47,16 +47,15 @@ export const p521 = createCurve({
|
||||
} as const, sha512);
|
||||
export const secp521r1 = p521;
|
||||
|
||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
||||
const mapSWU = /* @__PURE__ */ (() =>
|
||||
mapToCurveSimpleSWU(Fp, {
|
||||
A: CURVE.a,
|
||||
B: CURVE.b,
|
||||
Z: Fp.create(BigInt('-4')),
|
||||
});
|
||||
}))();
|
||||
|
||||
const { hashToCurve, encodeToCurve } = htf.createHasher(
|
||||
secp521r1.ProjectivePoint,
|
||||
(scalars: bigint[]) => mapSWU(scalars[0]),
|
||||
{
|
||||
const htf = /* @__PURE__ */ (() =>
|
||||
createHasher(secp521r1.ProjectivePoint, (scalars: bigint[]) => mapSWU(scalars[0]), {
|
||||
DST: 'P521_XMD:SHA-512_SSWU_RO_',
|
||||
encodeDST: 'P521_XMD:SHA-512_SSWU_NU_',
|
||||
p: Fp.ORDER,
|
||||
@ -64,6 +63,6 @@ const { hashToCurve, encodeToCurve } = htf.createHasher(
|
||||
k: 256,
|
||||
expand: 'xmd',
|
||||
hash: sha512,
|
||||
}
|
||||
);
|
||||
export { hashToCurve, encodeToCurve };
|
||||
}))();
|
||||
export const hashToCurve = /* @__PURE__ */ (() => htf.hashToCurve)();
|
||||
export const encodeToCurve = /* @__PURE__ */ (() => htf.encodeToCurve)();
|
||||
|
@ -5,7 +5,7 @@ import { Field, mod, pow2 } from './abstract/modular.js';
|
||||
import { ProjPointType as PointType, mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import type { Hex, PrivKey } from './abstract/utils.js';
|
||||
import { bytesToNumberBE, concatBytes, ensureBytes, numberToBytesBE } from './abstract/utils.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
import { createHasher, isogenyMap } from './abstract/hash-to-curve.js';
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
|
||||
const secp256k1P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
|
||||
@ -199,7 +199,7 @@ function schnorrVerify(signature: Hex, message: Hex, publicKey: Hex): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
export const schnorr = {
|
||||
export const schnorr = /* @__PURE__ */ (() => ({
|
||||
getPublicKey: schnorrGetPublicKey,
|
||||
sign: schnorrSign,
|
||||
verify: schnorrVerify,
|
||||
@ -212,9 +212,10 @@ export const schnorr = {
|
||||
taggedHash,
|
||||
mod,
|
||||
},
|
||||
};
|
||||
}))();
|
||||
|
||||
const isoMap = htf.isogenyMap(
|
||||
const isoMap = /* @__PURE__ */ (() =>
|
||||
isogenyMap(
|
||||
Fp,
|
||||
[
|
||||
// xNum
|
||||
@ -245,13 +246,15 @@ const isoMap = htf.isogenyMap(
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
|
||||
],
|
||||
].map((i) => i.map((j) => BigInt(j))) as [bigint[], bigint[], bigint[], bigint[]]
|
||||
);
|
||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
||||
))();
|
||||
const mapSWU = /* @__PURE__ */ (() =>
|
||||
mapToCurveSimpleSWU(Fp, {
|
||||
A: BigInt('0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533'),
|
||||
B: BigInt('1771'),
|
||||
Z: Fp.create(BigInt('-11')),
|
||||
});
|
||||
export const { hashToCurve, encodeToCurve } = htf.createHasher(
|
||||
}))();
|
||||
const htf = /* @__PURE__ */ (() =>
|
||||
createHasher(
|
||||
secp256k1.ProjectivePoint,
|
||||
(scalars: bigint[]) => {
|
||||
const { x, y } = mapSWU(Fp.create(scalars[0]));
|
||||
@ -266,4 +269,6 @@ export const { hashToCurve, encodeToCurve } = htf.createHasher(
|
||||
expand: 'xmd',
|
||||
hash: sha256,
|
||||
}
|
||||
);
|
||||
))();
|
||||
export const hashToCurve = /* @__PURE__ */ (() => htf.hashToCurve)();
|
||||
export const encodeToCurve = /* @__PURE__ */ (() => htf.encodeToCurve)();
|
||||
|
Loading…
Reference in New Issue
Block a user