1
\$\begingroup\$

As told by experts, I am re-posting the code review request with the code.

Brief Description:

  1. from outside sha256() will be called with parameter having UTF-16 character set.

  2. then after prepareData() and initializing variables, the hash() will be called with converted binary message string (having pad and 64 bits message length appended) as parameter inside sha256(). The number of calls is ((total message length) / 512). Each hash function includes 64 internal rounds.

  3. With that the initialized hash value 8 * (32 bits) = 256 bits initialized hash value will be updated to final value in the last loop. After adding those up to a string, we are getting the final hash value of 256 bits.

I just want to get my code reviewed, and any suggestion or help will be worth to welcome.

The following is my script.js file.

var H = [];
var W = [];

function sha256 (input) {
    var output = "";
    input = prepareInputBits (input);
    var n = Math.floor (input.length / 512);
    prepareData();

    for (i = 0; i < n; i++) { // (n * 512 bits) chunk
        hash (input.substr (i * 512, 512));
    }

    for (i = 0; i < H.length; i++) {
        output += H[i];
    }

    output = convertBase2To16 (output);

    return output;
}

function hash (input) { // 512 bits in
    var i;
    let sigma0 = "";
    let sigma1 = "";

    /*
    ** 64 rounds = (16 + 48) rounds
    ** for first 16 rounds, 512 bits = 16 * 32 bits = 16 words
    ** for next 48 rounds, calculate round word, W[i]
    */

    for (i = 0; i < 64; i++) {
        if (i < 16) {
            W[i] = input.substr(32 * i, 32);
        } else {
            sigma0 = bitsXor (bitsXor (rotateRight (W[i-15], 7), rotateRight (W[i-15], 18)), shiftRight (W[i-15], 3));
            sigma1 = bitsXor (bitsXor (rotateRight (W[i-2], 17), rotateRight (W[i-2], 19)), shiftRight (W[i-2], 10));
            W[i] = bitsAdd (W[i-16], W[i-7]);
            W[i] = bitsAdd (W[i], bitsAdd (sigma0, sigma1));
        }
    }

    let t0 = null;
    let t1 = null;

    for (var round = 0; round < 64; round++) {
        t0 = bitsAdd (H[7], bitsAdd (bitsAdd (Ep1(H[4]), Ch(H[4], H[5], H[6])), bitsAdd (_K[round], W[round])));
        t1 = bitsAdd (Ep0(H[0]), Maj(H[0], H[1], H[2]));

        H[7] = H[6];
        H[6] = H[5];
        H[5] = H[4];
        H[4] = bitsAdd (H[3], t0);
        H[3] = H[2];
        H[2] = H[1];
        H[1] = H[0];
        H[0] = bitsAdd (t0, t1);
    }
}

function prepareInputBits (input) {
    // binary-message + padding (1000...) + message-length (64 bits) => 0 (modulo 512)
    var output = "";
    var i, x;

    // converting character ASCII or UTF to hex-number (16 bits each) string
    for (i = 0; i < input.length; i++) {
        x = convertBase10To2 (input.charCodeAt(i));
        output += padLeftZeroes (x, (16 - x.length));
    }

    // getting 64 bit message length
    let msgLen = convertBase10To2 (output.length);
    msgLen = padLeftZeroes (msgLen, 64 - msgLen.length);

    x = output.length % 512; // getting extra bits length
    let nP = 0; // number of zeroes in pad

    if (x == 0) {
        // add new block
        nP = 512 - 65; // 65 = 64 + 1
    } else if (x > 447) {
        // add new block
        nP = (512 - x) + (512 - 65);
    } else {
        // use last block
        nP = 512 - x - 65;
    }

    output = output + "1" + padLeftZeroes ("", nP) + msgLen;
    console.log(output);

    return output;
}

function prepareData() {
    var i;

    // initialize hash value with base hash constants
    H = [];
    for (i = 0; i < 8; i++) {
        H.push(_H[i]);
    }

    // initialize word with 64 empty string
    W = [];
    for (i = 0; i < 64; i++) {
        W.push("");
    }
}

// *** basic hash functions ***
function Ch (E, F, G) {
    return bitsXor (bitsAnd (E, F), bitsAnd (bitsNot (E), G));
}

function Maj (A, B, C) {
    return bitsXor (bitsXor (bitsAnd (A, B), bitsAnd (B, C)), bitsAnd (C, A));
}

function Ep0 (A) {
    return bitsXor (bitsXor (rotateRight(A, 2), rotateRight(A, 13)), rotateRight(A, 22));
}

function Ep1 (E) {
    return bitsXor (bitsXor (rotateRight(E, 6), rotateRight(E, 11)), rotateRight(E, 25));
}

