8
8
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9
9
*/
10
10
11
+ public protocol HashAlgorithm {
12
+
13
+ /// Hashes the input bytes, returning the digest.
14
+ ///
15
+ /// - Parameters:
16
+ /// - bytes: The input bytes.
17
+ /// - Returns: The output digest.
18
+ func hash( _ bytes: ByteString ) -> ByteString
19
+ }
20
+
21
+ extension HashAlgorithm {
22
+ public func hash( _ string: String ) -> ByteString {
23
+ hash ( ByteString ( [ UInt8] ( string. utf8) ) )
24
+ }
25
+ }
26
+
11
27
/// SHA-256 implementation from Secure Hash Algorithm 2 (SHA-2) set of
12
28
/// cryptographic hash functions (FIPS PUB 180-2).
13
- public final class SHA256 {
29
+ public struct SHA256 : HashAlgorithm {
14
30
15
31
/// The length of the output digest (in bits).
16
- let digestLength = 256
32
+ private static let digestLength = 256
17
33
18
34
/// The size of each blocks (in bits).
19
- let blockBitSize = 512
35
+ private static let blockBitSize = 512
20
36
21
37
/// The initial hash value.
22
38
private static let initalHashValue : [ UInt32 ] = [
@@ -35,60 +51,28 @@ public final class SHA256 {
35
51
0x748f82ee , 0x78a5636f , 0x84c87814 , 0x8cc70208 , 0x90befffa , 0xa4506ceb , 0xbef9a3f7 , 0xc67178f2
36
52
]
37
53
38
- /// The hash that is being computed.
39
- private var hash = SHA256 . initalHashValue
40
-
41
- /// The input that was provided. It will be padded when computing the digest.
42
- private var input : [ UInt8 ]
43
-
44
- /// The result, once computed.
45
- private var result : [ UInt8 ] ?
46
-
47
- public init ( _ input: [ UInt8 ] ) {
48
- self . input = input
54
+ public init ( ) {
49
55
}
50
56
51
- public init ( _ bytes: ByteString ) {
52
- self . input = bytes. contents
53
- }
54
-
55
- public init ( _ string: String ) {
56
- self . input = [ UInt8] ( string. utf8)
57
- }
58
-
59
- /// Returns the digest as hexadecimal string.
60
- public func digestString( ) -> String {
61
- return digest ( ) . reduce ( " " ) {
62
- var str = String ( $1, radix: 16 )
63
- // The above method does not do zero padding.
64
- if str. count == 1 {
65
- str = " 0 " + str
66
- }
67
- return $0 + str
68
- }
69
- }
70
-
71
- /// Returns the digest.
72
- public func digest( ) -> [ UInt8 ] {
73
-
74
- // If we already have the result, we're done.
75
- if let result = self . result {
76
- return result
77
- }
57
+ public func hash( _ bytes: ByteString ) -> ByteString {
58
+ var input = bytes. contents
78
59
79
60
// Pad the input.
80
61
pad ( & input)
81
62
82
63
// Break the input into N 512-bit blocks.
83
- let messageBlocks = input. blocks ( size: blockBitSize / 8 )
64
+ let messageBlocks = input. blocks ( size: SHA256 . blockBitSize / 8 )
65
+
66
+ /// The hash that is being computed.
67
+ var hash = SHA256 . initalHashValue
84
68
85
69
// Process each block.
86
70
for block in messageBlocks {
87
- process ( block)
71
+ process ( block, hash : & hash )
88
72
}
89
73
90
74
// Finally, compute the result.
91
- var result = [ UInt8] ( repeating: 0 , count: digestLength / 8 )
75
+ var result = [ UInt8] ( repeating: 0 , count: SHA256 . digestLength / 8 )
92
76
for (idx, element) in hash. enumerated ( ) {
93
77
let pos = idx * 4
94
78
result [ pos + 0 ] = UInt8 ( ( element >> 24 ) & 0xff )
@@ -97,12 +81,11 @@ public final class SHA256 {
97
81
result [ pos + 3 ] = UInt8 ( element & 0xff )
98
82
}
99
83
100
- self . result = result
101
- return result
84
+ return ByteString ( result)
102
85
}
103
86
104
87
/// Process and compute hash from a block.
105
- private func process( _ block: ArraySlice < UInt8 > ) {
88
+ private func process( _ block: ArraySlice < UInt8 > , hash : inout [ UInt32 ] ) {
106
89
107
90
// Compute message schedule.
108
91
var W = [ UInt32] ( repeating: 0 , count: SHA256 . konstants. count)
0 commit comments