UNPKG

@noble/post-quantum

Version:

Auditable & minimal JS implementation of post-quantum public-key cryptography: FIPS 203, 204, 205

146 lines 6.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EMPTY = exports.utf8ToBytes = exports.concatBytes = exports.randomBytes = exports.ensureBytes = void 0; exports.equalBytes = equalBytes; exports.splitCoder = splitCoder; exports.vecCoder = vecCoder; exports.cleanBytes = cleanBytes; exports.getMask = getMask; exports.getMessage = getMessage; exports.getMessagePrehash = getMessagePrehash; /** * Utilities for hex, bytearray and number handling. * @module */ /*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */ const _assert_1 = require("@noble/hashes/_assert"); const sha256_1 = require("@noble/hashes/sha256"); const sha3_1 = require("@noble/hashes/sha3"); const sha512_1 = require("@noble/hashes/sha512"); const utils_1 = require("@noble/hashes/utils"); Object.defineProperty(exports, "concatBytes", { enumerable: true, get: function () { return utils_1.concatBytes; } }); Object.defineProperty(exports, "utf8ToBytes", { enumerable: true, get: function () { return utils_1.utf8ToBytes; } }); exports.ensureBytes = _assert_1.abytes; exports.randomBytes = utils_1.randomBytes; // Compares 2 u8a-s in kinda constant time function equalBytes(a, b) { if (a.length !== b.length) return false; let diff = 0; for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i]; return diff === 0; } function splitCoder(...lengths) { const getLength = (c) => (typeof c === 'number' ? c : c.bytesLen); const bytesLen = lengths.reduce((sum, a) => sum + getLength(a), 0); return { bytesLen, encode: (bufs) => { const res = new Uint8Array(bytesLen); for (let i = 0, pos = 0; i < lengths.length; i++) { const c = lengths[i]; const l = getLength(c); const b = typeof c === 'number' ? bufs[i] : c.encode(bufs[i]); (0, exports.ensureBytes)(b, l); res.set(b, pos); if (typeof c !== 'number') b.fill(0); // clean pos += l; } return res; }, decode: (buf) => { (0, exports.ensureBytes)(buf, bytesLen); const res = []; for (const c of lengths) { const l = getLength(c); const b = buf.subarray(0, l); res.push(typeof c === 'number' ? b : c.decode(b)); buf = buf.subarray(l); } return res; }, }; } // nano-packed.array (fixed size) function vecCoder(c, vecLen) { const bytesLen = vecLen * c.bytesLen; return { bytesLen, encode: (u) => { if (u.length !== vecLen) throw new Error(`vecCoder.encode: wrong length=${u.length}. Expected: ${vecLen}`); const res = new Uint8Array(bytesLen); for (let i = 0, pos = 0; i < u.length; i++) { const b = c.encode(u[i]); res.set(b, pos); b.fill(0); // clean pos += b.length; } return res; }, decode: (a) => { (0, exports.ensureBytes)(a, bytesLen); const r = []; for (let i = 0; i < a.length; i += c.bytesLen) r.push(c.decode(a.subarray(i, i + c.bytesLen))); return r; }, }; } // cleanBytes(new Uint8Array(), [new Uint16Array(), new Uint32Array()]) function cleanBytes(...list) { for (const t of list) { if (Array.isArray(t)) for (const b of t) b.fill(0); else t.fill(0); } } function getMask(bits) { return (1 << bits) - 1; // 4 -> 0b1111 } exports.EMPTY = new Uint8Array(0); function getMessage(msg, ctx = exports.EMPTY) { (0, exports.ensureBytes)(msg); (0, exports.ensureBytes)(ctx); if (ctx.length > 255) throw new Error('context should be less than 255 bytes'); return (0, utils_1.concatBytes)(new Uint8Array([0, ctx.length]), ctx, msg); } // OIDS from https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration // TODO: maybe add 'OID' property to hashes themselves to improve tree-shaking? const HASHES = { 'SHA2-256': { oid: (0, utils_1.hexToBytes)('0609608648016503040201'), hash: sha256_1.sha256 }, 'SHA2-384': { oid: (0, utils_1.hexToBytes)('0609608648016503040202'), hash: sha512_1.sha384 }, 'SHA2-512': { oid: (0, utils_1.hexToBytes)('0609608648016503040203'), hash: sha512_1.sha512 }, 'SHA2-224': { oid: (0, utils_1.hexToBytes)('0609608648016503040204'), hash: sha256_1.sha224 }, 'SHA2-512/224': { oid: (0, utils_1.hexToBytes)('0609608648016503040205'), hash: sha512_1.sha512_224 }, 'SHA2-512/256': { oid: (0, utils_1.hexToBytes)('0609608648016503040206'), hash: sha512_1.sha512_256 }, 'SHA3-224': { oid: (0, utils_1.hexToBytes)('0609608648016503040207'), hash: sha3_1.sha3_224 }, 'SHA3-256': { oid: (0, utils_1.hexToBytes)('0609608648016503040208'), hash: sha3_1.sha3_256 }, 'SHA3-384': { oid: (0, utils_1.hexToBytes)('0609608648016503040209'), hash: sha3_1.sha3_384 }, 'SHA3-512': { oid: (0, utils_1.hexToBytes)('060960864801650304020A'), hash: sha3_1.sha3_512 }, 'SHAKE-128': { oid: (0, utils_1.hexToBytes)('060960864801650304020B'), hash: (msg) => (0, sha3_1.shake128)(msg, { dkLen: 32 }), }, 'SHAKE-256': { oid: (0, utils_1.hexToBytes)('060960864801650304020C'), hash: (msg) => (0, sha3_1.shake256)(msg, { dkLen: 64 }), }, }; function getMessagePrehash(hashName, msg, ctx = exports.EMPTY) { (0, exports.ensureBytes)(msg); (0, exports.ensureBytes)(ctx); if (ctx.length > 255) throw new Error('context should be less than 255 bytes'); if (!HASHES[hashName]) throw new Error('unknown hash: ' + hashName); const { oid, hash } = HASHES[hashName]; const hashed = hash(msg); return (0, utils_1.concatBytes)(new Uint8Array([1, ctx.length]), ctx, oid, hashed); } //# sourceMappingURL=utils.js.map