{"id":21885000,"url":"https://github.com/codegasms/sha256","last_synced_at":"2025-10-08T14:07:49.087Z","repository":{"id":231778224,"uuid":"782213830","full_name":"codegasms/sha256","owner":"codegasms","description":"SHA-256 hash function implementation in Javascript","archived":false,"fork":false,"pushed_at":"2024-04-09T07:07:33.000Z","size":1065,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-14T07:29:37.436Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codegasms.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-04T21:20:16.000Z","updated_at":"2024-04-08T04:04:02.000Z","dependencies_parsed_at":"2024-04-05T22:25:21.428Z","dependency_job_id":"6816098b-2894-4a6e-8583-cb760e6038a9","html_url":"https://github.com/codegasms/sha256","commit_stats":{"total_commits":15,"total_committers":2,"mean_commits":7.5,"dds":0.06666666666666665,"last_synced_commit":"016c45b1274c05257b8d6a9990d9dff98dceed1f"},"previous_names":["codegasms/sha256"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/codegasms/sha256","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codegasms%2Fsha256","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codegasms%2Fsha256/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codegasms%2Fsha256/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codegasms%2Fsha256/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codegasms","download_url":"https://codeload.github.com/codegasms/sha256/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codegasms%2Fsha256/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278956330,"owners_count":26075221,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-28T10:18:15.568Z","updated_at":"2025-10-08T14:07:49.069Z","avatar_url":"https://github.com/codegasms.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SHA-256 Algorithm\n\n## Usage\n\n```javascript\n    const hashString = require('@codegasms/sha256');\n\n    const message = 'Hello World';\n    \n    const hashedMessageHex = hashString(message, 'hex');\n    const hashedMessageBinary = hashString(message, 'binary');\n    const hashedMessageBase64 = hashString(message, 'base64');\n```\n\n## Unicode Codepoint To UTF-8 Conversion\n\n```Unicode``` is represented as ```U+XXXX```, where ```XXXX``` is a hexadecimal number. ```UTF-8``` is a direct mapping of the unicode characters i.e. Encoding format of Unicode characters in one-byte units, hence the suffix ```-8```, more specifically it is a conversion of a codepoint into a set of one to four bytes.\n\n1. **Range 1 : 0xxxxxxx**\n\n    Out of the available 8-bits, 1-bit is reserved to show that this is of Type-1 UTF-8 i.e. one-byte encoding. The rest of the bits i.e. 7-bits can be used to map $2^7 = 128$ numbers.\n\n    _e.g._ ```U+0047``` (Unicode of A i.e ASCII \"A\") is mapped as [0 1 0 0 0 0 0 1]\n\n    \u003e This contains the mappings of ASCII characters (0-127)\n\n2. **Range 2 : 110xxxxx 10xxxxxx**\n\n    Out of the available 16-bits, first 3-bits of the first byte are reserved to show that this is of Type-2 UTF-8 i.e. two-byte encoding. This is shown by using two 1s and a 0. The first 2-bits of the second byte are also reserved to denote the same thing. To avoid ambiguity in memory access, both the bytes have some reserved bits to denote the type of UTF-8 range. The rest of the bits i.e. 5-bits from the first byte and the 6-bits from the second byte can be used to map $2^{(5+6)} = 2^{11} = 2048$ numbers.\n\n    _e.g._ ```U+00B9``` (Unicode of $^1$ i.e. Superscript \"1\") is mapped as [1 1 0 0 0 0 1 0] [1 0 1 1 1 0 0 1]\n\n    \u003e This contains the mappings of unicode characters (128-2047)\n\n3. **Range 3 : 1110xxxx 10xxxxxx 10xxxxxx**\n\n    Out of the available 24-bits, first 4-bits of the first byte are reserved to show that this is of Type-3 UTF-8 i.e. three-byte encoding. This is shown by using three 1s and a 0. The first 2-bits of the second byte and third byte are also reserved to denote the same thing. To avoid ambiguity in memory access, all the bytes have some reserved bits to denote the type of UTF-8 range. The rest of the bits i.e. 5-bits from the first byte and the 6-bits from the second byte \u0026 third byte can be used to map $2^{(4+6+6)} = 2^{16} = 65536$ numbers.\n\n    _e.g._ ```U+2070``` (Unicode of $^0$ i.e. Superscript \"0\") is mapped as [1 1 1 0 0 0 1 0] [1 0 0 0 0 0 0 1] [1 0 1 1 0 0 0 0]\n\n    \u003e This contains the mappings of unicode characters (2048-65535)\n\n4. **Range 4 : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx**\n\n    Out of the available 32-bits, first 5-bits of the first byte are reserved to show that this is of Type-4 UTF-8 i.e. four-byte encoding. This is shown by using four 1s and a 0. The first 2-bits of the second byte, third byte and fourth byte are also reserved to denote the same thing. To avoid ambiguity in memory access, all the bytes have some reserved bits to denote the type of UTF-8 range. The rest of the bits i.e. 5-bits from the first byte and the 6-bits from the second byte, third byte \u0026 fourth byte can be used to map $2^{(3+6+6+6)} = 2^{21} = 2097152$ numbers.\n\n    \u003e This contains the mappings of unicode characters (65536-2097151),  but we have not yet reached the upper-bound yet. Range 4 is (65536-1114111) as of today. _(Discalimer : This data is prone to changes on a regular basis, check the Unicode website for more information)_\n\n```javascript\n/**\n * Converts Binary Unicode Codepoint into Binary UTF-8 string\n * Unicode is represented as U+XXXX where XXXX is the hexadecimal codepoint\n * Convert the codepoint to respective ary-byte depending on the lenght of the codepoint\n * @param {number} codepoint - Unicode Codepoint as a number\n * @returns {string} - UTF-8 string for the given unicode codepoint\n */\nfunction unicodeToUtf8Binary(codepoint) {\n    const str = codepoint.toString(2);      // Converts to base-2 binary string\n    const length = str.length;              // Length of the binary string\n\n    // Range 1 : 0xxxxxxx\n    if (length \u003c= 7) {\n        return `0${'0'.repeat(7 - length)}${str}`;\n    }\n\n    // Range 2 : 110xxxxx 10xxxxxx\n    else if (length \u003c= 11) {\n        return `110${'0'.repeat(11 - length)}${str.slice(0, -6)} 10${str.slice(-6)}`;\n    }\n\n    // Range 3 : 1110xxxx 10xxxxxx 10xxxxxx\n    else if (length \u003c= 16) {\n        return `1110${'0'.repeat(16 - length)}${str.slice(0, -12)} 10${str.slice(-12, -6)} 10${str.slice(-6)}`;\n    }\n\n    // Range 4 : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n    else if (length \u003c= 21) {\n        return `11110${'0'.repeat(21 - length)}${str.slice(0, -18)} 10${str.slice(-18, -12)} 10${str.slice(-12, -6)} 10${str.slice(-6)}`;\n    }\n\n    // Out Of Range\n    else {\n        throw new Error('Invalid Unicode Codepoint received : Out Of UTF-8 Range');\n    }\n}\n```\n\n## String To UTF-8 \u0026 UTF-8 To String\n\nUsing this logic one can simply build 2 conversion functions i.e.\n\n1. **UTF-8 To String**\n\n```javascript\n/**\n * Converts UTF-8 string to human-readable string\n * @param {string} str - UTF-8 string to be converted to human-readable string \n * @returns {string} - Human-readable string for the given UTF-8 string\n */\nfunction fromUTF8String(str) {\n    let utf8StringArray = str.split(' ');\n    let output = [];\n    let i = 0;\n    while (i \u003c utf8StringArray.length) {\n        // Range 1 : 0xxxxxxx\n        if (utf8StringArray[i].startsWith('0')) {\n            let unit = utf8StringArray.slice(i, i + 1).join('');\n            let codepoint = parseInt(unit.slice(1), 2);\n            output.push(String.fromCodePoint(codepoint));\n            i += 1;\n        }\n        // Range 2 : 110xxxxx 10xxxxxx\n        else if (utf8StringArray[i].startsWith('110')) {\n            let unit = utf8StringArray.slice(i, i + 2).join('');\n            let codepoint = parseInt(unit.slice(3, 8) + unit.slice(11), 2);\n            output.push(String.fromCodePoint(codepoint));\n            i += 2;\n        }\n        // Range 3 : 1110xxxx 10xxxxxx 10xxxxxx\n        else if (utf8StringArray[i].startsWith('1110')) {\n            let unit = utf8StringArray.slice(i, i + 3).join('');\n            let codepoint = parseInt(unit.slice(4, 8) + unit.slice(11, 17) + unit.slice(20), 2);\n            output.push(String.fromCodePoint(codepoint));\n            i += 3;\n        }\n        // Range 4 : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n        else if (utf8StringArray[i].startsWith('11110')) {\n            let unit = utf8StringArray.slice(i, i + 4).join('');\n            let codepoint = parseInt(unit.slice(5, 8) + unit.slice(11, 17) + unit.slice(20, 26) + unit.slice(29), 2);\n            output.push(String.fromCodePoint(codepoint));\n            i += 4;\n        }\n        else {\n            throw new Error('Invalid UTF-8 string');\n        }\n    }\n    return output.join('');\n};\n```\n\n2. **String To UTF-8**\n\n```javascript\n/**\n * Converts any human-readable string to UTF-8 string\n * @param {string} str - Human-readbale string to be converted to UTF-8 \n * @returns {string} - UTF-8 string for the given unicode string\n */\nfunction toUTF8String(str) {\n        let utf8StringArray = [];\n\n        for (let symbol of str) {\n            const codepoint = symbol.codePointAt(0);\n            utf8StringArray.push(unicodeToUtf8Binary(codepoint));\n        };\n\n        return utf8StringArray.join(' ');\n    };\n```\n\n## Explaining The SHA-256\n\n### Preprocessing\n\nPreprocessing needs to be done before implementing the SHA-256 algorithm. The preprocessing consists of 3 steps :\n\n1. Padding The Message (To ensure that the message length is a ```multiple of 512-bits```)\n2. Parsing The Message into Message blocks (Entire message is broken down into ```n blocks``` of size 512-bits each, and SHA-256 runs ```n iterations``` to compute the ```Hashed Value```)\n3. Setting The Initial Hash Value (Defined as ```\"The 32-bit fractional part of square root of first 8 prime numbers\"```)\n\n#### Padding the Message\n\n\u003e The Message :\n\u003e\n\u003e 512-bits message = UTF-8 Encoding + 1 {Mark the start of padding hereafter} + padding {0000...000} + length(UTF-8 Encoding) {64-bits reserved}\n\nTo create the padded message, we need to add 2 paddings :\n\n1. Zero padding after '1' and before start of length\n\n    ```javascript\n        let zeroPadding = '0'.repeat(512 - (message.length + 1 + 64) % 512);\n    ```\n\n2. Zero padding to make length = 64-bit\n\n    ```javascript\n        let lengthPadding = '0'.repeat(64 - message.length.toString(2).length);\n    ```\n\n#### Parsing the Message\n\nFor SHA-256, the padded message is parsed into N 512-bit blocks, M(1) ...  M(N). Since the ```512-bits``` of the input block may be expressed as ```sixteen 32-bit words```, the first 32-bits of message block i are denoted M(0)i , the next 32 bits are M(1)i , and so on up to M(15)i.\n\n\u003e Clever way is to use RegEx to parse the message\n\u003e\n\u003e 1. Divide into blocks of 512-bits first\n\u003e\n```javascript\n    let blocks = [];\n\n    for (let i = 0; i \u003c message.length; i += 512) {\n        blocks.push(message.slice(i, i + 512));\n    }\n```\n\u003e\n\u003e 2. Divide each blocks into sizteen 32-bits words\n\u003e\n```javascript\n    return blocks.map((x) =\u003e {\n        let chunks = [];\n\n        let j = 0;\n        for (let i = 0; i \u003c x.length; i += 32) {\n            chunks.push(x.slice(i, i + 32));\n        }\n    });\n```\n\n#### Setting up the Initial Hash Values\n\nThese Hash Values were obtained by taking the ```first 32-bits``` of the ```fractional parts``` of the ```square roots``` of the ```first 8 prime numbers```.\n\n```javascript\nconst H = [\n    0x6a09e667,\n    0xbb67ae85,\n    0x3c6ef372,\n    0xa54ff53a,\n    0x510e527f,\n    0x9b05688c,\n    0x1f83d9ab,\n    0x5be0cd19\n];\n```\n\n### Hash Computation\n\n#### Operations In SHA-256\n\nThere are some predefined operations in SHA-256 algorithm which are :\n\n1. Ch(x, y, z) - Choose : y if x is set else z\n\n    ```javascript\n    function Choose(x, y, z) {\n        return (x \u0026 y) ^ (~x \u0026 z);\n    };\n    ```\n\n2. Maj(a, b, c) - Majority : max(frequency(1) in (a,b,c), frequency(0) in (a,b,c))\n\n    ```javascript\n    function Majority(x, y, z) {\n        return (x \u0026 y) ^ (x \u0026 z) ^ (y \u0026 z);\n    };\n    ```\n\n3. Σ0(x) - Sigma0 : Rotates the number to the right by 2, 13, and 22 bits and then XORs the result\n\n    ```javascript\n\n    function Sigma0(x) {\n        return rightRotate(x, 2, 32) ^ rightRotate(x, 13, 32) ^ rightRotate(x, 22, 32);\n    };\n    ```\n\n4. Σ1(x) - Sigma1 : Rotates the number to the right by 6, 11, and 25 bits and then XORs the result\n\n    ```javascript\n\n    function Sigma1(x) {\n        return rightRotate(x, 6, 32) ^ rightRotate(x, 11, 32) ^ rightRotate(x, 25, 32);\n    };\n    ```\n\n5. σ0(x) - sigma0 : Rotates the number to the right by 7, 18, and shifts to the right by 3 bits and then XORs the result\n\n    ```javascript\n\n    function sigma0(x) {\n        return rightRotate(x, 7, 32) ^ rightRotate(x, 18, 32) ^ (x \u003e\u003e\u003e 3);\n    }\n    ```\n\n6. σ1(x) - sigma1 : Rotates the number to the right by 17, 19, and shifts to the right by 10 bits and then XORs the result\n\n    ```javascript6. σ1(x) - sigma1 : Rotates the number to the right by 17, 19, and shifts to the right by 10 bits and then XORs the result\n\n    function sigma1(x) {\n        return rightRotate(x, 17, 32) ^ rightRotate(x, 19, 32) ^ (x \u003e\u003e\u003e 10);\n    }\n    ```\n\n\u003e Each Message Block, M(1) ... M(N), is processed in order, following the steps:\n\u003e\n\u003e 1. Prepare Message Schedule\n\u003e 2. Initialize Working Variables\n\u003e 3. Find State of Variables at each Iteration and,\n\u003e 4. Compute New $i^{th}$ Hash Values\n\u003e\n\u003e After ```N iterations```, concatenate ```H0 ... H7``` i.e. ```H0 || H1 || H2 || H3 || H4 || H5 || H6 || H7``` to obtain the ```SHA-256 Hash```.\n\n#### Prepare the Message Schedule\n\nPerform the following operation:\n\n$messageSchedule[i] =\n\\begin{cases}\n    parsedMessage[i] \u0026 \\text{if } 0 \\leq i \\leq 15 \\\\\n    \\sigma_1(messageSchedule[i - 2]) + messageSchedule[i - 7] + \\sigma_0(messageSchedule[i - 15]) + messageSchedule[i - 16] \u0026 \\text{if } 16 \\leq i \\leq 63\n\\end{cases}$\n\n```javascript\nlet messageSchedule = [];\n\nfor (let t = 0; t \u003c 64; t++) {\n    if (t \u003c= 15) {\n        messageSchedule[t] = parsedMesssage[i][t];\n    } else {\n        messageSchedule[t] = (sigma1(messageSchedule[t - 2]) + messageSchedule[t - 7] + sigma0(messageSchedule[t - 15]) + messageSchedule[t - 16]) % Math.pow(2, 32);\n    }\n}\n```\n\n#### Initialize Working Variables\n\nInitialize 8 working variables ```a, b, c, d, e, f, g and h``` with $(i - 1)th$ hash value.\n\n```shell\na = H0(i)\nb = H1(i)\nc = H2(i)\nd = H3(i)\ne = H4(i)\nf = H5(i)\ng = H6(i)\nh = H7(i)\n```\n\n#### Find the State of Variables\n\nIterate in the ```Message Schedules``` and perform the following operations:\n\n```shell\nT1 = h + Σ1(a) + Ch(e, f, g) + K[i] + mwssageSchedule[i]\nT2 = Σ0(a) + Maj(a, b, c)\nh = g\ng = f\nf = e\ne = d + T1\nd = c\nc = b\nb = a\na = T1 + T2\n```\n\n```javascript\nfor (let t = 0; t \u003c 64; t++) {\n    T1 = (h + Sigma1(e) + Choose(e, f, g) + K[t] + messageSchedule[t]) % Math.pow(2, 32);\n    T2 = (Sigma0(a) + Majority(a, b, c)) % Math.pow(2, 32);\n    h = g;\n    g = f;\n    f = e;\n    e = (d + T1) % Math.pow(2, 32);\n    d = c;\n    c = b;\n    b = a;\n    a = (T1 + T2) % Math.pow(2, 32);\n}\n```\n\n#### Compute New $i^{th}$ Hash Values\n\nCompute the $i^{th}$ immediate hash value by performing the following operations:\n\n```shell\nH0(i) = a + H0(i - 1)\nH1(i) = b + H1(i - 1)\nH2(i) = c + H2(i - 1)\nH3(i) = d + H3(i - 1)\nH4(i) = e + H4(i - 1)\nH5(i) = f + H5(i - 1)\nH6(i) = g + H6(i - 1)\nH7(i) = h + H7(i - 1)\n```\n\n#### Final Result\n\nAfter completing ```N iterations```, the resulting ```256-bits Message Digest``` of the message is :\n\n$H0(N) | H1(N) | H2(N) | H3(N) | H4(N) | H5(N) | H6(N) | H7(N)$\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodegasms%2Fsha256","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodegasms%2Fsha256","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodegasms%2Fsha256/lists"}