// *** basic binary functions ***
function padLeftZeroes (input, numberOfZeroes) {
    var initialZeroes = "";

    for (var i = 0; i < numberOfZeroes; i++) {
        initialZeroes += "0";
    }

    return (initialZeroes + input);
}

function convertBase10To2 (input) {
    var output = "";

    while (input != 0) {
        output = (input % 2) + output;
        input = Math.floor(input / 2);
    }

    return output;
}

function convertBase2To10 (base2s) {
    var  base10n = 0;

    for (var i = 0; i < base2s.length; i++) {
        base10n = 2 * base10n + ((base2s[i] == "1") ? 1 : 0);
    }

    return base10n;
}

function convertBase2To16 (input) {
    let listNibbles = ["0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"];
    let listDigits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
    let output = "";
    var x = (input.length % 4);

    if (x != 0) {
        input = padLeftZeroes(input, 4 - x);
    }

    for (var i = 0; i < input.length; i += 4) {
        for (var j = 0; j < 16; j++) {
            if (input.substr(i, 4) == listNibbles[j]) {
                break;
            }
        }

        output += listDigits[j];
    }

    return output;
}

function convertToNibbles (input) {
    var output = "";

    for (var i = 0; i < input.length; i += 4) {
        output += getNibble (input.substr(i, 4));
    }

    return output;
}

function getNibble (base2s) {
    var base16s = "";
    const list = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];

    base16s = list[convertBase2To10 (base2s)];
    return base16s;
}

// *** basic bits functions ***
function shiftRight (input, numberOfBits) {
    var output = "";

    output = input.substring(0, numberOfBits);
    output = padLeftZeroes(output, input.length - numberOfBits);

    return output;
}

function rotateLeft (input, numberOfBits) {
    var output = "";
    output = input.substring(numberOfBits, input.length) + input.substring(0, numberOfBits);
    return output;
}

function rotateRight (input, numberOfBits) {
    var output = "";
    output = input.substring(input.length - numberOfBits, input.length) + input.substring(0, input.length - numberOfBits);
    return output;
}

// *** basic gate functions ***
function bitNot (x) {
    return (x == '0') ? '1' : '0';
}

function bitOr (x, y) {
    return (x == '1' || y == '1') ? '1' : '0';
}

function bitXor (x, y) {
    return (x == y) ? '0' : '1';
}

function bitAnd (x, y) {
    return (x == '0' || y == '0') ? '0' : '1';
}

// *** bunch gates functions ***
function bitsOr (a, b) {
    var c = "";

    if (a.length != b.length) {
        a = padLeftZeroes (a, b.length - a.length);
        b = padLeftZeroes (b, a.length - b.length);
    }

    for (var i = 0; i < a.length; i++) {
        c += bitOr (a[i], b[i]);
    }

    return c;
}

function bitsAnd (a, b) {
    var c = "";

    if (a.length != b.length) {
        a = padLeftZeroes(a, b.length - a.length);
        b = padLeftZeroes(b, a.length - b.length);
    }

    for (var i = 0; i < a.length; i++) {
        c += bitAnd (a[i], b[i]);
    }

    return c;
}

function bitsNot (a) {
    var b = "";

    for (var i = 0; i < a.length; i++) {
        b += bitNot (a[i]);
    }

    return b;
}

function bitsXor (a, b) {
    var c = "";

    if (a.length != b.length) {
        a = padLeftZeroes(a, b.length - a.length);
        b = padLeftZeroes(b, a.length - b.length);
    }

    for (var i = 0; i < a.length; i++) {
        c += bitXor (a[i], b[i]);
    }

    return c;
}

// basic arithmetic functions
function bitAdd (c_in, x, y) {
    let xor = bitXor (x, y);
    let c_out = bitOr (bitAnd (x, y), bitAnd (c_in, xor));
    let s = bitXor (c_in, xor);
    return (c_out + s);
}

function bitsAdd (a, b) {
    var i = 0;
    var s = "";
    var c = '0';
    let x = "";

    if (a.length != b.length) {
        a = padLeftZeroes (a, b.length - a.length);
        b = padLeftZeroes (b, a.length - b.length);
    }

    for (i = a.length - 1; i >= 0; i--) {
        x = bitAdd (c, a[i], b[i]);
        c = x[0];
        s = x[1] + s;
    }

    s = c + s;

    return trimNumber (s, a.length);
}

function trimNumber (input, bitsLength) {
    let x = input.length - bitsLength;
    return input.substr (x, bitsLength);
}

And the following is my data.js file content

