@@ -9,8 +9,7 @@ import CryptoSwift
99
1010extension UInt32 {
1111 public func serialize32( ) -> Data {
12- let uint32 = UInt32 ( self )
13- var bigEndian = uint32. bigEndian
12+ var bigEndian = self . bigEndian
1413 let count = MemoryLayout< UInt32> . size
1514 let bytePtr = withUnsafePointer ( to: & bigEndian) {
1615 $0. withMemoryRebound ( to: UInt8 . self, capacity: count) {
@@ -24,11 +23,11 @@ extension UInt32 {
2423
2524public class HDNode {
2625 public struct HDversion {
26+ // swiftlint:disable force_unwrapping
2727 public var privatePrefix : Data = Data . fromHex ( " 0x0488ADE4 " ) !
2828 public var publicPrefix : Data = Data . fromHex ( " 0x0488B21E " ) !
29- public init ( ) {
30-
31- }
29+ // swiftlint:enable force_unwrapping
30+ public init ( ) { }
3231 }
3332 public var path : String ? = " m "
3433 public var privateKey : Data ?
@@ -38,23 +37,17 @@ public class HDNode {
3837 public var parentFingerprint : Data = Data ( repeating: 0 , count: 4 )
3938 public var childNumber : UInt32 = UInt32 ( 0 )
4039 public var isHardened : Bool {
41- get {
42- return self . childNumber >= ( UInt32 ( 1 ) << 31 )
43- }
40+ childNumber >= ( UInt32 ( 1 ) << 31 )
4441 }
4542 public var index : UInt32 {
46- get {
4743 if self . isHardened {
48- return self . childNumber - ( UInt32 ( 1 ) << 31 )
44+ return childNumber - ( UInt32 ( 1 ) << 31 )
4945 } else {
50- return self . childNumber
46+ return childNumber
5147 }
52- }
5348 }
5449 public var hasPrivate : Bool {
55- get {
56- return privateKey != nil
57- }
50+ privateKey != nil
5851 }
5952
6053 init ( ) {
@@ -81,8 +74,11 @@ public class HDNode {
8174 chaincode = data [ 13 ..< 45 ]
8275 if serializePrivate {
8376 privateKey = data [ 46 ..< 78 ]
84- guard let pubKey = Utilities . privateToPublic ( privateKey!, compressed: true ) else { return nil }
85- if pubKey [ 0 ] != 0x02 && pubKey [ 0 ] != 0x03 { return nil }
77+ guard
78+ let privateKey = privateKey,
79+ let pubKey = Utilities . privateToPublic ( privateKey, compressed: true ) ,
80+ ( pubKey [ 0 ] == 0x02 || pubKey [ 0 ] == 0x03 )
81+ else { return nil }
8682 publicKey = pubKey
8783 } else {
8884 publicKey = data [ 45 ..< 78 ]
@@ -94,10 +90,10 @@ public class HDNode {
9490
9591 public init ? ( seed: Data ) {
9692 guard seed. count >= 16 else { return nil }
93+ // swiftlint:disable force_unwrapping
9794 let hmacKey = " Bitcoin seed " . data ( using: . ascii) !
98- let hmac : Authenticator = HMAC ( key: hmacKey. bytes, variant: HMAC . Variant. sha2 ( . sha512) )
99- guard let entropy = try ? hmac. authenticate ( seed. bytes) else { return nil }
100- guard entropy. count == 64 else { return nil }
95+ let hmac = HMAC ( key: hmacKey. bytes, variant: HMAC . Variant. sha2 ( . sha512) )
96+ guard let entropy = try ? hmac. authenticate ( seed. bytes) , entropy. count == 64 else { return nil }
10197 let I_L = entropy [ 0 ..< 32 ]
10298 let I_R = entropy [ 32 ..< 64 ]
10399 chaincode = Data ( I_R)
@@ -112,6 +108,7 @@ public class HDNode {
112108 }
113109
114110 private static var curveOrder = BigUInt ( " FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 " , radix: 16 ) !
111+ // swiftlint:enable force_unwrapping
115112 public static var defaultPath : String = " m/44'/60'/0'/0 "
116113 public static var defaultPathPrefix : String = " m/44'/60'/0' "
117114 public static var defaultPathMetamask : String = " m/44'/60'/0'/0/0 "
@@ -120,130 +117,15 @@ public class HDNode {
120117}
121118
122119extension HDNode {
123- public func derive ( index: UInt32 , derivePrivateKey: Bool , hardened: Bool = false ) -> HDNode ? {
120+ public func derive( index: UInt32 , derivePrivateKey: Bool , hardened: Bool = false ) -> HDNode ? {
124121 if derivePrivateKey {
125- if self . hasPrivate { // derive private key when is itself extended private key
126- var entropy : [ UInt8 ]
127- var trueIndex : UInt32
128- if index >= ( UInt32 ( 1 ) << 31 ) || hardened {
129- trueIndex = index
130- if trueIndex < ( UInt32 ( 1 ) << 31 ) {
131- trueIndex = trueIndex + ( UInt32 ( 1 ) << 31 )
132- }
133- let hmac : Authenticator = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
134- var inputForHMAC = Data ( )
135- inputForHMAC. append ( Data ( [ UInt8 ( 0x00 ) ] ) )
136- inputForHMAC. append ( self . privateKey!)
137- inputForHMAC. append ( trueIndex. serialize32 ( ) )
138- guard let ent = try ? hmac. authenticate ( inputForHMAC. bytes) else { return nil }
139- guard ent. count == 64 else { return nil }
140- entropy = ent
141- } else {
142- trueIndex = index
143- let hmac : Authenticator = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
144- var inputForHMAC = Data ( )
145- inputForHMAC. append ( self . publicKey)
146- inputForHMAC. append ( trueIndex. serialize32 ( ) )
147- guard let ent = try ? hmac. authenticate ( inputForHMAC. bytes) else { return nil }
148- guard ent. count == 64 else { return nil }
149- entropy = ent
150- }
151- let I_L = entropy [ 0 ..< 32 ]
152- let I_R = entropy [ 32 ..< 64 ]
153- let cc = Data ( I_R)
154- let bn = BigUInt ( Data ( I_L) )
155- if bn > HDNode . curveOrder {
156- if trueIndex < UInt32 . max {
157- return self . derive ( index: index+ 1 , derivePrivateKey: derivePrivateKey, hardened: hardened)
158- }
159- return nil
160- }
161- let newPK = ( bn + BigUInt( self . privateKey!) ) % HDNode. curveOrder
162- if newPK == BigUInt ( 0 ) {
163- if trueIndex < UInt32 . max {
164- return self . derive ( index: index+ 1 , derivePrivateKey: derivePrivateKey, hardened: hardened)
165- }
166- return nil
167- }
168- guard let privKeyCandidate = newPK. serialize ( ) . setLengthLeft ( 32 ) else { return nil }
169- guard SECP256K1 . verifyPrivateKey ( privateKey: privKeyCandidate) else { return nil }
170- guard let pubKeyCandidate = SECP256K1 . privateToPublic ( privateKey: privKeyCandidate, compressed: true ) else { return nil }
171- guard pubKeyCandidate. bytes [ 0 ] == 0x02 || pubKeyCandidate. bytes [ 0 ] == 0x03 else { return nil }
172- guard self . depth < UInt8 . max else { return nil }
173- let newNode = HDNode ( )
174- newNode. chaincode = cc
175- newNode. depth = self . depth + 1
176- newNode. publicKey = pubKeyCandidate
177- newNode. privateKey = privKeyCandidate
178- newNode. childNumber = trueIndex
179- guard let fprint = try ? RIPEMD160 . hash ( message: self . publicKey. sha256 ( ) ) [ 0 ..< 4 ] else {
180- return nil
181- }
182- newNode. parentFingerprint = fprint
183- var newPath = String ( )
184- if newNode. isHardened {
185- newPath = self . path! + " / "
186- newPath += String ( newNode. index % HDNode. hardenedIndexPrefix) + " ' "
187- } else {
188- newPath = self . path! + " / " + String( newNode. index)
189- }
190- newNode. path = newPath
191- return newNode
192- } else {
193- return nil // derive private key when is itself extended public key (impossible)
194- }
195- } else { // deriving only the public key
196- var entropy : [ UInt8 ] // derive public key when is itself public key
197- if index >= ( UInt32 ( 1 ) << 31 ) || hardened {
198- return nil // no derivation of hardened public key from extended public key
199- } else {
200- let hmac : Authenticator = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
201- var inputForHMAC = Data ( )
202- inputForHMAC. append ( self . publicKey)
203- inputForHMAC. append ( index. serialize32 ( ) )
204- guard let ent = try ? hmac. authenticate ( inputForHMAC. bytes) else { return nil }
205- guard ent. count == 64 else { return nil }
206- entropy = ent
207- }
208- let I_L = entropy [ 0 ..< 32 ]
209- let I_R = entropy [ 32 ..< 64 ]
210- let cc = Data ( I_R)
211- let bn = BigUInt ( Data ( I_L) )
212- if bn > HDNode . curveOrder {
213- if index < UInt32 . max {
214- return self . derive ( index: index+ 1 , derivePrivateKey: derivePrivateKey, hardened: hardened)
215- }
216- return nil
217- }
218- guard let tempKey = bn. serialize ( ) . setLengthLeft ( 32 ) else { return nil }
219- guard SECP256K1 . verifyPrivateKey ( privateKey: tempKey) else { return nil }
220- guard let pubKeyCandidate = SECP256K1 . privateToPublic ( privateKey: tempKey, compressed: true ) else { return nil }
221- guard pubKeyCandidate. bytes [ 0 ] == 0x02 || pubKeyCandidate. bytes [ 0 ] == 0x03 else { return nil }
222- guard let newPublicKey = SECP256K1 . combineSerializedPublicKeys ( keys: [ self . publicKey, pubKeyCandidate] , outputCompressed: true ) else { return nil }
223- guard newPublicKey. bytes [ 0 ] == 0x02 || newPublicKey. bytes [ 0 ] == 0x03 else { return nil }
224- guard self . depth < UInt8 . max else { return nil }
225- let newNode = HDNode ( )
226- newNode. chaincode = cc
227- newNode. depth = self . depth + 1
228- newNode. publicKey = newPublicKey
229- newNode. childNumber = index
230- guard let fprint = try ? RIPEMD160 . hash ( message: self . publicKey. sha256 ( ) ) [ 0 ..< 4 ] else {
231- return nil
232- }
233- newNode. parentFingerprint = fprint
234- var newPath = String ( )
235- if newNode. isHardened {
236- newPath = self . path! + " / "
237- newPath += String ( newNode. index % HDNode. hardenedIndexPrefix) + " ' "
238- } else {
239- newPath = self . path! + " / " + String( newNode. index)
240- }
241- newNode. path = newPath
242- return newNode
122+ return self . derivePrivateKey ( index: index, hardened: hardened)
123+ } else {
124+ return derivePublicKey ( index: index, hardened: hardened)
243125 }
244126 }
245127
246- public func derive ( path: String , derivePrivateKey: Bool = true ) -> HDNode ? {
128+ public func derive( path: String , derivePrivateKey: Bool = true ) -> HDNode ? {
247129 let components = path. components ( separatedBy: " / " )
248130 var currentNode : HDNode = self
249131 var firstComponent = 0
@@ -262,30 +144,158 @@ extension HDNode {
262144 return currentNode
263145 }
264146
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)
152+ return nil
153+ }
154+
155+ var trueIndex = index
156+ if trueIndex < ( UInt32 ( 1 ) << 31 ) && hardened {
157+ trueIndex += ( UInt32 ( 1 ) << 31 )
158+ }
159+
160+ guard let entropy = calculateEntropy ( index: trueIndex, privateKey: privateKey, hardened: hardened) else { return nil }
161+
162+ let I_L = entropy [ 0 ..< 32 ]
163+ let I_R = entropy [ 32 ..< 64 ]
164+ let chainCode = Data ( I_R)
165+ let bn = BigUInt ( Data ( I_L) )
166+ if bn > HDNode . curveOrder {
167+ if trueIndex < UInt32 . max {
168+ return self . derive ( index: index + 1 , derivePrivateKey: true , hardened: hardened)
169+ }
170+ return nil
171+ }
172+ let newPK = ( bn + BigUInt( privateKey) ) % HDNode. curveOrder
173+ if newPK == BigUInt ( 0 ) {
174+ if trueIndex < UInt32 . max {
175+ return self . derive ( index: index + 1 , derivePrivateKey: true , hardened: hardened)
176+ }
177+ return nil
178+ }
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+ }
208+ return nil
209+ }
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+ newNode. parentFingerprint = fprint
236+ var newPath = String ( )
237+ if newNode. isHardened {
238+ newPath = path + " / "
239+ newPath += String ( newNode. index % HDNode. hardenedIndexPrefix) + " ' "
240+ } else {
241+ newPath = path + " / " + String( newNode. index)
242+ }
243+ newNode. path = newPath
244+ return newNode
245+ }
246+
247+ private func calculateHMACInput( _ index: UInt32 , privateKey: Data ? = nil , hardened: Bool ) -> Data {
248+ var inputForHMAC = Data ( )
249+
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)
255+ }
256+
257+ inputForHMAC. append ( index. serialize32 ( ) )
258+ return inputForHMAC
259+ }
260+
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
272+ }
273+
265274 public func serializeToString( serializePublic: Bool = true , version: HDversion = HDversion ( ) ) -> String ? {
266275 guard let data = self . serialize ( serializePublic: serializePublic, version: version) else { return nil }
267- let encoded = Base58 . base58FromBytes ( data. bytes)
268- return encoded
276+ return Base58 . base58FromBytes ( data. bytes)
269277 }
270278
271279 public func serialize( serializePublic: Bool = true , version: HDversion = HDversion ( ) ) -> Data ? {
272280 var data = Data ( )
273- if !serializePublic && !self . hasPrivate { return nil }
281+ /// Public or private key
282+ let keyData : Data
274283 if serializePublic {
284+ keyData = publicKey
275285 data. append ( version. publicPrefix)
276286 } else {
287+ guard let privateKey = privateKey else { return nil }
288+ keyData = privateKey
277289 data. append ( version. privatePrefix)
278290 }
279- data. append ( contentsOf: [ self . depth] )
280- data. append ( self . parentFingerprint)
281- data. append ( self . childNumber. serialize32 ( ) )
282- data. append ( self . chaincode)
283- if serializePublic {
284- data. append ( self . publicKey)
285- } else {
291+ data. append ( contentsOf: [ depth] )
292+ data. append ( parentFingerprint)
293+ data. append ( childNumber. serialize32 ( ) )
294+ data. append ( chaincode)
295+ if !serializePublic {
286296 data. append ( contentsOf: [ 0x00 ] )
287- data. append ( self . privateKey!)
288297 }
298+ data. append ( keyData)
289299 let hashedData = data. sha256 ( ) . sha256 ( )
290300 let checksum = hashedData [ 0 ..< 4 ]
291301 data. append ( checksum)
0 commit comments