def sha256(message, H=H, K=K): bitstring = pad_message(message) chunks = [] # bitstring chunks of 512 bits for i in range(0, len(bitstring), 512): chunks.append(bitstring[i:i + 512]) # Initialize hash values as BitString objects # They are originally 32 bit hex values h0, h1, h2, h3, h4, h5, h6, h7 = list( map(lambda x: BitString.from_hex(x, 32), H)) # Initialize round constants as BitString objects K = [BitString.from_hex(k, 32) for k in K] for chunk in chunks: # chunk is bitstring of size 512 # Run 64 rounds in compression function # We need W(i) and K(i) for i=1,..,64 # Break the 16 first rounds into 32-bit blocks from the chunk M = parse_block(chunk) # The 48 next rounds will be computed by # W(i) = Wⁱ⁻¹⁶ + σ⁰ + Wⁱ⁻⁷ + σ¹ where, # σ⁰ = (Wⁱ⁻¹⁵ ROTR⁷(x)) XOR (Wⁱ⁻¹⁵ ROTR¹⁸(x)) XOR (Wⁱ⁻¹⁵ SHR³(x)) # σ¹ = (Wⁱ⁻² ROTR¹⁷(x)) XOR (Wⁱ⁻² ROTR¹⁹(x)) XOR (Wⁱ⁻² SHR¹⁰(x)) # ROTRⁿ(x) = Circular right rotation of 'x' by 'n' bits # SHRⁿ(x) = Circular right shift of 'x' by 'n' bits W = M + ['0'.rjust(32, '0')] * 48 W = [BitString.from_bitstring(w) for w in W] for i in range(16, 64): _W = [w.copy() for w in W] sigma1 = _W[i-15].rotate_right(7).bitwise_xor(_W[i-15].rotate_right(18))\ .bitwise_xor(_W[i-15].shift_right(3)) sigma2 = _W[i-2].rotate_right(17).bitwise_xor(_W[i-2].rotate_right(19))\ .bitwise_xor(_W[i-2].shift_right(10)) W[i] = _W[i - 16].add(sigma1).add(_W[i - 7]).add(sigma1) # Initialize eight working variables a, b, c, d, e, f, g, h = h0, h1, h2, h3, h4, h5, h6, h7 # Compression function for i in range(64): _e = e.copy() _a = a.copy() _c = c.copy() _f = f.copy() _h = h.copy() _g = g.copy() _b = b.copy() sum_e = _e.rotate_right(6).bitwise_xor(_e.rotate_right(11))\ .bitwise_xor(_e.rotate_right(25)) sum_a = _a.rotate_right(2).bitwise_xor(_a.rotate_right(13))\ .bitwise_xor(_a.rotate_right(22)) Ch = _e.bitwise_and(_f).bitwise_xor( _e.bitwise_not().bitwise_and(_g)) maj = _a.bitwise_and(_b).bitwise_xor(_a.bitwise_and(_c))\ .bitwise_xor(_b.bitwise_and(_c)) T1 = _h.add(sum_e).add(Ch).add(K[i]).add(W[i]) T2 = sum_e.add(maj) h, g, f, e, d, c, b, a = g, f, e, d.add(T1), c, b, a, T1.add(T2) # Add compressed chunk to current hash val for h, char in zip([h0, h1, h2, h3, h4, h5, h6, h7], [a, b, c, d, e, f, g, h]): char = BitString.from_bitstring(char.bits) # Produce final hash val digest = h0.extend(h1).extend(h2).extend(h3).extend(h4)\ .extend(h5).extend(h6).extend(h7) return digest