| 124 | return data + padding + big_endian_integer |
| 125 | |
| 126 | def final_hash(self) -> None: |
| 127 | # Convert into blocks of 64 bytes |
| 128 | self.blocks = [ |
| 129 | self.preprocessed_data[x : x + 64] |
| 130 | for x in range(0, len(self.preprocessed_data), 64) |
| 131 | ] |
| 132 | |
| 133 | for block in self.blocks: |
| 134 | # Convert the given block into a list of 4 byte integers |
| 135 | words = list(struct.unpack(">16L", block)) |
| 136 | # add 48 0-ed integers |
| 137 | words += [0] * 48 |
| 138 | |
| 139 | a, b, c, d, e, f, g, h = self.hashes |
| 140 | |
| 141 | for index in range(64): |
| 142 | if index > 15: |
| 143 | # modify the zero-ed indexes at the end of the array |
| 144 | s0 = ( |
| 145 | self.ror(words[index - 15], 7) |
| 146 | ^ self.ror(words[index - 15], 18) |
| 147 | ^ (words[index - 15] >> 3) |
| 148 | ) |
| 149 | s1 = ( |
| 150 | self.ror(words[index - 2], 17) |
| 151 | ^ self.ror(words[index - 2], 19) |
| 152 | ^ (words[index - 2] >> 10) |
| 153 | ) |
| 154 | |
| 155 | words[index] = ( |
| 156 | words[index - 16] + s0 + words[index - 7] + s1 |
| 157 | ) % 0x100000000 |
| 158 | |
| 159 | # Compression |
| 160 | s1 = self.ror(e, 6) ^ self.ror(e, 11) ^ self.ror(e, 25) |
| 161 | ch = (e & f) ^ ((~e & (0xFFFFFFFF)) & g) |
| 162 | temp1 = ( |
| 163 | h + s1 + ch + self.round_constants[index] + words[index] |
| 164 | ) % 0x100000000 |
| 165 | s0 = self.ror(a, 2) ^ self.ror(a, 13) ^ self.ror(a, 22) |
| 166 | maj = (a & b) ^ (a & c) ^ (b & c) |
| 167 | temp2 = (s0 + maj) % 0x100000000 |
| 168 | |
| 169 | h, g, f, e, d, c, b, a = ( |
| 170 | g, |
| 171 | f, |
| 172 | e, |
| 173 | ((d + temp1) % 0x100000000), |
| 174 | c, |
| 175 | b, |
| 176 | a, |
| 177 | ((temp1 + temp2) % 0x100000000), |
| 178 | ) |
| 179 | |
| 180 | mutated_hash_values = [a, b, c, d, e, f, g, h] |
| 181 | |
| 182 | # Modify final values |
| 183 | self.hashes = [ |