| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 | "use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.keccakprg = exports.m14 = exports.k12 = exports.turboshake256 = exports.turboshake128 = exports.parallelhash256xof = exports.parallelhash128xof = exports.parallelhash256 = exports.parallelhash128 = exports.tuplehash256xof = exports.tuplehash128xof = exports.tuplehash256 = exports.tuplehash128 = exports.kmac256xof = exports.kmac128xof = exports.kmac256 = exports.kmac128 = exports.cshake256 = exports.cshake128 = void 0;const _assert_js_1 = require("./_assert.js");const utils_js_1 = require("./utils.js");const sha3_js_1 = require("./sha3.js");// cSHAKE && KMAC (NIST SP800-185)function leftEncode(n) {    const res = [n & 0xff];    n >>= 8;    for (; n > 0; n >>= 8)        res.unshift(n & 0xff);    res.unshift(res.length);    return new Uint8Array(res);}function rightEncode(n) {    const res = [n & 0xff];    n >>= 8;    for (; n > 0; n >>= 8)        res.unshift(n & 0xff);    res.push(res.length);    return new Uint8Array(res);}function chooseLen(opts, outputLen) {    return opts.dkLen === undefined ? outputLen : opts.dkLen;}const toBytesOptional = (buf) => (buf !== undefined ? (0, utils_js_1.toBytes)(buf) : new Uint8Array([]));// NOTE: second modulo is necessary since we don't need to add padding if current element takes whole blockconst getPadding = (len, block) => new Uint8Array((block - (len % block)) % block);// Personalizationfunction cshakePers(hash, opts = {}) {    if (!opts || (!opts.personalization && !opts.NISTfn))        return hash;    // Encode and pad inplace to avoid unneccesary memory copies/slices (so we don't need to zero them later)    // bytepad(encode_string(N) || encode_string(S), 168)    const blockLenBytes = leftEncode(hash.blockLen);    const fn = toBytesOptional(opts.NISTfn);    const fnLen = leftEncode(8 * fn.length); // length in bits    const pers = toBytesOptional(opts.personalization);    const persLen = leftEncode(8 * pers.length); // length in bits    if (!fn.length && !pers.length)        return hash;    hash.suffix = 0x04;    hash.update(blockLenBytes).update(fnLen).update(fn).update(persLen).update(pers);    let totalLen = blockLenBytes.length + fnLen.length + fn.length + persLen.length + pers.length;    hash.update(getPadding(totalLen, hash.blockLen));    return hash;}const gencShake = (suffix, blockLen, outputLen) => (0, utils_js_1.wrapXOFConstructorWithOpts)((opts = {}) => cshakePers(new sha3_js_1.Keccak(blockLen, suffix, chooseLen(opts, outputLen), true), opts));exports.cshake128 = (() => gencShake(0x1f, 168, 128 / 8))();exports.cshake256 = (() => gencShake(0x1f, 136, 256 / 8))();class KMAC extends sha3_js_1.Keccak {    constructor(blockLen, outputLen, enableXOF, key, opts = {}) {        super(blockLen, 0x1f, outputLen, enableXOF);        cshakePers(this, { NISTfn: 'KMAC', personalization: opts.personalization });        key = (0, utils_js_1.toBytes)(key);        // 1. newX = bytepad(encode_string(K), 168) || X || right_encode(L).        const blockLenBytes = leftEncode(this.blockLen);        const keyLen = leftEncode(8 * key.length);        this.update(blockLenBytes).update(keyLen).update(key);        const totalLen = blockLenBytes.length + keyLen.length + key.length;        this.update(getPadding(totalLen, this.blockLen));    }    finish() {        if (!this.finished)            this.update(rightEncode(this.enableXOF ? 0 : this.outputLen * 8)); // outputLen in bits        super.finish();    }    _cloneInto(to) {        // Create new instance without calling constructor since key already in state and we don't know it.        // Force "to" to be instance of KMAC instead of Sha3.        if (!to) {            to = Object.create(Object.getPrototypeOf(this), {});            to.state = this.state.slice();            to.blockLen = this.blockLen;            to.state32 = (0, utils_js_1.u32)(to.state);        }        return super._cloneInto(to);    }    clone() {        return this._cloneInto();    }}function genKmac(blockLen, outputLen, xof = false) {    const kmac = (key, message, opts) => kmac.create(key, opts).update(message).digest();    kmac.create = (key, opts = {}) => new KMAC(blockLen, chooseLen(opts, outputLen), xof, key, opts);    return kmac;}exports.kmac128 = (() => genKmac(168, 128 / 8))();exports.kmac256 = (() => genKmac(136, 256 / 8))();exports.kmac128xof = (() => genKmac(168, 128 / 8, true))();exports.kmac256xof = (() => genKmac(136, 256 / 8, true))();// TupleHash// Usage: tuple(['ab', 'cd']) != tuple(['a', 'bcd'])class TupleHash extends sha3_js_1.Keccak {    constructor(blockLen, outputLen, enableXOF, opts = {}) {        super(blockLen, 0x1f, outputLen, enableXOF);        cshakePers(this, { NISTfn: 'TupleHash', personalization: opts.personalization });        // Change update after cshake processed        this.update = (data) => {            data = (0, utils_js_1.toBytes)(data);            super.update(leftEncode(data.length * 8));            super.update(data);            return this;        };    }    finish() {        if (!this.finished)            super.update(rightEncode(this.enableXOF ? 0 : this.outputLen * 8)); // outputLen in bits        super.finish();    }    _cloneInto(to) {        to || (to = new TupleHash(this.blockLen, this.outputLen, this.enableXOF));        return super._cloneInto(to);    }    clone() {        return this._cloneInto();    }}function genTuple(blockLen, outputLen, xof = false) {    const tuple = (messages, opts) => {        const h = tuple.create(opts);        for (const msg of messages)            h.update(msg);        return h.digest();    };    tuple.create = (opts = {}) => new TupleHash(blockLen, chooseLen(opts, outputLen), xof, opts);    return tuple;}exports.tuplehash128 = (() => genTuple(168, 128 / 8))();exports.tuplehash256 = (() => genTuple(136, 256 / 8))();exports.tuplehash128xof = (() => genTuple(168, 128 / 8, true))();exports.tuplehash256xof = (() => genTuple(136, 256 / 8, true))();class ParallelHash extends sha3_js_1.Keccak {    constructor(blockLen, outputLen, leafCons, enableXOF, opts = {}) {        super(blockLen, 0x1f, outputLen, enableXOF);        this.leafCons = leafCons;        this.chunkPos = 0; // Position of current block in chunk        this.chunksDone = 0; // How many chunks we already have        cshakePers(this, { NISTfn: 'ParallelHash', personalization: opts.personalization });        let { blockLen: B } = opts;        B || (B = 8);        (0, _assert_js_1.number)(B);        this.chunkLen = B;        super.update(leftEncode(B));        // Change update after cshake processed        this.update = (data) => {            data = (0, utils_js_1.toBytes)(data);            const { chunkLen, leafCons } = this;            for (let pos = 0, len = data.length; pos < len;) {                if (this.chunkPos == chunkLen || !this.leafHash) {                    if (this.leafHash) {                        super.update(this.leafHash.digest());                        this.chunksDone++;                    }                    this.leafHash = leafCons();                    this.chunkPos = 0;                }                const take = Math.min(chunkLen - this.chunkPos, len - pos);                this.leafHash.update(data.subarray(pos, pos + take));                this.chunkPos += take;                pos += take;            }            return this;        };    }    finish() {        if (this.finished)            return;        if (this.leafHash) {            super.update(this.leafHash.digest());            this.chunksDone++;        }        super.update(rightEncode(this.chunksDone));        super.update(rightEncode(this.enableXOF ? 0 : this.outputLen * 8)); // outputLen in bits        super.finish();    }    _cloneInto(to) {        to || (to = new ParallelHash(this.blockLen, this.outputLen, this.leafCons, this.enableXOF));        if (this.leafHash)            to.leafHash = this.leafHash._cloneInto(to.leafHash);        to.chunkPos = this.chunkPos;        to.chunkLen = this.chunkLen;        to.chunksDone = this.chunksDone;        return super._cloneInto(to);    }    destroy() {        super.destroy.call(this);        if (this.leafHash)            this.leafHash.destroy();    }    clone() {        return this._cloneInto();    }}function genPrl(blockLen, outputLen, leaf, xof = false) {    const parallel = (message, opts) => parallel.create(opts).update(message).digest();    parallel.create = (opts = {}) => new ParallelHash(blockLen, chooseLen(opts, outputLen), () => leaf.create({ dkLen: 2 * outputLen }), xof, opts);    return parallel;}exports.parallelhash128 = (() => genPrl(168, 128 / 8, exports.cshake128))();exports.parallelhash256 = (() => genPrl(136, 256 / 8, exports.cshake256))();exports.parallelhash128xof = (() => genPrl(168, 128 / 8, exports.cshake128, true))();exports.parallelhash256xof = (() => genPrl(136, 256 / 8, exports.cshake256, true))();const genTurboshake = (blockLen, outputLen) => (0, utils_js_1.wrapXOFConstructorWithOpts)((opts = {}) => {    const D = opts.D === undefined ? 0x1f : opts.D;    // Section 2.1 of https://datatracker.ietf.org/doc/draft-irtf-cfrg-kangarootwelve/    if (!Number.isSafeInteger(D) || D < 0x01 || D > 0x7f)        throw new Error(`turboshake: wrong domain separation byte: ${D}, should be 0x01..0x7f`);    return new sha3_js_1.Keccak(blockLen, D, opts.dkLen === undefined ? outputLen : opts.dkLen, true, 12);});exports.turboshake128 = genTurboshake(168, 256 / 8);exports.turboshake256 = genTurboshake(136, 512 / 8);// Kangaroo// Same as NIST rightEncode, but returns [0] for zero stringfunction rightEncodeK12(n) {    const res = [];    for (; n > 0; n >>= 8)        res.unshift(n & 0xff);    res.push(res.length);    return new Uint8Array(res);}const EMPTY = new Uint8Array([]);class KangarooTwelve extends sha3_js_1.Keccak {    constructor(blockLen, leafLen, outputLen, rounds, opts) {        super(blockLen, 0x07, outputLen, true, rounds);        this.leafLen = leafLen;        this.chunkLen = 8192;        this.chunkPos = 0; // Position of current block in chunk        this.chunksDone = 0; // How many chunks we already have        const { personalization } = opts;        this.personalization = toBytesOptional(personalization);    }    update(data) {        data = (0, utils_js_1.toBytes)(data);        const { chunkLen, blockLen, leafLen, rounds } = this;        for (let pos = 0, len = data.length; pos < len;) {            if (this.chunkPos == chunkLen) {                if (this.leafHash)                    super.update(this.leafHash.digest());                else {                    this.suffix = 0x06; // Its safe to change suffix here since its used only in digest()                    super.update(new Uint8Array([3, 0, 0, 0, 0, 0, 0, 0]));                }                this.leafHash = new sha3_js_1.Keccak(blockLen, 0x0b, leafLen, false, rounds);                this.chunksDone++;                this.chunkPos = 0;            }            const take = Math.min(chunkLen - this.chunkPos, len - pos);            const chunk = data.subarray(pos, pos + take);            if (this.leafHash)                this.leafHash.update(chunk);            else                super.update(chunk);            this.chunkPos += take;            pos += take;        }        return this;    }    finish() {        if (this.finished)            return;        const { personalization } = this;        this.update(personalization).update(rightEncodeK12(personalization.length));        // Leaf hash        if (this.leafHash) {            super.update(this.leafHash.digest());            super.update(rightEncodeK12(this.chunksDone));            super.update(new Uint8Array([0xff, 0xff]));        }        super.finish.call(this);    }    destroy() {        super.destroy.call(this);        if (this.leafHash)            this.leafHash.destroy();        // We cannot zero personalization buffer since it is user provided and we don't want to mutate user input        this.personalization = EMPTY;    }    _cloneInto(to) {        const { blockLen, leafLen, leafHash, outputLen, rounds } = this;        to || (to = new KangarooTwelve(blockLen, leafLen, outputLen, rounds, {}));        super._cloneInto(to);        if (leafHash)            to.leafHash = leafHash._cloneInto(to.leafHash);        to.personalization.set(this.personalization);        to.leafLen = this.leafLen;        to.chunkPos = this.chunkPos;        to.chunksDone = this.chunksDone;        return to;    }    clone() {        return this._cloneInto();    }}// Default to 32 bytes, so it can be used without optsexports.k12 = (() => (0, utils_js_1.wrapConstructorWithOpts)((opts = {}) => new KangarooTwelve(168, 32, chooseLen(opts, 32), 12, opts)))();// MarsupilamiFourteenexports.m14 = (() => (0, utils_js_1.wrapConstructorWithOpts)((opts = {}) => new KangarooTwelve(136, 64, chooseLen(opts, 64), 14, opts)))();// https://keccak.team/files/CSF-0.1.pdf// + https://github.com/XKCP/XKCP/tree/master/lib/high/Keccak/PRGclass KeccakPRG extends sha3_js_1.Keccak {    constructor(capacity) {        (0, _assert_js_1.number)(capacity);        // Rho should be full bytes        if (capacity < 0 || capacity > 1600 - 10 || (1600 - capacity - 2) % 8)            throw new Error('KeccakPRG: Invalid capacity');        // blockLen = rho in bytes        super((1600 - capacity - 2) / 8, 0, 0, true);        this.rate = 1600 - capacity;        this.posOut = Math.floor((this.rate + 7) / 8);    }    keccak() {        // Duplex padding        this.state[this.pos] ^= 0x01;        this.state[this.blockLen] ^= 0x02; // Rho is full bytes        super.keccak();        this.pos = 0;        this.posOut = 0;    }    update(data) {        super.update(data);        this.posOut = this.blockLen;        return this;    }    feed(data) {        return this.update(data);    }    finish() { }    digestInto(_out) {        throw new Error('KeccakPRG: digest is not allowed, please use .fetch instead.');    }    fetch(bytes) {        return this.xof(bytes);    }    // Ensure irreversibility (even if state leaked previous outputs cannot be computed)    forget() {        if (this.rate < 1600 / 2 + 1)            throw new Error('KeccakPRG: rate too low to use forget');        this.keccak();        for (let i = 0; i < this.blockLen; i++)            this.state[i] = 0;        this.pos = this.blockLen;        this.keccak();        this.posOut = this.blockLen;    }    _cloneInto(to) {        const { rate } = this;        to || (to = new KeccakPRG(1600 - rate));        super._cloneInto(to);        to.rate = rate;        return to;    }    clone() {        return this._cloneInto();    }}const keccakprg = (capacity = 254) => new KeccakPRG(capacity);exports.keccakprg = keccakprg;//# sourceMappingURL=sha3-addons.js.map
 |