@@ -22,12 +22,11 @@ extension UInt32 {
22
22
}
23
23
24
24
public class HDNode {
25
- public struct HDversion {
26
- // swiftlint:disable force_unwrapping
27
- public var privatePrefix : Data = Data . fromHex ( " 0x0488ADE4 " ) !
28
- public var publicPrefix : Data = Data . fromHex ( " 0x0488B21E " ) !
29
- // swiftlint:enable force_unwrapping
30
- public init ( ) { }
25
+
26
+ private struct HDversion {
27
+ public static var privatePrefix : Data ? = Data . fromHex ( " 0x0488ADE4 " )
28
+ public static var publicPrefix : Data ? = Data . fromHex ( " 0x0488B21E " )
29
+
31
30
}
32
31
public var path : String ? = " m "
33
32
public var privateKey : Data ?
@@ -40,11 +39,11 @@ public class HDNode {
40
39
childNumber >= ( UInt32 ( 1 ) << 31 )
41
40
}
42
41
public var index : UInt32 {
43
- if self . isHardened {
44
- return childNumber - ( UInt32 ( 1 ) << 31 )
45
- } else {
46
- return childNumber
47
- }
42
+ if self . isHardened {
43
+ return childNumber - ( UInt32 ( 1 ) << 31 )
44
+ } else {
45
+ return childNumber
46
+ }
48
47
}
49
48
public var hasPrivate : Bool {
50
49
privateKey != nil
@@ -65,7 +64,7 @@ public class HDNode {
65
64
guard data. count == 82 else { return nil }
66
65
let header = data [ 0 ..< 4 ]
67
66
var serializePrivate = false
68
- if header == HDNode . HDversion ( ) . privatePrefix {
67
+ if header == HDversion . privatePrefix {
69
68
serializePrivate = true
70
69
}
71
70
depth = data [ 4 ..< 5 ] . bytes [ 0 ]
@@ -90,25 +89,25 @@ public class HDNode {
90
89
91
90
public init ? ( seed: Data ) {
92
91
guard seed. count >= 16 else { return nil }
93
- // swiftlint:disable force_unwrapping
94
- let hmacKey = " Bitcoin seed " . data ( using: . ascii) !
95
- let hmac = HMAC ( key: hmacKey. bytes, variant: HMAC . Variant. sha2 ( . sha512) )
92
+
93
+ guard let hmacKey = " Bitcoin seed " . data ( using: . ascii) else { return nil }
94
+ let hmac : Authenticator = HMAC ( key: hmacKey. bytes, variant: HMAC . Variant. sha2 ( . sha512) )
95
+
96
96
guard let entropy = try ? hmac. authenticate ( seed. bytes) , entropy. count == 64 else { return nil }
97
97
let I_L = entropy [ 0 ..< 32 ]
98
98
let I_R = entropy [ 32 ..< 64 ]
99
99
chaincode = Data ( I_R)
100
100
let privKeyCandidate = Data ( I_L)
101
101
guard SECP256K1 . verifyPrivateKey ( privateKey: privKeyCandidate) else { return nil }
102
102
guard let pubKeyCandidate = SECP256K1 . privateToPublic ( privateKey: privKeyCandidate, compressed: true ) else { return nil }
103
- guard pubKeyCandidate. bytes [ 0 ] == 0x02 || pubKeyCandidate. bytes [ 0 ] == 0x03 else { return nil }
103
+ guard pubKeyCandidate. bytes. first == 0x02 || pubKeyCandidate. bytes. first == 0x03 else { return nil }
104
104
publicKey = pubKeyCandidate
105
105
privateKey = privKeyCandidate
106
106
depth = 0x00
107
107
childNumber = UInt32 ( 0 )
108
108
}
109
109
110
110
private static var curveOrder = BigUInt ( " FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 " , radix: 16 ) !
111
- // swiftlint:enable force_unwrapping
112
111
public static var defaultPath : String = " m/44'/60'/0'/0 "
113
112
public static var defaultPathPrefix : String = " m/44'/60'/0' "
114
113
public static var defaultPathMetamask : String = " m/44'/60'/0'/0/0 "
@@ -119,183 +118,184 @@ public class HDNode {
119
118
extension HDNode {
120
119
public func derive( index: UInt32 , derivePrivateKey: Bool , hardened: Bool = false ) -> HDNode ? {
121
120
if derivePrivateKey {
122
- return self . derivePrivateKey ( index: index, hardened: hardened)
123
- } else {
124
- return derivePublicKey ( index: index, hardened: hardened)
121
+ return deriveWithPrivateKey ( index: index, hardened: hardened)
122
+ } else { // deriving only the public key
123
+ return deriveWithoutPrivateKey ( index: index, hardened: hardened)
125
124
}
126
125
}
127
126
128
- public func derive( path: String , derivePrivateKey: Bool = true ) -> HDNode ? {
129
- let components = path. components ( separatedBy: " / " )
130
- var currentNode : HDNode = self
131
- var firstComponent = 0
132
- if path. hasPrefix ( " m " ) {
133
- firstComponent = 1
127
+ public func deriveWithoutPrivateKey( index: UInt32 , hardened: Bool = false ) -> HDNode ? {
128
+ var entropy : [ UInt8 ] // derive public key when is itself public key
129
+ if index >= ( UInt32 ( 1 ) << 31 ) || hardened {
130
+ return nil // no derivation of hardened public key from extended public key
131
+ } else {
132
+ let hmac : Authenticator = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
133
+ var inputForHMAC = Data ( )
134
+ inputForHMAC. append ( self . publicKey)
135
+ inputForHMAC. append ( index. serialize32 ( ) )
136
+ guard let ent = try ? hmac. authenticate ( inputForHMAC. bytes) else { return nil }
137
+ guard ent. count == 64 else { return nil }
138
+ entropy = ent
134
139
}
135
- for component in components [ firstComponent ..< components. count] {
136
- var hardened = false
137
- if component. hasSuffix ( " ' " ) {
138
- hardened = true
140
+ let I_L = entropy [ 0 ..< 32 ]
141
+ let I_R = entropy [ 32 ..< 64 ]
142
+ let cc = Data ( I_R)
143
+ let bn = BigUInt ( Data ( I_L) )
144
+ if bn > HDNode . curveOrder {
145
+ if index < UInt32 . max {
146
+ return self . derive ( index: index+ 1 , derivePrivateKey: false , hardened: hardened)
139
147
}
140
- guard let index = UInt32 ( component. trimmingCharacters ( in: CharacterSet ( charactersIn: " ' " ) ) ) else { return nil }
141
- guard let newNode = currentNode. derive ( index: index, derivePrivateKey: derivePrivateKey, hardened: hardened) else { return nil }
142
- currentNode = newNode
148
+ return nil
143
149
}
144
- return currentNode
150
+ guard let tempKey = bn. serialize ( ) . setLengthLeft ( 32 ) else { return nil }
151
+ guard SECP256K1 . verifyPrivateKey ( privateKey: tempKey) else { return nil }
152
+ guard let pubKeyCandidate = SECP256K1 . privateToPublic ( privateKey: tempKey, compressed: true ) else { return nil }
153
+ guard pubKeyCandidate. bytes. first == 0x02 || pubKeyCandidate. bytes. first == 0x03 else { return nil }
154
+ guard let newPublicKey = SECP256K1 . combineSerializedPublicKeys ( keys: [ self . publicKey, pubKeyCandidate] , outputCompressed: true ) else { return nil }
155
+ guard newPublicKey. bytes. first == 0x02 || newPublicKey. bytes. first == 0x03 else { return nil }
156
+ guard self . depth < UInt8 . max else { return nil }
157
+ let newNode = HDNode ( )
158
+ newNode. chaincode = cc
159
+ newNode. depth = self . depth + 1
160
+ newNode. publicKey = newPublicKey
161
+ newNode. childNumber = index
162
+ guard let fprint = try ? RIPEMD160 . hash ( message: self . publicKey. sha256 ( ) ) [ 0 ..< 4 ] else {
163
+ return nil
164
+ }
165
+ newNode. parentFingerprint = fprint
166
+ var newPath = String ( )
167
+ if newNode. isHardened {
168
+ newPath = ( self . path ?? " " ) + " / "
169
+ newPath += String ( newNode. index % HDNode. hardenedIndexPrefix) + " ' "
170
+ } else {
171
+ newPath = ( self . path ?? " " ) + " / " + String( newNode. index)
172
+ }
173
+ newNode. path = newPath
174
+ return newNode
145
175
}
176
+ public func deriveWithPrivateKey( index: UInt32 , hardened: Bool = false ) -> HDNode ? {
146
177
147
- /// Derive public key when is itself private key.
148
- /// Derivation of private key when is itself extended public key is impossible and will return `nil`.
149
- private func derivePrivateKey( index: UInt32 , hardened: Bool ) -> HDNode ? {
150
- guard let privateKey = privateKey else {
151
- // derive private key when is itself extended public key (impossible)
178
+ guard let privateKey = self . privateKey else {
152
179
return nil
153
180
}
154
-
155
- var trueIndex = index
156
- if trueIndex < ( UInt32 ( 1 ) << 31 ) && hardened {
157
- trueIndex += ( UInt32 ( 1 ) << 31 )
181
+ var entropy : [ UInt8 ]
182
+ var trueIndex : UInt32
183
+ if index >= ( UInt32 ( 1 ) << 31 ) || hardened {
184
+ trueIndex = index
185
+ if trueIndex < ( UInt32 ( 1 ) << 31 ) {
186
+ trueIndex = trueIndex + ( UInt32 ( 1 ) << 31 )
187
+ }
188
+ let hmac : Authenticator = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
189
+ var inputForHMAC = Data ( )
190
+ inputForHMAC. append ( Data ( [ UInt8 ( 0x00 ) ] ) )
191
+ inputForHMAC. append ( privateKey)
192
+ inputForHMAC. append ( trueIndex. serialize32 ( ) )
193
+ guard let ent = try ? hmac. authenticate ( inputForHMAC. bytes) else { return nil }
194
+ guard ent. count == 64 else { return nil }
195
+ entropy = ent
196
+ } else {
197
+ trueIndex = index
198
+ let hmac : Authenticator = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
199
+ var inputForHMAC = Data ( )
200
+ inputForHMAC. append ( self . publicKey)
201
+ inputForHMAC. append ( trueIndex. serialize32 ( ) )
202
+ guard let ent = try ? hmac. authenticate ( inputForHMAC. bytes) else { return nil }
203
+ guard ent. count == 64 else { return nil }
204
+ entropy = ent
158
205
}
159
-
160
- guard let entropy = calculateEntropy ( index: trueIndex, privateKey: privateKey, hardened: hardened) else { return nil }
161
-
162
206
let I_L = entropy [ 0 ..< 32 ]
163
207
let I_R = entropy [ 32 ..< 64 ]
164
- let chainCode = Data ( I_R)
208
+ let cc = Data ( I_R)
165
209
let bn = BigUInt ( Data ( I_L) )
166
210
if bn > HDNode . curveOrder {
167
211
if trueIndex < UInt32 . max {
168
- return self . derive ( index: index + 1 , derivePrivateKey: true , hardened: hardened)
212
+ return self . derive ( index: index+ 1 , derivePrivateKey: true , hardened: hardened)
169
213
}
170
214
return nil
171
215
}
172
- let newPK = ( bn + BigUInt( privateKey) ) % HDNode. curveOrder
216
+ let newPK = ( bn + BigUInt( self . privateKey! ) ) % HDNode. curveOrder
173
217
if newPK == BigUInt ( 0 ) {
174
218
if trueIndex < UInt32 . max {
175
- return self . derive ( index: index + 1 , derivePrivateKey: true , hardened: hardened)
219
+ return self . derive ( index: index+ 1 , derivePrivateKey: true , hardened: hardened)
176
220
}
177
221
return nil
178
222
}
179
-
180
- guard
181
- let newPrivateKey = newPK. serialize ( ) . setLengthLeft ( 32 ) ,
182
- SECP256K1 . verifyPrivateKey ( privateKey: newPrivateKey) ,
183
- let newPublicKey = SECP256K1 . privateToPublic ( privateKey: newPrivateKey, compressed: true ) ,
184
- ( newPublicKey. bytes [ 0 ] == 0x02 || newPublicKey. bytes [ 0 ] == 0x03 ) ,
185
- self . depth < UInt8 . max
186
- else { return nil }
187
- return createNode ( chainCode: chainCode, depth: depth + 1 , publicKey: newPublicKey, privateKey: newPrivateKey, childNumber: trueIndex)
188
- }
189
-
190
- /// Derive public key when is itself public key.
191
- /// No derivation of hardened public key from extended public key is allowed.
192
- private func derivePublicKey( index: UInt32 , hardened: Bool ) -> HDNode ? {
193
- if index >= ( UInt32 ( 1 ) << 31 ) || hardened {
194
- // no derivation of hardened public key from extended public key
195
- return nil
196
- }
197
-
198
- guard let entropy = calculateEntropy ( index: index, hardened: hardened) else { return nil }
199
-
200
- let I_L = entropy [ 0 ..< 32 ]
201
- let I_R = entropy [ 32 ..< 64 ]
202
- let chainCode = Data ( I_R)
203
- let bn = BigUInt ( Data ( I_L) )
204
- if bn > HDNode . curveOrder {
205
- if index < UInt32 . max {
206
- return self . derive ( index: index+ 1 , derivePrivateKey: false , hardened: hardened)
207
- }
223
+ guard let privKeyCandidate = newPK. serialize ( ) . setLengthLeft ( 32 ) else { return nil }
224
+ guard SECP256K1 . verifyPrivateKey ( privateKey: privKeyCandidate) else { return nil }
225
+ guard let pubKeyCandidate = SECP256K1 . privateToPublic ( privateKey: privKeyCandidate, compressed: true ) else { return nil }
226
+ guard pubKeyCandidate. bytes [ 0 ] == 0x02 || pubKeyCandidate. bytes [ 0 ] == 0x03 else { return nil }
227
+ guard self . depth < UInt8 . max else { return nil }
228
+ let newNode = HDNode ( )
229
+ newNode. chaincode = cc
230
+ newNode. depth = self . depth + 1
231
+ newNode. publicKey = pubKeyCandidate
232
+ newNode. privateKey = privKeyCandidate
233
+ newNode. childNumber = trueIndex
234
+ guard let fprint = try ? RIPEMD160 . hash ( message: self . publicKey. sha256 ( ) ) [ 0 ..< 4 ] else {
208
235
return nil
209
236
}
210
-
211
- guard
212
- let tempKey = bn. serialize ( ) . setLengthLeft ( 32 ) ,
213
- SECP256K1 . verifyPrivateKey ( privateKey: tempKey) ,
214
- let pubKeyCandidate = SECP256K1 . privateToPublic ( privateKey: tempKey, compressed: true ) ,
215
- ( pubKeyCandidate. bytes [ 0 ] == 0x02 || pubKeyCandidate. bytes [ 0 ] == 0x03 ) ,
216
- let newPublicKey = SECP256K1 . combineSerializedPublicKeys ( keys: [ self . publicKey, pubKeyCandidate] , outputCompressed: true ) ,
217
- ( newPublicKey. bytes [ 0 ] == 0x02 || newPublicKey. bytes [ 0 ] == 0x03 ) ,
218
- self . depth < UInt8 . max
219
- else { return nil }
220
-
221
- return createNode ( chainCode: chainCode, depth: depth + 1 , publicKey: newPublicKey, childNumber: index)
222
- }
223
-
224
- private func createNode( chainCode: Data , depth: UInt8 , publicKey: Data , privateKey: Data ? = nil , childNumber: UInt32 ) -> HDNode ? {
225
- let newNode = HDNode ( )
226
- newNode. chaincode = chainCode
227
- newNode. depth = depth
228
- newNode. publicKey = publicKey
229
- newNode. privateKey = privateKey
230
- newNode. childNumber = childNumber
231
- guard
232
- let fprint = try ? RIPEMD160 . hash ( message: self . publicKey. sha256 ( ) ) [ 0 ..< 4 ] ,
233
- let path = path
234
- else { return nil }
235
237
newNode. parentFingerprint = fprint
236
238
var newPath = String ( )
237
239
if newNode. isHardened {
238
- newPath = path + " / "
240
+ newPath = self . path! + " / "
239
241
newPath += String ( newNode. index % HDNode. hardenedIndexPrefix) + " ' "
240
242
} else {
241
- newPath = path + " / " + String( newNode. index)
243
+ newPath = self . path! + " / " + String( newNode. index)
242
244
}
243
245
newNode. path = newPath
244
246
return newNode
247
+
245
248
}
246
249
247
- private func calculateHMACInput( _ index: UInt32 , privateKey: Data ? = nil , hardened: Bool ) -> Data {
248
- var inputForHMAC = Data ( )
250
+ public func derive( path: String , derivePrivateKey: Bool = true ) -> HDNode ? {
249
251
250
- if let privateKey = privateKey , ( index >= ( UInt32 ( 1 ) << 31 ) || hardened ) {
251
- inputForHMAC . append ( Data ( [ UInt8 ( 0x00 ) ] ) )
252
- inputForHMAC . append ( privateKey )
253
- } else {
254
- inputForHMAC . append ( self . publicKey )
252
+ let components = path . components ( separatedBy : " / " )
253
+ var currentNode : HDNode = self
254
+ var firstComponent = 0
255
+ if path . hasPrefix ( " m " ) {
256
+ firstComponent = 1
255
257
}
256
-
257
- inputForHMAC. append ( index. serialize32 ( ) )
258
- return inputForHMAC
258
+ for component in components [ firstComponent ..< components. count] {
259
+ var hardened = false
260
+ if component. hasSuffix ( " ' " ) {
261
+ hardened = true
262
+ }
263
+ guard let index = UInt32 ( component. trimmingCharacters ( in: CharacterSet ( charactersIn: " ' " ) ) ) else { return nil }
264
+ guard let newNode = currentNode. derive ( index: index, derivePrivateKey: derivePrivateKey, hardened: hardened) else { return nil }
265
+ currentNode = newNode
266
+ }
267
+ return currentNode
259
268
}
260
269
261
- /// Calculates entropy used for private or public key derivation.
262
- /// - Parameters:
263
- /// - index: index
264
- /// - privateKey: private key data or `nil` if entropy is calculated for a public key;
265
- /// - hardened: is hardened key
266
- /// - Returns: 64 bytes entropy or `nil`.
267
- private func calculateEntropy( index: UInt32 , privateKey: Data ? = nil , hardened: Bool ) -> [ UInt8 ] ? {
268
- let inputForHMAC = calculateHMACInput ( index, privateKey: privateKey, hardened: hardened)
269
- let hmac = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
270
- guard let entropy = try ? hmac. authenticate ( inputForHMAC. bytes) , entropy. count == 64 else { return nil }
271
- return entropy
270
+ public func serializeToString( serializePublic: Bool = true ) -> String ? {
271
+ guard let data = self . serialize ( serializePublic: serializePublic) else { return nil }
272
+ let encoded = Base58 . base58FromBytes ( data. bytes)
273
+ return encoded
272
274
}
273
275
274
- public func serializeToString( serializePublic: Bool = true , version: HDversion = HDversion ( ) ) -> String ? {
275
- guard let data = self . serialize ( serializePublic: serializePublic, version: version) else { return nil }
276
- return Base58 . base58FromBytes ( data. bytes)
277
- }
276
+ public func serialize( serializePublic: Bool = true ) -> Data ? {
278
277
279
- public func serialize( serializePublic: Bool = true , version: HDversion = HDversion ( ) ) -> Data ? {
280
278
var data = Data ( )
281
- /// Public or private key
282
- let keyData : Data
279
+
280
+ guard serializePublic || privateKey != nil else {
281
+ return nil
282
+ }
283
+
283
284
if serializePublic {
284
- keyData = publicKey
285
- data. append ( version. publicPrefix)
285
+ data. append ( HDversion . publicPrefix!)
286
286
} else {
287
- guard let privateKey = privateKey else { return nil }
288
- keyData = privateKey
289
- data. append ( version. privatePrefix)
287
+ data. append ( HDversion . privatePrefix!)
290
288
}
291
- data. append ( contentsOf: [ depth] )
292
- data. append ( parentFingerprint)
293
- data. append ( childNumber. serialize32 ( ) )
294
- data. append ( chaincode)
295
- if !serializePublic {
289
+ data. append ( contentsOf: [ self . depth] )
290
+ data. append ( self . parentFingerprint)
291
+ data. append ( self . childNumber. serialize32 ( ) )
292
+ data. append ( self . chaincode)
293
+ if serializePublic {
294
+ data. append ( self . publicKey)
295
+ } else {
296
296
data. append ( contentsOf: [ 0x00 ] )
297
+ data. append ( self . privateKey!)
297
298
}
298
- data. append ( keyData)
299
299
let hashedData = data. sha256 ( ) . sha256 ( )
300
300
let checksum = hashedData [ 0 ..< 4 ]
301
301
data. append ( checksum)
0 commit comments