@okxweb3/crypto-lib
Version:
A base package for @okxweb3/coin-*
159 lines • 5.74 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createHasher = exports.isogenyMap = exports.hash_to_field = exports.expand_message_xof = exports.expand_message_xmd = exports.isNum = exports.isBytes = exports.strxor = exports.i2osp = exports.validateDST = void 0;
const modular_1 = require("./modular");
const utils_1 = require("./utils");
function validateDST(dst) {
if (dst instanceof Uint8Array)
return dst;
if (typeof dst === 'string')
return (0, utils_1.utf8ToBytes)(dst);
throw new Error('DST must be Uint8Array or string');
}
exports.validateDST = validateDST;
const os2ip = utils_1.bytesToNumberBE;
function i2osp(value, length) {
if (value < 0 || value >= 1 << (8 * length)) {
throw new Error(`bad I2OSP call: value=${value} length=${length}`);
}
const res = Array.from({ length }).fill(0);
for (let i = length - 1; i >= 0; i--) {
res[i] = value & 0xff;
value >>>= 8;
}
return new Uint8Array(res);
}
exports.i2osp = i2osp;
function strxor(a, b) {
const arr = new Uint8Array(a.length);
for (let i = 0; i < a.length; i++) {
arr[i] = a[i] ^ b[i];
}
return arr;
}
exports.strxor = strxor;
function isBytes(item) {
if (!(item instanceof Uint8Array))
throw new Error('Uint8Array expected');
}
exports.isBytes = isBytes;
function isNum(item) {
if (!Number.isSafeInteger(item))
throw new Error('number expected');
}
exports.isNum = isNum;
function expand_message_xmd(msg, DST, lenInBytes, H) {
isBytes(msg);
isBytes(DST);
isNum(lenInBytes);
if (DST.length > 255)
DST = H((0, utils_1.concatBytes)((0, utils_1.utf8ToBytes)('H2C-OVERSIZE-DST-'), DST));
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
const ell = Math.ceil(lenInBytes / b_in_bytes);
if (ell > 255)
throw new Error('Invalid xmd length');
const DST_prime = (0, utils_1.concatBytes)(DST, i2osp(DST.length, 1));
const Z_pad = i2osp(0, r_in_bytes);
const l_i_b_str = i2osp(lenInBytes, 2);
const b = new Array(ell);
const b_0 = H((0, utils_1.concatBytes)(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime));
b[0] = H((0, utils_1.concatBytes)(b_0, i2osp(1, 1), DST_prime));
for (let i = 1; i <= ell; i++) {
const args = [strxor(b_0, b[i - 1]), i2osp(i + 1, 1), DST_prime];
b[i] = H((0, utils_1.concatBytes)(...args));
}
const pseudo_random_bytes = (0, utils_1.concatBytes)(...b);
return pseudo_random_bytes.slice(0, lenInBytes);
}
exports.expand_message_xmd = expand_message_xmd;
function expand_message_xof(msg, DST, lenInBytes, k, H) {
isBytes(msg);
isBytes(DST);
isNum(lenInBytes);
if (DST.length > 255) {
const dkLen = Math.ceil((2 * k) / 8);
DST = H.create({ dkLen }).update((0, utils_1.utf8ToBytes)('H2C-OVERSIZE-DST-')).update(DST).digest();
}
if (lenInBytes > 65535 || DST.length > 255)
throw new Error('expand_message_xof: invalid lenInBytes');
return (H.create({ dkLen: lenInBytes })
.update(msg)
.update(i2osp(lenInBytes, 2))
.update(DST)
.update(i2osp(DST.length, 1))
.digest());
}
exports.expand_message_xof = expand_message_xof;
function hash_to_field(msg, count, options) {
(0, utils_1.validateObject)(options, {
DST: 'string',
p: 'bigint',
m: 'isSafeInteger',
k: 'isSafeInteger',
hash: 'hash',
});
const { p, k, m, hash, expand, DST: _DST } = options;
isBytes(msg);
isNum(count);
const DST = validateDST(_DST);
const log2p = p.toString(2).length;
const L = Math.ceil((log2p + k) / 8);
const len_in_bytes = count * m * L;
let prb;
if (expand === 'xmd') {
prb = expand_message_xmd(msg, DST, len_in_bytes, hash);
}
else if (expand === 'xof') {
prb = expand_message_xof(msg, DST, len_in_bytes, k, hash);
}
else if (expand === '_internal_pass') {
prb = msg;
}
else {
throw new Error('expand must be "xmd" or "xof"');
}
const u = new Array(count);
for (let i = 0; i < count; i++) {
const e = new Array(m);
for (let j = 0; j < m; j++) {
const elm_offset = L * (j + i * m);
const tv = prb.subarray(elm_offset, elm_offset + L);
e[j] = (0, modular_1.mod)(os2ip(tv), p);
}
u[i] = e;
}
return u;
}
exports.hash_to_field = hash_to_field;
function isogenyMap(field, map) {
const COEFF = map.map((i) => Array.from(i).reverse());
return (x, y) => {
const [xNum, xDen, yNum, yDen] = COEFF.map((val) => val.reduce((acc, i) => field.add(field.mul(acc, x), i)));
x = field.div(xNum, xDen);
y = field.mul(y, field.div(yNum, yDen));
return { x, y };
};
}
exports.isogenyMap = isogenyMap;
function createHasher(Point, mapToCurve, def) {
if (typeof mapToCurve !== 'function')
throw new Error('mapToCurve() must be defined');
return {
hashToCurve(msg, options) {
const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options });
const u0 = Point.fromAffine(mapToCurve(u[0]));
const u1 = Point.fromAffine(mapToCurve(u[1]));
const P = u0.add(u1).clearCofactor();
P.assertValidity();
return P;
},
encodeToCurve(msg, options) {
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.createHasher = createHasher;
//# sourceMappingURL=hash-to-curve.js.map