5 // Created by Dongri Jin on 1/28/15.
6 // Copyright (c) 2015 Dongri Jin. All rights reserved.
13 private var message: [UInt8]
15 fileprivate let h: [UInt32] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]
17 init(_ message: Data) {
18 self.message = message.bytes
20 init(_ message: [UInt8]) {
21 self.message = message
24 /// Common part for hash calculation. Prepare header data.
25 func prepare(_ message: [UInt8], _ blockSize: Int, _ allowance: Int) -> [UInt8] {
26 var tmpMessage = message
28 // Step 1. Append Padding Bits
29 tmpMessage.append(0x80) // append one bit (Byte with one bit) to message
31 // append "0" bit until message length in bits ≡ 448 (mod 512)
32 var msgLength = tmpMessage.count
35 while msgLength % blockSize != (blockSize - allowance) {
40 tmpMessage += [UInt8](repeating: 0, count: counter)
45 func calculate() -> [UInt8] {
46 var tmpMessage = self.prepare(self.message, 64, 64 / 8)
51 // append message length, in a 64-bit big-endian integer. So now the message length is a multiple of 512 bits.
52 tmpMessage += (self.message.count * 8).bytes(64 / 8)
54 // Process the message in successive 512-bit chunks:
55 let chunkSizeBytes = 512 / 8 // 64
56 for chunk in BytesSequence(data: tmpMessage, chunkSize: chunkSizeBytes) {
57 // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15, big-endian
58 // Extend the sixteen 32-bit words into eighty 32-bit words:
59 var M: [UInt32] = [UInt32](repeating: 0, count: 80)
60 for x in 0..<M.count {
64 let memorySize = MemoryLayout<UInt32>.size
65 let start = chunk.startIndex + (x * memorySize)
66 let end = start + memorySize
67 let le = chunk[start..<end].toUInt32
70 M[x] = rotateLeft(M[x-3] ^ M[x-8] ^ M[x-14] ^ M[x-16], n: 1)
87 f = (B & C) | ((~B) & D)
93 f = (B & C) | (B & D) | (C & D)
102 let temp = (rotateLeft(A, n: 5) &+ f &+ E &+ M[j] &+ k) & 0xffffffff
105 C = rotateLeft(B, n: 30)
111 hh[0] = (hh[0] &+ A) & 0xffffffff
112 hh[1] = (hh[1] &+ B) & 0xffffffff
113 hh[2] = (hh[2] &+ C) & 0xffffffff
114 hh[3] = (hh[3] &+ D) & 0xffffffff
115 hh[4] = (hh[4] &+ E) & 0xffffffff
118 // Produce the final hash value (big-endian) as a 160 bit number:
119 var result = [UInt8]()
120 result.reserveCapacity(hh.count / 4)
122 let item = $0.bigEndian
123 result += [UInt8(item & 0xff), UInt8((item >> 8) & 0xff), UInt8((item >> 16) & 0xff), UInt8((item >> 24) & 0xff)]
129 private func rotateLeft(_ v: UInt32, n: UInt32) -> UInt32 {
130 return ((v << n) & 0xFFFFFFFF) | (v >> (32 - n))
135 private struct BytesSequence<D: RandomAccessCollection>: Sequence where D.Iterator.Element == UInt8, D.Index == Int {
139 func makeIterator() -> AnyIterator<D.SubSequence> {
140 var offset = data.startIndex
142 let end = Swift.min(self.chunkSize, self.data.count - offset)
143 let result = self.data[offset..<offset + end]
144 offset = offset.advanced(by: result.count)