{"id":19731138,"url":"https://github.com/dyspersja/java-sha256","last_synced_at":"2025-10-24T12:27:48.092Z","repository":{"id":216680902,"uuid":"740957525","full_name":"Dyspersja/Java-Sha256","owner":"Dyspersja","description":"Implementation of sha256 algorithm in java.","archived":false,"fork":false,"pushed_at":"2024-04-07T13:50:12.000Z","size":51,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-10T17:53:29.608Z","etag":null,"topics":["hashing-algorithm","java","sha256"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Dyspersja.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-01-09T12:21:38.000Z","updated_at":"2024-04-03T20:30:37.000Z","dependencies_parsed_at":"2025-01-10T17:45:20.422Z","dependency_job_id":"74d7a52c-662c-4344-aa37-94a6989ac33f","html_url":"https://github.com/Dyspersja/Java-Sha256","commit_stats":null,"previous_names":["dyspersja/java-sha256"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dyspersja%2FJava-Sha256","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dyspersja%2FJava-Sha256/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dyspersja%2FJava-Sha256/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dyspersja%2FJava-Sha256/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dyspersja","download_url":"https://codeload.github.com/Dyspersja/Java-Sha256/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241056179,"owners_count":19901727,"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","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":["hashing-algorithm","java","sha256"],"created_at":"2024-11-12T00:19:22.894Z","updated_at":"2025-10-24T12:27:43.058Z","avatar_url":"https://github.com/Dyspersja.png","language":"Java","readme":"# Java-Sha256\nThis repository contains a Java implementation of the SHA-256 algorithm. The priority of writing this implementation was clarity and readability to easily understand the algorithm.\n\n### If you're looking for how to implement the SHA 256 algorithm in your Java project, just use:\n\n```java\n  MessageDigest messageDigest = MessageDigest.getInstance(\"SHA-256\");\n  byte[] hash = messageDigest.digest(source);\n```\n\nCode in this project is divided into two files **Main.java** with main function and two uses of the implemented algorithm for generating a hash from string input or from a file. \nSecond file **Sha256MessageDigest.java** contains the whole implementation of the SHA-256 algorithm with marked each step that is crucial for calculating the hash value. \n\n# SHA-256 Algorithm\n\nBelow, you'll find an explanation of the SHA-256 algorithm, breaking down each step needed to implement it. Every step described below is marked in **Sha256MessageDigest** class for easier tracking and understanding. The algorithm was described by hashing the beginning of the book 'The Tempest', because why not. The text: \"Scene 1 A tempestuous noise of thunder and lightning heard.\"\n\n## Step 1: Convert the input data into its binary representation. \n\nThe SHA256 algorithm operates on the binary form of input data, so first we need to prepare the data. Files are already stored as bytes, but for text data, we need to perform a conversion. By default, UTF-8 encoding is commonly used for this purpose, but there's nothing preventing us from using other character encoding systems such as UTF-16LE, UTF-16BE, or any other encoding system. We will use UTF-8.\n\nCharacter | Binary Representation\n--------- | ---------------------\nS         | 01010011  \nc         | 01100011\ne         | 01100101\nn         | 01101110\ne         | 01100101\n(space)   | 00100000\n1         | 00110001\n\nand so on...\n\nNext lets concatenate the binary representation of each letter into single block of data:\n\n*01010011 01100011 01100101 01101110 01100101 00100000 00110001 00100000  \n01000001 00100000 01110100 01100101 01101101 01110000 01100101 01110011  \n01110100 01110101 01101111 01110101 01110011 00100000 01101110 01101111  \n01101001 01110011 01100101 00100000 01101111 01100110 00100000 01110100  \n01101000 01110101 01101110 01100100 01100101 01110010 00100000 01100001  \n01101110 01100100 00100000 01101100 01101001 01100111 01101000 01110100  \n01101110 01101001 01101110 01100111 00100000 01101000 01100101 01100001  \n01110010 01100100 00101110*\n\nAt the end of this step we obtained a set of data with a length of 472 bits that is ready for the next step.\n\n## Step 2: Append a single '1' to the end of the input data.\n\nThe SHA-256 hash function processes input data in 512-bit blocks, each divided into 16 words of 32 bits each. Therefore, with the binary form of the data for which we want to create a hash, we now need to process it into a format suitable for the algorithm.\n\nWe begin this process by appending a single '1' to the end of the source data:\n\n01010011 01100011 01100101 01101110 01100101 00100000 00110001 00100000  \n01000001 00100000 01110100 01100101 01101101 01110000 01100101 01110011  \n01110100 01110101 01101111 01110101 01110011 00100000 01101110 01101111  \n01101001 01110011 01100101 00100000 01101111 01100110 00100000 01110100  \n01101000 01110101 01101110 01100100 01100101 01110010 00100000 01100001  \n01101110 01100100 00100000 01101100 01101001 01100111 01101000 01110100  \n01101110 01101001 01101110 01100111 00100000 01101000 01100101 01100001  \n01110010 01100100 00101110 *1*\n\n## Step 3: Append data with padding consisting of multiple '0's.\n\nNext, we need to prepare our data so that its length is a multiple of 512 in bits. However, it's important to note that the last 64 bits are reserved for the total length of the source message, encoded as an 64-bit integer. So, after adding padding with zeros, our message should have a length x ≡ 448 mod 512. (where 448 comes from the length of the last 512-bit block minus 64 bits of source message length). \n\nIn our case, we need to add 487 zeros:\n\n01010011 01100011 01100101 01101110 01100101 00100000 00110001 00100000  \n01000001 00100000 01110100 01100101 01101101 01110000 01100101 01110011  \n01110100 01110101 01101111 01110101 01110011 00100000 01101110 01101111  \n01101001 01110011 01100101 00100000 01101111 01100110 00100000 01110100  \n01101000 01110101 01101110 01100100 01100101 01110010 00100000 01100001  \n01101110 01100100 00100000 01101100 01101001 01100111 01101000 01110100  \n01101110 01101001 01101110 01100111 00100000 01101000 01100101 01100001  \n01110010 01100100 00101110 1*0000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000*\n\n## Step 4: Append the length of the original message to the end.\n\nIn this step, as mentioned earlier, we need to append the total length of the original message in bits as a 64-bit integer. Our original message had 472 bits, in binary this number is **111011000**.\n\nBelow is the fully prepared message:\n\n01010011 01100011 01100101 01101110 01100101 00100000 00110001 00100000  \n01000001 00100000 01110100 01100101 01101101 01110000 01100101 01110011  \n01110100 01110101 01101111 01110101 01110011 00100000 01101110 01101111  \n01101001 01110011 01100101 00100000 01101111 01100110 00100000 01110100  \n01101000 01110101 01101110 01100100 01100101 01110010 00100000 01100001  \n01101110 01100100 00100000 01101100 01101001 01100111 01101000 01110100  \n01101110 01101001 01101110 01100111 00100000 01101000 01100101 01100001  \n01110010 01100100 00101110 10000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n*00000000 00000000 00000000 00000000 00000000 00000000 00000001 11011000*\n\n## Step 5: Break the prepared message into 512 bit blocks.\n\nNow, at this step, we need to divide our message into 512-bit blocks, each of which will be then processed individually using a set of bitwise operations, to finally calculate a 256-bit hash using the obtained values.\n\nAt the end of the previous steps, we should get a message that's length is a multiple of 512 bits. If it's not, some error must have been made, most likely while adding padding to the original message on **Step 3**.\n\nOur example prepared message had a length of 1024 bits, so after dividing it, we received two 512 bit blocks shown below:\n\nBlock 1:\n\n01010011 01100011 01100101 01101110 01100101 00100000 00110001 00100000  \n01000001 00100000 01110100 01100101 01101101 01110000 01100101 01110011  \n01110100 01110101 01101111 01110101 01110011 00100000 01101110 01101111  \n01101001 01110011 01100101 00100000 01101111 01100110 00100000 01110100  \n01101000 01110101 01101110 01100100 01100101 01110010 00100000 01100001  \n01101110 01100100 00100000 01101100 01101001 01100111 01101000 01110100  \n01101110 01101001 01101110 01100111 00100000 01101000 01100101 01100001  \n01110010 01100100 00101110 10000000 00000000 00000000 00000000 00000000\n\nBlock 2:\n\n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  \n00000000 00000000 00000000 00000000 00000000 00000000 00000001 11011000\n\n## Step 6: Prepare message schedule.\n\nNow we move on to the main part of the algorithm. In the first part, for each 512-bit block received in the previous steps, we need to prepare a message schedule consisting of 64 words, each 32 bits long.\n\nThese message schedules will be used for decomposing each of the blocks. This step is done to maximize the spreading out of input changes throughout the output and to make the relationship between input and output complex and difficult to predict. \n\nIn the subsequent steps, I will provide examples for both blocks. Especially in the case of the second block, which consists mostly of zeros with single ones at the end, the resulting message schedule after computation will be completely unpredictable.\n\nNow, the empty message schedule for Block 1 looks as follows:\n\nW0: 00000000 00000000 00000000 00000000  \nW1: 00000000 00000000 00000000 00000000  \nW2: 00000000 00000000 00000000 00000000  \nW3: 00000000 00000000 00000000 00000000  \n...  \nW63: 00000000 00000000 00000000 00000000\n\n## Step 7: Divide the block and assign it into the first 16 words of the message schedule.\n\nIn this step, we need to divide our 512-bit block into 16 32-bit sub-blocks and assign them sequentially to the first 16 words of the message scheduler.\n\nFor the Block 1:\n\nW0: 01010011 01100011 01100101 01101110  \nW1: 01100101 00100000 00110001 00100000  \nW2: 01000001 00100000 01110100 01100101  \nW3: 01101101 01110000 01100101 01110011  \nW4: 01110100 01110101 01101111 01110101  \nW5: 01110011 00100000 01101110 01101111  \nW6: 01101001 01110011 01100101 00100000  \nW7: 01101111 01100110 00100000 01110100  \nW8: 01101000 01110101 01101110 01100100  \nW9: 01100101 01110010 00100000 01100001  \nW10: 01101110 01100100 00100000 01101100  \nW11: 01101001 01100111 01101000 01110100  \nW12: 01101110 01101001 01101110 01100111  \nW13: 00100000 01101000 01100101 01100001  \nW14: 01110010 01100100 00101110 10000000  \nW15: 00000000 00000000 00000000 00000000  \nW16: 00000000 00000000 00000000 00000000  \nW17: 00000000 00000000 00000000 00000000  \nW18: 00000000 00000000 00000000 00000000  \n...  \nW63: 00000000 00000000 00000000 00000000\n\nWords 0 through 15 have been assigned as initial values from the 512-bit block. Subsequent words from 16 to 63 will be calculated using simple bitwise operations on the previous words, such as rotation, shifting, or XOR operations.\n\n## Step 8: Calculate the remaining 16 to 63 words of the message scheduler.\n\nStarting from word 16, each subsequent word must be computed using the previous ones and the following formula:\n\n```\nWj = Wj-16 + σ0(Wj-15) + Wj-7 + σ1(Wj-2)\n```\n\nWhere, from the beginning, Wj represents the word being currently calculated, 'j' is its index position in the message scheduler, Wj-n represents the word at index j-n, and σ0 and σ1 are functions operating on a single word.\n\n**A crucial point to mention is that the resulting word Wj must be of size 32 bits to be assigned back to the message scheduler. So, the operation '+' signifies mod 2\u003csup\u003e32\u003c/sup\u003e addition.**\n\nBelow is the description of functions σ0 and σ1. Both functions utilize two bitwise rotation operations, bitwise shifting, and XOR-ing the results of these operations, but each with a slightly different number of bits.\n\nfunction **σ0**:\n\n```\nσ0(X) = RotR(X, 7) ⊕ RotR(X, 18) ⊕ (X \u003e\u003e 3)\n```\n\n- **RotR(X, 7)** Right rotation (circular shift) of the input word by 7 bits.\n- **RotR(X, 18)** Another right rotation of the input word by 18 bits.\n- **(X \u003e\u003e 3)** Right shift of the input word by 3 bits\n- **⊕** Finally, it performs a bitwise XOR operation between the results of the previous operations.\n\nfunction **σ1**: (It is very similar, differing only in the number of bits in the operations.)\n\n```\nσ1(X) = RotR(X, 17) ⊕ RotR(X, 19) ⊕ (X \u003e\u003e 10)\n```\n---------------------\n### Knowing the formulas, let's calculate the first, i.e., the 16th word in the message schedule. \n\nAfter replacing the index 'j' with the number 16 in the formula, we get:\n\n```\nW16 = W0 + σ0(W1) + W9 + σ1(W14)\n```\n\nWe will need the following words for calculations:\n\nW0: 01010011 01100011 01100101 01101110  \nW1: 01100101 00100000 00110001 00100000  \nW9: 01100101 01110010 00100000 01100001  \nW14: 01110010 01100100 00101110 10000000   \n\nLet's calculate the σ0 and σ1:\n\ncomputations for σ0(W1):\n```\n01100101 00100000 00110001 00100000 - W1  \n\n01000000 11001010 01000000 01100010 - right rotate 7  \n00001100 01001000 00011001 01001000 - right rotate 18  \n00001100 10100100 00000110 00100100 - right shift 3  \n\n01000000 00100110 01011111 00001110 - σ0(W1) // after XOR-ing above results\n```\ncomputations for σ1(W14):\n```\n01110010 01100100 00101110 10000000 - W14  \n\n00010111 01000000 00111001 00110010 - right rotate 17  \n10000101 11010000 00001110 01001100 - right rotate 19  \n00000000 00011100 10011001 00001011 - right shift 10  \n\n10010010 10001100 10101110 01110101 - σ1(W14) // after XOR-ing above results\n```\nAfter calculating σ0 and σ1, we can compute the word W16:\n```\n01010011 01100011 01100101 01101110 - W0  \n01000000 00100110 01011111 00001110 - σ0(W1)  \n01100101 01110010 00100000 01100001 - W9  \n10010010 10001100 10101110 01110101 - σ1(W14)\n\n10001011 10001000 10010011 01010010 - W16 // after mod 2^32 addition of above results\n```\n\nAt the end, we obtained the 16th word, and we can now put it into the message schedule. Now we need to repeat this step for the subsequent words up to 63rd until we have the entire message schedule prepared.\n\nThe subsequent words, as shown earlier, are calculated using previously calculated words. Therefore, there isn't much opportunity for parallelization, and the entire message schedule must be computed sequentially. But, while the computation of the message schedule for a single block may be sequential, multiple blocks can be processed in parallel by different threads or processes. This can significantly speed up the hashing process, especially for large messages where multiple blocks are involved.\n\nSince I think it doesn't make sense to list 2048 ones and zeros here for the first block and another 2048 for the second, it's worth showing how the subsequent words in the message schedule look for a block that was filled with mostly zeros with a few ones at the end.\n\nBelow are the last 10 words for the block 2.\n\nW54: 10001100 11111010 10000001 01101100  \nW55: 11111111 10101101 11000111 10100010  \nW56: 01011110 10000100 00000111 01011000  \nW57: 01111010 10100000 11100100 11010011  \nW58: 11111001 11111001 01110101 10000001  \nW59: 11000111 00000000 01111010 00001000  \nW60: 10000110 11011111 10101001 00110000  \nW61: 10001100 10111000 00000001 01000100  \nW62: 10010100 10101000 11011101 00101011  \nW63: 10111001 00111001 01100101 00001110  \n\nAs you can see, they are filled with values that are impossible to predict, and changing even one more zero to a one in that block would completely alter above values.\n\n## Step 9: Prepare the initial hash value for the new set of words.\n\nIn this step, we begin the actual computation of the hash value. \n\nAt the beginning of computing the hash value for a new set of words, we assign the hash values to 8 32-bit registers a, b, c, d, e, f, g, h, calculated using the previous set or initial values if it's the first set being computed.\n\n### Calculating the initial values for the first block.\n\nThe initial values are obtained by taking the first 32 bits of the fractional part of the square roots of the first 8 prime numbers 2, 3, 5, 7, 11, 13, 17 and 19.\n\nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(1)\u003c/sup\u003e: √2 = 1.414213562373095... = 1.01101010000010011110011001100111... = 01101010 00001001 11100110 01100111  \n\nFirst, we take the nth prime number: **2**  \nWe take the square root of that number: **√2**  \nWe calculate the decimal representation of that square root: **1.414213562373095...**  \nWe convert the decimal representation to binary form: **1.01101010000010011110011001100111...**  \nWe take the first 32 bits of the fractional part of the obtained square root in binary form: **01101010 00001001 11100110 01100111**\n\nThe obtained number is our initial value for the first register. Remaining values are calculated below.\n\nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(2)\u003c/sup\u003e: √3 = 1.732050807568877... = 1.10111011011001111010111010000101... =\u003e 10111011 01100111 10101110 10000101  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(3)\u003c/sup\u003e: √5 = 2.23606797749979... = 10.00111100011011101111001101110010... =\u003e 00111100 01101110 11110011 01110010  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(4)\u003c/sup\u003e: √7 = 2.645751311064591... = 10.10100101010011111111010100111010... =\u003e 10100101 01001111 11110101 00111010  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(5)\u003c/sup\u003e: √11 = 3.3166247903554... = 11.01010001000011100101001001111111... =\u003e 01010001 00001110 01010010 01111111  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(6)\u003c/sup\u003e: √13 = 3.605551275463989... = 11.10011011000001010110100010001100... =\u003e 10011011 00000101 01101000 10001100  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(7)\u003c/sup\u003e: √17 = 4.123105625617661... = 100.00011111100000111101100110101011... =\u003e 00011111 10000011 11011001 10101011  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(8)\u003c/sup\u003e: √19 = 4.358898943540674... = 100.01011011111000001100110100011001... =\u003e 01011011 11100000 11001101 00011001  \n\nIn implementations of the algorithm, it doesn't make sense to calculate these values every time a new hash value is computed. They are usually hard-coded into the program's code, often in hexadecimal form:\n\nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(1)\u003c/sup\u003e: 6A09 E667  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(2)\u003c/sup\u003e: BB67 AE85  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(3)\u003c/sup\u003e: 3C6E F372  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(4)\u003c/sup\u003e: A54F F53A  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(5)\u003c/sup\u003e: 510E 527F  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(6)\u003c/sup\u003e: 9B05 688C  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(7)\u003c/sup\u003e: 1F83 D9AB  \nH\u003csub\u003e0\u003c/sub\u003e\u003csup\u003e(8)\u003c/sup\u003e: 5BE0 CD19  \n\nThese values are only being used during the calculation of the hash value for the first block as initial values. For the next block, the starting values will be the values calculated at the end of the previous block, as will be shown in the following steps.\n\nAt the end of this step, we assign values to the registers calculated in the previous step 'i - 1', or for the first step initial values calculated earlier.\n\na = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(1)\u003c/sup\u003e  \nb = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(2)\u003c/sup\u003e  \nc = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(3)\u003c/sup\u003e  \nd = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(4)\u003c/sup\u003e  \ne = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(5)\u003c/sup\u003e  \nf = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(6)\u003c/sup\u003e  \ng = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(7)\u003c/sup\u003e  \nh = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(8)\u003c/sup\u003e  \n\n## Step 10: Calculate the intermediate hash value for each block.\n\nWith registers from a to h prepared, we can proceed to the main computation of the hash value in the SHA-256 algorithm.\n\nIn this step, for each word 'Wj' in the message scheduler a total of 64 times, we perform the following operations.\n\nh = g  \ng = f  \nf = e  \ne = d + Temp1  \nd = c  \nc = b  \nb = a  \na = Temp1 + Temp2  \n\nwhere:\n\nTemp1 = h + Σ1(e) + Choice(e, f, g) + Kj + Wj  \nTemp2 = Σ0(a) + Majority(a, b, c)  \n\nNow we need to explain what Σ0 and Σ1 represent, as well as K and the Choice and Majority functions.\n\n----------------------------\nLet's start with K. These are 64 32-bit words obtained through a very similar process to the initial values H\u003csub\u003e0\u003c/sub\u003e from the previous step. But this time, we use cube roots instead of square roots.\n\nThis time the constant K is calculated as the first 32 bits of the fractional part of the **cube roots** of the first 64 prime numbers. \n\nK\u003csup\u003e(1)\u003c/sup\u003e: \u003csup\u003e3\u003c/sup\u003e√2 = 1.25992104989... = 1.01000010100010100010111110011000... =\u003e 01000010 10001010 00101111 10011000 = **428A 2F98**  \n\n-----------------------------------------------\nNow, functions Σ0 and Σ1. They are quite similar to σ0 and σ1, but they do not involve right shifts, only right rotations and XOR operations on the results of these rotations.\n\ncomputations for Σ0(a):\n```\n01101010 00001001 11100110 01100111 - a\n\n11011010 10000010 01111001 10011001 - right rotate 2  \n00110011 00111011 01010000 01001111 - right rotate 13  \n00100111 10011001 10011101 10101000 - right rotate 22\n\n11001110 00100000 10110100 01111110 - Σ0(a) // after XOR-ing above results\n```\n\ncomputations for Σ1(e):\n```\n01010001 00001110 01010010 01111111 - e\n\n11111101 01000100 00111001 01001001 - right rotate 6\n01001111 11101010 00100001 11001010 - right rotate 11\n10000111 00101001 00111111 10101000 - right rotate 25\n\n00110101 10000111 00100111 00101011 - Σ1(e) // after XOR-ing above results\n```\n\n-----------------------------------\nNow let's talk about the function Choice.\n\nIt operates on three 32-bit words, always registers e, f and g. The choice function selects bits from f or g based on the value of the corresponding bit in e.\n\nIn other words: For each bit position, it chooses the bit from register e. If the bit is 1, It sets the result bit to corresponding bit from register f. If the bit from e was 0 it takes the bit from register g.\n\nMathematically, it can be expressed as:\n```\nChoice(e, f, g) = (e ∧ f) ⊕ ((¬e) ∧ g)\n```\nwhere:\n\n- ∧ denotes the bitwise AND operation.\n- ¬ denotes the bitwise NOT operation.\n- ⊕ denotes the bitwise XOR operation.\n\nLet's calculate the value of this function for our example.\n```\n01010001 00001110 01010010 01111111 - e\n10011011 00000101 01101000 10001100 - f\n00011111 10000011 11011001 10101011 - g\n\n00011111 10000101 11001001 10001100 - Choice(e, f, g)\n```\n\n-------------------------------------\nNow the last function to explain, Majority.\n\nIt also operates on three 32-bit words, this time always registers a, b and c.\n\nFor each bit position, it computes the majority of the bits at that position among the three input words. If there are more '0' than '1' bits, the result bit is set to '0' otherwise, it is set to '1'.\n\nMathematically, the majority function can be expressed as:\n```\nMajority(a, b, c) = (a ∧ b) ⊕ (a ∧ c) ⊕ (b ∧ c)\n```\n\ncomputations for Majority(a, b, c)\n```\n01101010 00001001 11100110 01100111 - a\n10111011 01100111 10101110 10000101 - b\n00111100 01101110 11110011 01110010 - c\n\n00111010 01101111 11100110 01100111 - Majority(a, b, c)\n```\n\nNow that we have explained all the functions, let's calculate updated register values for the first word Wj in the message scheduler for the first block.\n\nJust to remind you, the register values are: (these are the values calculated in step 9)\n\na: 01101010 00001001 11100110 01100111  \nb: 10111011 01100111 10101110 10000101  \nc: 00111100 01101110 11110011 01110010  \nd: 10100101 01001111 11110101 00111010  \ne: 01010001 00001110 01010010 01111111  \nf: 10011011 00000101 01101000 10001100  \ng: 00011111 10000011 11011001 10101011  \nh: 01011011 11100000 11001101 00011001  \n\nFirst, we need to calculate the values of Temp1 and Temp2.\n\ncomputations for Temp1\n```\n01011011 11100000 11001101 00011001 - h\n00110101 10000111 00100111 00101011 - Σ1(e)\n00011111 10000101 11001001 10001100 - Choice(e, f, g)\n01000010 10001010 00101111 10011000 - Kj\n01010011 01100011 01100101 01101110 - Wj\n\n01000110 11011011 01010010 11010110 - Temp1 // after mod 2^32 addition of above values\n```\n\ncomputations for Temp2\n```\n11001110 00100000 10110100 01111110 - Σ0(a)\n00111010 01101111 11100110 01100111 - Majority(a, b, c)\n\n00001000 10010000 10011010 11100101 - Temp2 // after mod 2^32 addition of above values\n```\n\nNow we can assign new values to the registers.\n\na = 01001111 01101011 11101101 10111011 = Temp1 + Temp2  \nb = 01101010 00001001 11100110 01100111 = a\u003csup\u003e j-1\u003c/sup\u003e  \nc = 10111011 01100111 10101110 10000101 = b\u003csup\u003e j-1\u003c/sup\u003e  \nd = 00111100 01101110 11110011 01110010 = c\u003csup\u003e j-1\u003c/sup\u003e  \ne = 11101100 00101011 01001000 00010000 = d\u003csup\u003e j-1\u003c/sup\u003e + Temp1  \nf = 01010001 00001110 01010010 01111111 = e\u003csup\u003e j-1\u003c/sup\u003e  \ng = 10011011 00000101 01101000 10001100 = f\u003csup\u003e j-1\u003c/sup\u003e  \nh = 00011111 10000011 11011001 10101011 = g\u003csup\u003e j-1\u003c/sup\u003e  \n\nNow that we have updated register values for the first word, we need to repeat the above steps for the remaining words from 2 to 64.\n\n## Step 11: Calculate the new hash values for the computed block.\n\nAfter completing the calculations from the previous step for each word up to 64th, we can proceed to calculate the intermediate hash value, which will serve as the initial value for the next block, or if it was the last block, as the final result of the algorithm.\n\nTo do this, simply add the register values from a to h to the initial values with which we started the calculations for this block.\n\nH\u003csub\u003ei\u003c/sub\u003e\u003csup\u003e(1)\u003c/sup\u003e = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(1)\u003c/sup\u003e + a  \nH\u003csub\u003ei\u003c/sub\u003e\u003csup\u003e(2)\u003c/sup\u003e = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(2)\u003c/sup\u003e + b  \nH\u003csub\u003ei\u003c/sub\u003e\u003csup\u003e(3)\u003c/sup\u003e = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(3)\u003c/sup\u003e + c  \nH\u003csub\u003ei\u003c/sub\u003e\u003csup\u003e(4)\u003c/sup\u003e = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(4)\u003c/sup\u003e + d  \nH\u003csub\u003ei\u003c/sub\u003e\u003csup\u003e(5)\u003c/sup\u003e = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(5)\u003c/sup\u003e + e  \nH\u003csub\u003ei\u003c/sub\u003e\u003csup\u003e(6)\u003c/sup\u003e = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(6)\u003c/sup\u003e + f  \nH\u003csub\u003ei\u003c/sub\u003e\u003csup\u003e(7)\u003c/sup\u003e = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(7)\u003c/sup\u003e + g  \nH\u003csub\u003ei\u003c/sub\u003e\u003csup\u003e(8)\u003c/sup\u003e = H\u003csub\u003ei-1\u003c/sub\u003e\u003csup\u003e(8)\u003c/sup\u003e + h  \n\nBelow are the calculated values for the first block 'i = 1', and these values will be used as the initial values for calculating next intermediate hash value from the next block.\n\nH\u003csub\u003e1\u003c/sub\u003e\u003csup\u003e(1)\u003c/sup\u003e = 01101010 00001001 11100110 01100111 + 10110010 00111000 00000000 01101001 = 00011100 01000001 11100110 11010000  \nH\u003csub\u003e1\u003c/sub\u003e\u003csup\u003e(2)\u003c/sup\u003e = 10111011 01100111 10101110 10000101 + 11011101 00010001 11100100 01101001 = 10011000 01111001 10010010 11101110  \nH\u003csub\u003e1\u003c/sub\u003e\u003csup\u003e(3)\u003c/sup\u003e = 00111100 01101110 11110011 01110010 + 00110100 01101010 11011011 10100111 = 01110000 11011001 11001111 00011001  \nH\u003csub\u003e1\u003c/sub\u003e\u003csup\u003e(4)\u003c/sup\u003e = 10100101 01001111 11110101 00111010 + 01100100 01000110 11010111 11110000 = 00001001 10010110 11001101 00101010  \nH\u003csub\u003e1\u003c/sub\u003e\u003csup\u003e(5)\u003c/sup\u003e = 01010001 00001110 01010010 01111111 + 01110111 00101010 10100000 01110100 = 11001000 00111000 11110010 11110011  \nH\u003csub\u003e1\u003c/sub\u003e\u003csup\u003e(6)\u003c/sup\u003e = 10011011 00000101 01101000 10001100 + 01010010 01111101 10000110 11010011 = 11101101 10000010 11101111 01011111  \nH\u003csub\u003e1\u003c/sub\u003e\u003csup\u003e(7)\u003c/sup\u003e = 00011111 10000011 11011001 10101011 + 01011101 00011010 10101100 11011110 = 01111100 10011110 10000110 10001001  \nH\u003csub\u003e1\u003c/sub\u003e\u003csup\u003e(8)\u003c/sup\u003e = 01011011 11100000 11001101 00011001 + 01101000 10101000 00110101 10111111 = 11000100 10001001 00000010 11011000  \n\n## Step 12: Calculate the final hash value.\n\nIf all sets have been calculated for all blocks, the final hash value is the concatenation of eight 32-bit blocks from the H\u003csub\u003en\u003c/sub\u003e array (n - number of blocks).\n\nThe values calculated at the end of the second (last) block:\n\nH\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(1)\u003c/sup\u003e = 00010010 10110111 11110110 00100011 = 12B7 F623  \nH\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(2)\u003c/sup\u003e = 10111011 11011011 10101100 01001000 = BBDB AC48  \nH\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(3)\u003c/sup\u003e = 11000000 11101101 11111111 11010101 = C0ED FFD5  \nH\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(4)\u003c/sup\u003e = 00011000 10101110 01000011 00101000 = 18AE 4328  \nH\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(5)\u003c/sup\u003e = 00111110 11010111 11010001 10100110 = 3ED7 D1A6  \nH\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(6)\u003c/sup\u003e = 11100001 11011111 00101000 10000101 = E1DF 2885  \nH\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(7)\u003c/sup\u003e = 01111000 00011001 01001101 11001100 = 7819 4DCC  \nH\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(8)\u003c/sup\u003e = 01111000 00000101 01111000 10001110 = 7805 788E  \n\nNow all we need to do is concatenate these values into a single sequence.\n\nSHA-256 hash: H\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(1)\u003c/sup\u003e || H\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(2)\u003c/sup\u003e || H\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(3)\u003c/sup\u003e || H\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(4)\u003c/sup\u003e || H\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(5)\u003c/sup\u003e || H\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(6)\u003c/sup\u003e || H\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(7)\u003c/sup\u003e || H\u003csub\u003en\u003c/sub\u003e\u003csup\u003e(8)\u003c/sup\u003e\n\nSHA-256 hash: 12B7 F623 BBDB AC48 C0ED FFD5 18AE 4328 3ED7 D1A6 E1DF 2885 7819 4DCC 7805 788E\n\n# Special Thanks\n\nThe materials thanks to which I learned how the algorithm works:  \nhttps://helix.stormhub.org/papers/SHA-256.pdf  \nhttps://eips.ethereum.org/assets/eip-2680/sha256-384-512.pdf  \n\nThe algorithm demonstration I used to compute individual values in the above README.md:  \nhttps://sha256algorithm.com/\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdyspersja%2Fjava-sha256","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdyspersja%2Fjava-sha256","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdyspersja%2Fjava-sha256/lists"}