/********************************************************************
 * @author:      Kaven
 * @email:       kaven@wuwenkai.com
 * @website:     http://kavenblog.com
 * @file:        [basic] /src/libs/hashing_algorithms/KavenSHA.ts
 * @create:      2019-04-03 18:12:33.984
 * @modify:      2019-04-05 22:50:29.190
 * @version:     1.1.20
 * @times:       86
 * @lines:       698
 * @copyright:   Copyright © 2019 Kaven. All Rights Reserved.
 * @description: [description]
 * @license:
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 ********************************************************************/
import { BitString } from "../BitString";
import { Strings } from "../Strings";
// tslint:disable:no-bitwise
/**
 * SHA1 and SHA2
 */
var KavenSHA = /** @class */ (function () {
    function KavenSHA() {
    }
    Object.defineProperty(KavenSHA, "SHA512_INITIAL_HASH_VALUES", {
        /**
         * SHA-512 initial hash values(in big-endian).
         *
         * These words were obtained by taking the first sixty-four bits of
         * the fractional parts of the square roots of the first eight prime numbers.
         */
        get: function () {
            return [
                new BitString("6a09e667f3bcc908", 16),
                new BitString("bb67ae8584caa73b", 16),
                new BitString("3c6ef372fe94f82b", 16),
                new BitString("a54ff53a5f1d36f1", 16),
                new BitString("510e527fade682d1", 16),
                new BitString("9b05688c2b3e6c1f", 16),
                new BitString("1f83d9abfb41bd6b", 16),
                new BitString("5be0cd19137e2179", 16),
            ];
        },
        enumerable: true,
        configurable: true
    });
    /**
     *
     * @param str
     * @see {@link https://en.wikipedia.org/wiki/SHA-1}
     */
    KavenSHA.prototype.ComputeSHA1 = function (str) {
        /*
            Note 1: All variables are unsigned 32-bit quantities and wrap modulo 232 when calculating, except for
            ml, the message length, which is a 64-bit quantity, and
            hh, the message digest, which is a 160-bit quantity.

            Note 2: All constants in this pseudo code are in big endian.
            Within each word, the most significant byte is stored in the leftmost byte position
        */
        var message = str.ToUTF8ByteArray();
        /// Initialize variables
        var h0 = 0x67452301;
        var h1 = 0xEFCDAB89;
        var h2 = 0x98BADCFE;
        var h3 = 0x10325476;
        var h4 = 0xC3D2E1F0;
        // ml = message length in bits (always a multiple of the number of bits in a character).
        var ml = message.length * 8;
        /// Pre-processing
        // append the bit '1' to the message e.g. by adding 0x80 if message length is a multiple of 8 bits.
        message.push(0x80);
        // append 0 ≤ k < 512 bits '0', such that the resulting message length in bits
        // is congruent to −64 ≡ 448 (mod 512)
        var total = 512 - (ml % 512);
        var K = total - 8 - 64;
        var n = K / 8;
        while (n-- > 0) {
            message.push(0);
        }
        // append ml, the original message length, as a 64-bit big-endian integer.
        // Thus, the total length is a multiple of 512 bits.
        var lbe = new BitString(ml).ToBytes(64);
        message.push.apply(message, lbe);
        /// Process the message in successive 512-bit chunks
        // break message into 512-bit chunks
        var chunks = message.Split(512 / 8, true);
        // for each chunk
        for (var _i = 0, chunks_1 = chunks; _i < chunks_1.length; _i++) {
            var chunk = chunks_1[_i];
            var w = new Array(80);
            // break chunk into sixteen 32-bit big-endian words w[i], 0 ≤ i ≤ 15
            var bit32Array = chunk.Split(4, true);
            for (var j = 0; j < 16; j++) {
                var bits32 = bit32Array[j];
                w[j] = bits32[0] << 24 | bits32[1] << 16 | bits32[2] << 8 | bits32[3];
            }
            // Extend the sixteen 32-bit words into eighty 32-bit words
            // for i from 16 to 79
            for (var i = 16; i <= 79; i++) {
                // w[i] = (w[i-3] xor w[i-8] xor w[i-14] xor w[i-16]) leftrotate 1
                // w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).LeftRotate(1).ToInt32();
                if (i < 32) {
                    // w[i] = (w[i-3] xor w[i-8] xor w[i-14] xor w[i-16]) leftrotate 1
                    w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).LeftRotate(1).ToUInt32();
                }
                else {
                    // This transformation keeps all operands 64-bit aligned and,
                    // by removing the dependency of w[i] on w[i-3],
                    // allows efficient SIMD implementation with a vector length of 4 like x86 SSE instructions.
                    // the rounds 32–79 the computation can be replaced with:
                    // w[i] = (w[i-6] xor w[i-16] xor w[i-28] xor w[i-32]) leftrotate 2
                    w[i] = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]).LeftRotate(2).ToUInt32();
                }
            }
            // Initialize hash value for this chunk
            var a = h0;
            var b = h1;
            var c = h2;
            var d = h3;
            var e = h4;
            var f = void 0;
            var k = void 0;
            /// Main loop
            // for i from 0 to 79
            for (var i = 0; i <= 79; i++) {
                if (0 <= i && i <= 19) { // if 0 ≤ i ≤ 19 then
                    // f = (b and c) or ((not b) and d)
                    f = (b & c) | ((~b) & d);
                    // Instead of the formulation from the original FIPS PUB 180-1 shown,
                    // the following equivalent expressions may be used to compute f in the main loop above:
                    // Bitwise choice between c and d, controlled by b.
                    /*
                        f = d xor (b and (c xor d))        (alternative 1)
                        f = (b and c) xor ((not b) and d)  (alternative 2)
                        f = (b and c) + ((not b) and d)    (alternative 3)
                        f = vec_sel(d, c, b)               (alternative 4)
                    */
                    // k = 0x5A827999
                    k = 0x5A827999;
                }
                else if (20 <= i && i <= 39) { // else if 20 ≤ i ≤ 39
                    // f = b xor c xor d
                    f = b ^ c ^ d;
                    // k = 0x6ED9EBA1
                    k = 0x6ED9EBA1;
                }
                else if (40 <= i && i <= 59) { // else if 40 ≤ i ≤ 59
                    // f = (b and c) or (b and d) or (c and d)
                    f = (b & c) | (b & d) | (c & d);
                    // Bitwise majority function.
                    /*
                        f = (b and c) or (d and (b or c))          (alternative 1)
                        f = (b and c) or (d and (b xor c))         (alternative 2)
                        f = (b and c) xor (d and (b xor c))        (alternative 3)
                        f = (b and c) + (d and (b xor c))          (alternative 4)
                        f = (b and c) xor (b and d) xor (c and d)  (alternative 5)
                        f = vec_sel(c, b, c xor d)                 (alternative 6)
                    */
                    // k = 0x8F1BBCDC
                    k = 0x8F1BBCDC;
                }
                else if (60 <= i && i <= 79) { // else if 60 ≤ i ≤ 79
                    // f = b xor c xor d
                    f = b ^ c ^ d;
                    // k = 0xCA62C1D6
                    k = 0xCA62C1D6;
                }
                if (f === undefined || k === undefined) {
                    throw new Error("k or f is undefined, k: " + k + ", f: " + f);
                }
                var temp = ((a.LeftRotate(5)) + f + e + k + w[i]).ToUInt32();
                e = d;
                d = c;
                c = b.LeftRotate(30).ToUInt32();
                b = a;
                a = temp;
            }
            /// Add this chunk's hash to result so far
            h0 = (h0 + a).ToUInt32();
            h1 = (h1 + b).ToUInt32();
            h2 = (h2 + c).ToUInt32();
            h3 = (h3 + d).ToUInt32();
            h4 = (h4 + e).ToUInt32();
        }
        /// Produce the final hash value (big-endian) as a 160-bit number:
        // hh = (h0 leftshift 128) or (h1 leftshift 96) or (h2 leftshift 64) or (h3 leftshift 32) or h4
        // const hh = (h0 << 128) | (h1 << 96) | (h2 << 64) | (h3 << 32) | h4;
        var result = [h0, h1, h2, h3, h4];
        var hash = result.ToHEX();
        return hash;
    };
    /**
     *
     * @param str
     * @see {@link https://en.wikipedia.org/wiki/SHA-2}
     */
    KavenSHA.prototype.ComputeSHA256 = function (str) {
        var initialHashValues = [
            0x6a09e667,
            0xbb67ae85,
            0x3c6ef372,
            0xa54ff53a,
            0x510e527f,
            0x9b05688c,
            0x1f83d9ab,
            0x5be0cd19,
        ];
        var data = str.ToUTF8ByteArray();
        var result = this.compute_224_256(data, initialHashValues);
        var hash = result.ToHEX();
        return hash;
    };
    KavenSHA.prototype.ComputeSHA224 = function (str) {
        // The second 32 bits of the fractional parts of the square roots of the 9th through 16th primes 23..53
        var initialHashValues = [
            0xc1059ed8,
            0x367cd507,
            0x3070dd17,
            0xf70e5939,
            0xffc00b31,
            0x68581511,
            0x64f98fa7,
            0xbefa4fa4,
        ];
        var data = str.ToUTF8ByteArray();
        var result = this.compute_224_256(data, initialHashValues);
        // the output is constructed by omitting h7.
        result.splice(-1, 1);
        var hash = result.ToHEX();
        return hash;
    };
    KavenSHA.prototype.ComputeSHA512 = function (str) {
        var data = str.ToUTF8ByteArray();
        var result = this.compute_384_512(data, KavenSHA.SHA512_INITIAL_HASH_VALUES);
        var hash = result.map(function (p) { return p.HEX; }).join(Strings.Empty);
        return hash;
    };
    KavenSHA.prototype.ComputeSHA384 = function (str) {
        /*
            SHA-384 is identical to SHA-512, except that:

            > the initial hash values h0 through h7 are different (taken from the 9th through 16th primes), and
            > the output is constructed by omitting h6 and h7.
        */
        // SHA-384 initial hash values (in big-endian)
        var initialHashValues = [
            new BitString("cbbb9d5dc1059ed8", 16),
            new BitString("629a292a367cd507", 16),
            new BitString("9159015a3070dd17", 16),
            new BitString("152fecd8f70e5939", 16),
            new BitString("67332667ffc00b31", 16),
            new BitString("8eb44a8768581511", 16),
            new BitString("db0c2e0d64f98fa7", 16),
            new BitString("47b5481dbefa4fa4", 16),
        ];
        var data = str.ToUTF8ByteArray();
        var result = this.compute_384_512(data, initialHashValues);
        result.splice(-2, 2);
        var hash = result.map(function (p) { return p.HEX; }).join(Strings.Empty);
        return hash;
    };
    KavenSHA.prototype.ComputeSHA512T = function (str, t) {
        /*
            SHA-512/t is identical to SHA-512 except that:

            > the initial hash values h0 through h7 are given by the SHA-512/t IV generation function,
            > the output is constructed by truncating the concatenation of h0 through h7 at t bits,
            > t equal to 384 is not allowed, instead SHA-384 should be used as specified, and
            > t values 224 and 256 are especially mentioned as approved.
         */
        if (t === 384) {
            throw new Error("t equal to 384 is not allowed, instead SHA-384 should be used as specified.");
        }
        // Denote H(0)′ to be the initial hash value of SHA-512.
        // Hi(0)′′ = Hi(0)′ ⊕ a5a5a5a5a5a5a5a5(in hex).
        var xorValue = new BitString("a5a5a5a5a5a5a5a5", 16);
        var xorValues = KavenSHA.SHA512_INITIAL_HASH_VALUES.map(function (p) { return p.XOR(xorValue); });
        // H(0) = SHA-512 ("SHA-512/t") using H(0)′′ as the IV, where t is the specific truncation value.
        var name = "SHA-512/" + t;
        var initialHashValues = this.compute_384_512(name.ToUTF8ByteArray(), xorValues);
        var data = str.ToUTF8ByteArray();
        var result = this.compute_384_512(data, initialHashValues);
        var hash = result.map(function (p) { return p.HEX; }).join(Strings.Empty);
        return hash.substr(0, t / 4);
    };
    KavenSHA.prototype.compute_224_256 = function (data, initialHashValues) {
        // Note 1:
        // All variables are 32 bit unsigned integers and addition is calculated modulo 232
        // Note 2:
        // For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 ≤ i ≤ 63
        // Note 3:
        // The compression function uses 8 working variables, a through h
        // Note 4:
        // Big-endian convention is used when expressing the constants in this pseudocode,
        // and when parsing message block data from bytes to words, for example,
        // the first word of the input message "abc" after padding is 0x61626380
        var k = [
            0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
            0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
            0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
            0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
            0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
            0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
            0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
            0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
        ];
        /// Initialize hash values
        // (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
        var h0 = initialHashValues[0];
        var h1 = initialHashValues[1];
        var h2 = initialHashValues[2];
        var h3 = initialHashValues[3];
        var h4 = initialHashValues[4];
        var h5 = initialHashValues[5];
        var h6 = initialHashValues[6];
        var h7 = initialHashValues[7];
        /// Pre-processing (Padding)
        // begin with the original message of length L bits
        var L = data.length * 8;
        // append a single '1' bit
        data.push(0x80); // 8 bits
        // append K '0' bits, where K is the minimum number >= 0 such that L + 1 + K + 64 is a multiple of 512
        var total = 512 - (L % 512);
        var K = total - 8 - 64;
        var n = K / 8;
        while (n-- > 0) {
            data.push(0);
        }
        // append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits
        var lbe = new BitString(L).ToBytes(64);
        data.push.apply(data, lbe);
        /// Process the message in successive 512-bit chunks:
        // break message into 512-bit chunks
        var chunksCount = data.length / 64; // Math.ceil(L / 512);
        // for each chunk
        for (var chunkIndex = 0; chunkIndex < chunksCount; chunkIndex++) {
            var chunk = data.slice(chunkIndex * 64, (chunkIndex + 1) * 64);
            if (chunk.length !== 64) {
                throw new Error("chunk length error: " + chunk.length);
            }
            // create a 64-entry message schedule array w[0..63] of 32-bit words
            var w = new Array(64);
            // copy chunk into first 16 words w[0..15] of the message schedule array
            var bit32Array = chunk.Split(4, true);
            for (var j = 0; j < 16; j++) {
                var bits32 = bit32Array[j];
                w[j] = bits32[0] << 24 | bits32[1] << 16 | bits32[2] << 8 | bits32[3];
            }
            // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
            for (var i = 16; i < 64; i++) {
                // s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
                var s0 = (w[i - 15].RightRotate(7)) ^ (w[i - 15].RightRotate(18)) ^ (w[i - 15] >>> 3);
                // s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
                var s1 = (w[i - 2].RightRotate(17)) ^ (w[i - 2].RightRotate(19)) ^ (w[i - 2] >>> 10);
                // w[i] := w[i-16] + s0 + w[i-7] + s1
                w[i] = (w[i - 16] + s0 + w[i - 7] + s1).ToUInt32();
            }
            // Initialize working variables to current hash value
            var a = h0;
            var b = h1;
            var c = h2;
            var d = h3;
            var e = h4;
            var f = h5;
            var g = h6;
            var h = h7;
            // Compression function main loop
            for (var i = 0; i < 64; i++) {
                // S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
                var S1 = (e.RightRotate(6)) ^ (e.RightRotate(11)) ^ (e.RightRotate(25));
                // ch := (e and f) xor ((not e) and g)
                var ch = (e & f) ^ ((~e) & g);
                // temp1 := h + S1 + ch + k[i] + w[i]
                var temp1 = h + S1 + ch + k[i] + w[i];
                // S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
                var S0 = (a.RightRotate(2)) ^ (a.RightRotate(13)) ^ (a.RightRotate(22));
                // maj := (a and b) xor (a and c) xor (b and c)
                var maj = (a & b) ^ (a & c) ^ (b & c);
                // temp2 := S0 + maj
                var temp2 = S0 + maj;
                h = g;
                g = f;
                f = e;
                e = (d + temp1).ToUInt32();
                d = c;
                c = b;
                b = a;
                a = (temp1 + temp2).ToUInt32();
            }
            // Add the compressed chunk to the current hash value
            h0 = (h0 + a).ToUInt32();
            h1 = (h1 + b).ToUInt32();
            h2 = (h2 + c).ToUInt32();
            h3 = (h3 + d).ToUInt32();
            h4 = (h4 + e).ToUInt32();
            h5 = (h5 + f).ToUInt32();
            h6 = (h6 + g).ToUInt32();
            h7 = (h7 + h).ToUInt32();
        }
        // Produce the final hash value (big-endian):
        // digest := hash := h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7
        var result = [h0, h1, h2, h3, h4, h5, h6, h7];
        return result;
    };
    KavenSHA.prototype.compute_384_512 = function (data, initialHashValues) {
        /*
            SHA-512 is identical in structure to SHA-256, but:

            > the message is broken into 1024-bit chunks,
            > the initial hash values and round constants are extended to 64 bits,
            > there are 80 rounds instead of 64,
            > the message schedule array w has 80 64-bit words instead of 64 32-bit words,
            > to extend the message schedule array w, the loop is from 16 to 79 instead of from 16 to 63,
            > the round constants are based on the first 80 primes 2..409,
            > the word size used for calculations is 64 bits long,
            > the appended length of the message (before pre-processing), in bits, is a 128-bit big-endian integer, and
            > the shift and rotate amounts used are different.
        */
        var k = [
            // tslint:disable:max-line-length
            new BitString("428a2f98d728ae22", 16), new BitString("7137449123ef65cd", 16), new BitString("b5c0fbcfec4d3b2f", 16), new BitString("e9b5dba58189dbbc", 16), new BitString("3956c25bf348b538", 16),
            new BitString("59f111f1b605d019", 16), new BitString("923f82a4af194f9b", 16), new BitString("ab1c5ed5da6d8118", 16), new BitString("d807aa98a3030242", 16), new BitString("12835b0145706fbe", 16),
            new BitString("243185be4ee4b28c", 16), new BitString("550c7dc3d5ffb4e2", 16), new BitString("72be5d74f27b896f", 16), new BitString("80deb1fe3b1696b1", 16), new BitString("9bdc06a725c71235", 16),
            new BitString("c19bf174cf692694", 16), new BitString("e49b69c19ef14ad2", 16), new BitString("efbe4786384f25e3", 16), new BitString("0fc19dc68b8cd5b5", 16), new BitString("240ca1cc77ac9c65", 16),
            new BitString("2de92c6f592b0275", 16), new BitString("4a7484aa6ea6e483", 16), new BitString("5cb0a9dcbd41fbd4", 16), new BitString("76f988da831153b5", 16), new BitString("983e5152ee66dfab", 16),
            new BitString("a831c66d2db43210", 16), new BitString("b00327c898fb213f", 16), new BitString("bf597fc7beef0ee4", 16), new BitString("c6e00bf33da88fc2", 16), new BitString("d5a79147930aa725", 16),
            new BitString("06ca6351e003826f", 16), new BitString("142929670a0e6e70", 16), new BitString("27b70a8546d22ffc", 16), new BitString("2e1b21385c26c926", 16), new BitString("4d2c6dfc5ac42aed", 16),
            new BitString("53380d139d95b3df", 16), new BitString("650a73548baf63de", 16), new BitString("766a0abb3c77b2a8", 16), new BitString("81c2c92e47edaee6", 16), new BitString("92722c851482353b", 16),
            new BitString("a2bfe8a14cf10364", 16), new BitString("a81a664bbc423001", 16), new BitString("c24b8b70d0f89791", 16), new BitString("c76c51a30654be30", 16), new BitString("d192e819d6ef5218", 16),
            new BitString("d69906245565a910", 16), new BitString("f40e35855771202a", 16), new BitString("106aa07032bbd1b8", 16), new BitString("19a4c116b8d2d0c8", 16), new BitString("1e376c085141ab53", 16),
            new BitString("2748774cdf8eeb99", 16), new BitString("34b0bcb5e19b48a8", 16), new BitString("391c0cb3c5c95a63", 16), new BitString("4ed8aa4ae3418acb", 16), new BitString("5b9cca4f7763e373", 16),
            new BitString("682e6ff3d6b2b8a3", 16), new BitString("748f82ee5defb2fc", 16), new BitString("78a5636f43172f60", 16), new BitString("84c87814a1f0ab72", 16), new BitString("8cc702081a6439ec", 16),
            new BitString("90befffa23631e28", 16), new BitString("a4506cebde82bde9", 16), new BitString("bef9a3f7b2c67915", 16), new BitString("c67178f2e372532b", 16), new BitString("ca273eceea26619c", 16),
            new BitString("d186b8c721c0c207", 16), new BitString("eada7dd6cde0eb1e", 16), new BitString("f57d4f7fee6ed178", 16), new BitString("06f067aa72176fba", 16), new BitString("0a637dc5a2c898a6", 16),
            new BitString("113f9804bef90dae", 16), new BitString("1b710b35131c471b", 16), new BitString("28db77f523047d84", 16), new BitString("32caab7b40c72493", 16), new BitString("3c9ebe0a15c9bebc", 16),
            new BitString("431d67c49c100d4c", 16), new BitString("4cc5d4becb3e42b6", 16), new BitString("597f299cfc657e2a", 16), new BitString("5fcb6fab3ad6faec", 16), new BitString("6c44198c4a475817", 16),
        ];
        /// Initialize hash values
        var h0 = initialHashValues[0];
        var h1 = initialHashValues[1];
        var h2 = initialHashValues[2];
        var h3 = initialHashValues[3];
        var h4 = initialHashValues[4];
        var h5 = initialHashValues[5];
        var h6 = initialHashValues[6];
        var h7 = initialHashValues[7];
        /// Pre-processing (Padding)
        // begin with the original message of length L bits
        var L = data.length * 8;
        // append a single '1' bit
        data.push(0x80); // 8 bits
        // append K '0' bits, where K is the minimum number >= 0 such that L + 1 + K + 64 is a multiple of 1024
        var total = 1024 - (L % 1024);
        var K = total - 8 - 64;
        var n = K / 8;
        while (n-- > 0) {
            data.push(0);
        }
        // append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits
        var lbe = new BitString(L).ToBytes(64);
        data.push.apply(data, lbe);
        /// Process the message in successive 1024-bit chunks:
        // break message into 1024-bit chunks
        var chunksCount = data.length / 128; // 128 = 1024 / 8
        // for each chunk
        for (var chunkIndex = 0; chunkIndex < chunksCount; chunkIndex++) {
            var chunk = data.slice(chunkIndex * 128, (chunkIndex + 1) * 128);
            if (chunk.length !== 128) {
                throw new Error("chunk length error: " + chunk.length);
            }
            // create a 80-entry message schedule array w[0..79] of 64-bit words
            var w = new Array(80);
            // copy chunk into first 16 words w[0..15] of the message schedule array
            var bit64Array = chunk.Split(8, true);
            for (var j = 0; j < 16; j++) {
                var bits32 = bit64Array[j];
                var b1 = new BitString(bits32[0]).LeftShift(56);
                var b2 = new BitString(bits32[1]).LeftShift(48);
                var b3 = new BitString(bits32[2]).LeftShift(40);
                var b4 = new BitString(bits32[3]).LeftShift(32);
                var b5 = new BitString(bits32[4]).LeftShift(24);
                var b6 = new BitString(bits32[5]).LeftShift(16);
                var b7 = new BitString(bits32[6]).LeftShift(8);
                var b8 = new BitString(bits32[7]);
                w[j] = b1.OR(b2).OR(b3).OR(b4).OR(b5).OR(b6).OR(b7).OR(b8);
            }
            // Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array
            for (var i = 16; i <= 79; i++) {
                // s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7)
                var s0 = w[i - 15].RightRotate(1).XOR(w[i - 15].RightRotate(8)).XOR(w[i - 15].RightShift(7));
                // s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6)
                var s1 = w[i - 2].RightRotate(19).XOR(w[i - 2].RightRotate(61)).XOR(w[i - 2].RightShift(6));
                // w[i] := w[i-16] + s0 + w[i-7] + s1
                w[i] = w[i - 16].Add(s0).Add(w[i - 7].Add(s1)).SetLength(64);
            }
            // Initialize working variables to current hash value
            var a = h0;
            var b = h1;
            var c = h2;
            var d = h3;
            var e = h4;
            var f = h5;
            var g = h6;
            var h = h7;
            // Compression function main loop
            for (var i = 0; i < 80; i++) {
                // S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)
                var S1 = e.RightRotate(14).XOR(e.RightRotate(18)).XOR(e.RightRotate(41));
                // ch := (e and f) xor ((not e) and g)
                var ch = e.AND(f).XOR(e.NOT().AND(g));
                // temp1 := h + S1 + ch + k[i] + w[i]
                var temp1 = h.Add(S1).Add(ch).Add(k[i]).Add(w[i]);
                // S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)
                var S0 = a.RightRotate(28).XOR(a.RightRotate(34)).XOR(a.RightRotate(39));
                // maj := (a and b) xor (a and c) xor (b and c)
                var maj = a.AND(b).XOR(a.AND(c)).XOR(b.AND(c));
                // temp2 := S0 + maj
                var temp2 = S0.Add(maj);
                h = g;
                g = f;
                f = e;
                e = d.Add(temp1).SetLength(64);
                d = c;
                c = b;
                b = a;
                a = temp1.Add(temp2).SetLength(64);
            }
            // Add the compressed chunk to the current hash value
            h0 = h0.Add(a).SetLength(64);
            h1 = h1.Add(b).SetLength(64);
            h2 = h2.Add(c).SetLength(64);
            h3 = h3.Add(d).SetLength(64);
            h4 = h4.Add(e).SetLength(64);
            h5 = h5.Add(f).SetLength(64);
            h6 = h6.Add(g).SetLength(64);
            h7 = h7.Add(h).SetLength(64);
        }
        // Produce the final hash value (big-endian):
        // digest := hash := h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7
        var result = [h0, h1, h2, h3, h4, h5, h6, h7];
        return result;
    };
    return KavenSHA;
}());
export { KavenSHA };
//# sourceMappingURL=KavenSHA.js.map