@okxweb3/crypto-lib
Version:
A base package for @okxweb3/coin-*
276 lines • 9.49 kB
JavaScript
;
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
Object.defineProperty(exports, "__esModule", { value: true });
exports.hashToPrivateScalar = exports.FpSqrtEven = exports.FpSqrtOdd = exports.Field = 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;
const utils_1 = require("./utils");
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
const _4n = BigInt(4), _5n = BigInt(5), _8n = BigInt(8);
const _9n = BigInt(9), _16n = BigInt(16);
function mod(a, b) {
const result = a % b;
return result >= _0n ? result : b + result;
}
exports.mod = mod;
function pow(num, power, modulo) {
if (modulo <= _0n || power < _0n)
throw new Error('Expected power/modulo > 0');
if (modulo === _1n)
return _0n;
let res = _1n;
while (power > _0n) {
if (power & _1n)
res = (res * num) % modulo;
num = (num * num) % modulo;
power >>= _1n;
}
return res;
}
exports.pow = pow;
function pow2(x, power, modulo) {
let res = x;
while (power-- > _0n) {
res *= res;
res %= modulo;
}
return res;
}
exports.pow2 = pow2;
function invert(number, modulo) {
if (number === _0n || modulo <= _0n) {
throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);
}
let a = mod(number, modulo);
let b = modulo;
let x = _0n, y = _1n, u = _1n, v = _0n;
while (a !== _0n) {
const q = b / a;
const r = b % a;
const m = x - u * q;
const n = y - v * q;
b = a, a = r, x = u, y = v, u = m, v = n;
}
const gcd = b;
if (gcd !== _1n)
throw new Error('invert: does not exist');
return mod(x, modulo);
}
exports.invert = invert;
function tonelliShanks(P) {
const legendreC = (P - _1n) / _2n;
let Q, S, Z;
for (Q = P - _1n, S = 0; Q % _2n === _0n; Q /= _2n, S++)
;
for (Z = _2n; Z < P && pow(Z, legendreC, P) !== P - _1n; Z++)
;
if (S === 1) {
const p1div4 = (P + _1n) / _4n;
return function tonelliFast(Fp, n) {
const root = Fp.pow(n, p1div4);
if (!Fp.eql(Fp.sqr(root), n))
throw new Error('Cannot find square root');
return root;
};
}
const Q1div2 = (Q + _1n) / _2n;
return function tonelliSlow(Fp, n) {
if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE))
throw new Error('Cannot find square root');
let r = S;
let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q);
let x = Fp.pow(n, Q1div2);
let b = Fp.pow(n, Q);
while (!Fp.eql(b, Fp.ONE)) {
if (Fp.eql(b, Fp.ZERO))
return Fp.ZERO;
let m = 1;
for (let t2 = Fp.sqr(b); m < r; m++) {
if (Fp.eql(t2, Fp.ONE))
break;
t2 = Fp.sqr(t2);
}
const ge = Fp.pow(g, _1n << BigInt(r - m - 1));
g = Fp.sqr(ge);
x = Fp.mul(x, ge);
b = Fp.mul(b, g);
r = m;
}
return x;
};
}
exports.tonelliShanks = tonelliShanks;
function FpSqrt(P) {
if (P % _4n === _3n) {
const p1div4 = (P + _1n) / _4n;
return function sqrt3mod4(Fp, n) {
const root = Fp.pow(n, p1div4);
if (!Fp.eql(Fp.sqr(root), n))
throw new Error('Cannot find square root');
return root;
};
}
if (P % _8n === _5n) {
const c1 = (P - _5n) / _8n;
return function sqrt5mod8(Fp, n) {
const n2 = Fp.mul(n, _2n);
const v = Fp.pow(n2, c1);
const nv = Fp.mul(n, v);
const i = Fp.mul(Fp.mul(nv, _2n), v);
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
if (!Fp.eql(Fp.sqr(root), n))
throw new Error('Cannot find square root');
return root;
};
}
if (P % _16n === _9n) {
}
return tonelliShanks(P);
}
exports.FpSqrt = FpSqrt;
const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
exports.isNegativeLE = isNegativeLE;
const FIELD_FIELDS = [
'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
'eql', 'add', 'sub', 'mul', 'pow', 'div',
'addN', 'subN', 'mulN', 'sqrN'
];
function validateField(field) {
const initial = {
ORDER: 'bigint',
MASK: 'bigint',
BYTES: 'isSafeInteger',
BITS: 'isSafeInteger',
};
const opts = FIELD_FIELDS.reduce((map, val) => {
map[val] = 'function';
return map;
}, initial);
return (0, utils_1.validateObject)(field, opts);
}
exports.validateField = validateField;
function FpPow(f, num, power) {
if (power < _0n)
throw new Error('Expected power > 0');
if (power === _0n)
return f.ONE;
if (power === _1n)
return num;
let p = f.ONE;
let d = num;
while (power > _0n) {
if (power & _1n)
p = f.mul(p, d);
d = f.sqr(d);
power >>= _1n;
}
return p;
}
exports.FpPow = FpPow;
function FpInvertBatch(f, nums) {
const tmp = new Array(nums.length);
const lastMultiplied = nums.reduce((acc, num, i) => {
if (f.is0(num))
return acc;
tmp[i] = acc;
return f.mul(acc, num);
}, f.ONE);
const inverted = f.inv(lastMultiplied);
nums.reduceRight((acc, num, i) => {
if (f.is0(num))
return acc;
tmp[i] = f.mul(acc, tmp[i]);
return f.mul(acc, num);
}, inverted);
return tmp;
}
exports.FpInvertBatch = FpInvertBatch;
function FpDiv(f, lhs, rhs) {
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
}
exports.FpDiv = FpDiv;
function FpIsSquare(f) {
const legendreConst = (f.ORDER - _1n) / _2n;
return (x) => {
const p = f.pow(x, legendreConst);
return f.eql(p, f.ZERO) || f.eql(p, f.ONE);
};
}
exports.FpIsSquare = FpIsSquare;
function nLength(n, nBitLength) {
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
const nByteLength = Math.ceil(_nBitLength / 8);
return { nBitLength: _nBitLength, nByteLength };
}
exports.nLength = nLength;
function Field(ORDER, bitLen, isLE = false, redef = {}) {
if (ORDER <= _0n)
throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
if (BYTES > 2048)
throw new Error('Field lengths over 2048 bytes are not supported');
const sqrtP = FpSqrt(ORDER);
const f = Object.freeze({
ORDER,
BITS,
BYTES,
MASK: (0, utils_1.bitMask)(BITS),
ZERO: _0n,
ONE: _1n,
create: (num) => mod(num, ORDER),
isValid: (num) => {
if (typeof num !== 'bigint')
throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
return _0n <= num && num < ORDER;
},
is0: (num) => num === _0n,
isOdd: (num) => (num & _1n) === _1n,
neg: (num) => mod(-num, ORDER),
eql: (lhs, rhs) => lhs === rhs,
sqr: (num) => mod(num * num, ORDER),
add: (lhs, rhs) => mod(lhs + rhs, ORDER),
sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
pow: (num, power) => FpPow(f, num, power),
div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
sqrN: (num) => num * num,
addN: (lhs, rhs) => lhs + rhs,
subN: (lhs, rhs) => lhs - rhs,
mulN: (lhs, rhs) => lhs * rhs,
inv: (num) => invert(num, ORDER),
sqrt: redef.sqrt || ((n) => sqrtP(f, n)),
invertBatch: (lst) => FpInvertBatch(f, lst),
cmov: (a, b, c) => (c ? b : a),
toBytes: (num) => (isLE ? (0, utils_1.numberToBytesLE)(num, BYTES) : (0, utils_1.numberToBytesBE)(num, BYTES)),
fromBytes: (bytes) => {
if (bytes.length !== BYTES)
throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`);
return isLE ? (0, utils_1.bytesToNumberLE)(bytes) : (0, utils_1.bytesToNumberBE)(bytes);
},
});
return Object.freeze(f);
}
exports.Field = Field;
function FpSqrtOdd(Fp, elm) {
if (!Fp.isOdd)
throw new Error(`Field doesn't have isOdd`);
const root = Fp.sqrt(elm);
return Fp.isOdd(root) ? root : Fp.neg(root);
}
exports.FpSqrtOdd = FpSqrtOdd;
function FpSqrtEven(Fp, elm) {
if (!Fp.isOdd)
throw new Error(`Field doesn't have isOdd`);
const root = Fp.sqrt(elm);
return Fp.isOdd(root) ? Fp.neg(root) : root;
}
exports.FpSqrtEven = FpSqrtEven;
function hashToPrivateScalar(hash, groupOrder, isLE = false) {
hash = (0, utils_1.ensureBytes)('privateHash', 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_1.bytesToNumberLE)(hash) : (0, utils_1.bytesToNumberBE)(hash);
return mod(num, groupOrder - _1n) + _1n;
}
exports.hashToPrivateScalar = hashToPrivateScalar;
//# sourceMappingURL=modular.js.map