const _K = [
    "01000010100010100010111110011000",
    "01110001001101110100010010010001",
    "10110101110000001111101111001111",
    "11101001101101011101101110100101",
    "00111001010101101100001001011011",
    "01011001111100010001000111110001",
    "10010010001111111000001010100100",
    "10101011000111000101111011010101",
    "11011000000001111010101010011000",
    "00010010100000110101101100000001",
    "00100100001100011000010110111110",
    "01010101000011000111110111000011",
    "01110010101111100101110101110100",
    "10000000110111101011000111111110",
    "10011011110111000000011010100111",
    "11000001100110111111000101110100",
    "11100100100110110110100111000001",
    "11101111101111100100011110000110",
    "00001111110000011001110111000110",
    "00100100000011001010000111001100",
    "00101101111010010010110001101111",
    "01001010011101001000010010101010",
    "01011100101100001010100111011100",
    "01110110111110011000100011011010",
    "10011000001111100101000101010010",
    "10101000001100011100011001101101",
    "10110000000000110010011111001000",
    "10111111010110010111111111000111",
    "11000110111000000000101111110011",
    "11010101101001111001000101000111",
    "00000110110010100110001101010001",
    "00010100001010010010100101100111",
    "00100111101101110000101010000101",
    "00101110000110110010000100111000",
    "01001101001011000110110111111100",
    "01010011001110000000110100010011",
    "01100101000010100111001101010100",
    "01110110011010100000101010111011",
    "10000001110000101100100100101110",
    "10010010011100100010110010000101",
    "10100010101111111110100010100001",
    "10101000000110100110011001001011",
    "11000010010010111000101101110000",
    "11000111011011000101000110100011",
    "11010001100100101110100000011001",
    "11010110100110010000011000100100",
    "11110100000011100011010110000101",
    "00010000011010101010000001110000",
    "00011001101001001100000100010110",
    "00011110001101110110110000001000",
    "00100111010010000111011101001100",
    "00110100101100001011110010110101",
    "00111001000111000000110010110011",
    "01001110110110001010101001001010",
    "01011011100111001100101001001111",
    "01101000001011100110111111110011",
    "01110100100011111000001011101110",
    "01111000101001010110001101101111",
    "10000100110010000111100000010100",
    "10001100110001110000001000001000",
    "10010000101111101111111111111010",
    "10100100010100000110110011101011",
    "10111110111110011010001111110111",
    "11000110011100010111100011110010"
];

var _H = [
    "01101010000010011110011001100111",
    "10111011011001111010111010000101",
    "00111100011011101111001101110010",
    "10100101010011111111010100111010",
    "01010001000011100101001001111111",
    "10011011000001010110100010001100",
    "00011111100000111101100110101011",
    "01011011111000001100110100011001"
];

function abc() {
    var list = [
        "428a2f98", "71374491", "b5c0fbcf", "e9b5dba5", "3956c25b", "59f111f1", "923f82a4", "ab1c5ed5",
        "d807aa98", "12835b01", "243185be", "550c7dc3", "72be5d74", "80deb1fe", "9bdc06a7", "c19bf174",
        "e49b69c1", "efbe4786", "0fc19dc6", "240ca1cc", "2de92c6f", "4a7484aa", "5cb0a9dc", "76f988da",
        "983e5152", "a831c66d", "b00327c8", "bf597fc7", "c6e00bf3", "d5a79147", "06ca6351", "14292967",
        "27b70a85", "2e1b2138", "4d2c6dfc", "53380d13", "650a7354", "766a0abb", "81c2c92e", "92722c85",
        "a2bfe8a1", "a81a664b", "c24b8b70", "c76c51a3", "d192e819", "d6990624", "f40e3585", "106aa070",
        "19a4c116", "1e376c08", "2748774c", "34b0bcb5", "391c0cb3", "4ed8aa4a", "5b9cca4f", "682e6ff3",
        "748f82ee", "78a5636f", "84c87814", "8cc70208", "90befffa", "a4506ceb", "bef9a3f7", "c67178f2"
    ];

    list = ["6a09e667", "bb67ae85", "3c6ef372", "a54ff53a", "510e527f", "9b05688c", "1f83d9ab", "5be0cd19"];

    const hex = {
        "0" : "0000", "1" : "0001", "2" : "0010", "3" : "0011",
        "4" : "0100", "5" : "0101", "6" : "0110", "7" : "0111",
        "8" : "1000", "9" : "1001", "a" : "1010", "b" : "1011",
        "c" : "1100", "d" : "1101", "e" : "1110", "f" : "1111"
    };

    for (var i = 0; i < list.length; i++) {
        var str = list[i];
        var output = "";

        for (var j = 0; j < str.length; j++) {
            output += hex[str[j]];
        }

        console.log(output);
    }
}
\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.