@@ -128,121 +128,118 @@ public class HDNode {
128128extension HDNode {
129129 public func derive( index: UInt32 , derivePrivateKey: Bool , hardened: Bool = false ) -> HDNode ? {
130130 if derivePrivateKey {
131- return deriveWithPrivateKey ( index: index, hardened: hardened)
132- } else { // deriving only the public key
133- return deriveWithoutPrivateKey ( index: index, hardened: hardened)
131+ return self . derivePrivateKey ( index: index, hardened: hardened)
132+ } else {
133+ return derivePublicKey ( index: index, hardened: hardened)
134134 }
135135 }
136136
137- public func deriveWithoutPrivateKey( index: UInt32 , hardened: Bool = false ) -> HDNode ? {
138- var entropy : [ UInt8 ] // derive public key when is itself public key
139- if index >= Self . maxIterationIndex || hardened {
140- return nil // no derivation of hardened public key from extended public key
141- } else {
142- let hmac : Authenticator = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
143- var inputForHMAC = Data ( )
144- inputForHMAC. append ( self . publicKey)
145- inputForHMAC. append ( index. serialize32 ( ) )
146- guard let ent = try ? hmac. authenticate ( inputForHMAC. bytes) else { return nil }
147- guard ent. count == 64 else { return nil }
148- entropy = ent
137+ public func derive( path: String , derivePrivateKey: Bool = true ) -> HDNode ? {
138+ let components = path. components ( separatedBy: " / " )
139+ var currentNode : HDNode = self
140+ var firstComponent = 0
141+ if path. hasPrefix ( " m " ) {
142+ firstComponent = 1
149143 }
150- let I_L = entropy [ 0 ..< 32 ]
151- let I_R = entropy [ 32 ..< 64 ]
152- let cc = Data ( I_R)
153- let bn = BigUInt ( Data ( I_L) )
154- if bn > HDNode . curveOrder {
155- if index < UInt32 . max {
156- return self . derive ( index: index+ 1 , derivePrivateKey: false , hardened: hardened)
144+ for component in components [ firstComponent ..< components. count] {
145+ var hardened = false
146+ if component. hasSuffix ( " ' " ) {
147+ hardened = true
157148 }
158- return nil
159- }
160- guard let tempKey = bn. serialize ( ) . setLengthLeft ( 32 ) else { return nil }
161- guard SECP256K1 . verifyPrivateKey ( privateKey: tempKey) else { return nil }
162- guard let pubKeyCandidate = SECP256K1 . privateToPublic ( privateKey: tempKey, compressed: true ) else { return nil }
163- guard pubKeyCandidate. bytes. first == 0x02 || pubKeyCandidate. bytes. first == 0x03 else { return nil }
164- guard let newPublicKey = SECP256K1 . combineSerializedPublicKeys ( keys: [ self . publicKey, pubKeyCandidate] , outputCompressed: true ) else { return nil }
165- guard newPublicKey. bytes. first == 0x02 || newPublicKey. bytes. first == 0x03 else { return nil }
166- guard self . depth < UInt8 . max else { return nil }
167- let newNode = HDNode ( )
168- newNode. chaincode = cc
169- newNode. depth = self . depth + 1
170- newNode. publicKey = newPublicKey
171- newNode. childNumber = index
172- guard let fprint = try ? RIPEMD160 . hash ( message: self . publicKey. sha256 ( ) ) [ 0 ..< 4 ] else {
173- return nil
174- }
175- newNode. parentFingerprint = fprint
176- var newPath = String ( )
177- if newNode. isHardened {
178- newPath = ( self . path ?? " " ) + " / "
179- newPath += String ( newNode. index % HDNode. hardenedIndexPrefix) + " ' "
180- } else {
181- newPath = ( self . path ?? " " ) + " / " + String( newNode. index)
149+ guard let index = UInt32 ( component. trimmingCharacters ( in: CharacterSet ( charactersIn: " ' " ) ) ) else { return nil }
150+ guard let newNode = currentNode. derive ( index: index, derivePrivateKey: derivePrivateKey, hardened: hardened) else { return nil }
151+ currentNode = newNode
182152 }
183- newNode. path = newPath
184- return newNode
153+ return currentNode
185154 }
186- public func deriveWithPrivateKey( index: UInt32 , hardened: Bool = false ) -> HDNode ? {
187155
188- guard let privateKey = self . privateKey else {
156+ /// Derive public key when is itself private key.
157+ /// Derivation of private key when is itself extended public key is impossible and will return `nil`.
158+ private func derivePrivateKey( index: UInt32 , hardened: Bool ) -> HDNode ? {
159+ guard let privateKey = privateKey else {
160+ // derive private key when is itself extended public key (impossible)
189161 return nil
190162 }
191- var entropy : [ UInt8 ]
192- var trueIndex : UInt32
193- if index >= Self . maxIterationIndex || hardened {
194- trueIndex = index
195- if trueIndex < Self . maxIterationIndex {
196- trueIndex = trueIndex + Self. maxIterationIndex
197- }
198- let hmac : Authenticator = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
199- var inputForHMAC = Data ( )
200- inputForHMAC. append ( Data ( [ UInt8 ( 0x00 ) ] ) )
201- inputForHMAC. append ( privateKey)
202- inputForHMAC. append ( trueIndex. serialize32 ( ) )
203- guard let ent = try ? hmac. authenticate ( inputForHMAC. bytes) else { return nil }
204- guard ent. count == 64 else { return nil }
205- entropy = ent
206- } else {
207- trueIndex = index
208- let hmac : Authenticator = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
209- var inputForHMAC = Data ( )
210- inputForHMAC. append ( self . publicKey)
211- inputForHMAC. append ( trueIndex. serialize32 ( ) )
212- guard let ent = try ? hmac. authenticate ( inputForHMAC. bytes) else { return nil }
213- guard ent. count == 64 else { return nil }
214- entropy = ent
163+
164+ var trueIndex = index
165+ if trueIndex < ( UInt32 ( 1 ) << 31 ) && hardened {
166+ trueIndex += ( UInt32 ( 1 ) << 31 )
215167 }
168+
169+ guard let entropy = calculateEntropy ( index: trueIndex, privateKey: privateKey, hardened: hardened) else { return nil }
170+
216171 let I_L = entropy [ 0 ..< 32 ]
217172 let I_R = entropy [ 32 ..< 64 ]
218- let cc = Data ( I_R)
173+ let chainCode = Data ( I_R)
219174 let bn = BigUInt ( Data ( I_L) )
220175 if bn > HDNode . curveOrder {
221176 if trueIndex < UInt32 . max {
222- return self . derive ( index: index+ 1 , derivePrivateKey: true , hardened: hardened)
177+ return self . derive ( index: index + 1 , derivePrivateKey: true , hardened: hardened)
223178 }
224179 return nil
225180 }
226- let newPK = ( bn + BigUInt( self . privateKey! ) ) % HDNode. curveOrder
181+ let newPK = ( bn + BigUInt( privateKey) ) % HDNode. curveOrder
227182 if newPK == BigUInt ( 0 ) {
228183 if trueIndex < UInt32 . max {
229- return self . derive ( index: index+ 1 , derivePrivateKey: true , hardened: hardened)
184+ return self . derive ( index: index + 1 , derivePrivateKey: true , hardened: hardened)
230185 }
231186 return nil
232187 }
233- guard let privKeyCandidate = newPK. serialize ( ) . setLengthLeft ( 32 ) else { return nil }
234- guard SECP256K1 . verifyPrivateKey ( privateKey: privKeyCandidate) else { return nil }
235- guard let pubKeyCandidate = SECP256K1 . privateToPublic ( privateKey: privKeyCandidate, compressed: true ) else { return nil }
236- guard pubKeyCandidate. bytes [ 0 ] == 0x02 || pubKeyCandidate. bytes [ 0 ] == 0x03 else { return nil }
237- guard self . depth < UInt8 . max else { return nil }
188+
189+ guard
190+ let newPrivateKey = newPK. serialize ( ) . setLengthLeft ( 32 ) ,
191+ SECP256K1 . verifyPrivateKey ( privateKey: newPrivateKey) ,
192+ let newPublicKey = SECP256K1 . privateToPublic ( privateKey: newPrivateKey, compressed: true ) ,
193+ ( newPublicKey. bytes [ 0 ] == 0x02 || newPublicKey. bytes [ 0 ] == 0x03 ) ,
194+ self . depth < UInt8 . max
195+ else { return nil }
196+ return createNode ( chainCode: chainCode, depth: depth + 1 , publicKey: newPublicKey, privateKey: newPrivateKey, childNumber: trueIndex)
197+ }
198+
199+ /// Derive public key when is itself public key.
200+ /// No derivation of hardened public key from extended public key is allowed.
201+ private func derivePublicKey( index: UInt32 , hardened: Bool ) -> HDNode ? {
202+ if index >= ( UInt32 ( 1 ) << 31 ) || hardened {
203+ // no derivation of hardened public key from extended public key
204+ return nil
205+ }
206+
207+ guard let entropy = calculateEntropy ( index: index, hardened: hardened) else { return nil }
208+
209+ let I_L = entropy [ 0 ..< 32 ]
210+ let I_R = entropy [ 32 ..< 64 ]
211+ let chainCode = Data ( I_R)
212+ let bn = BigUInt ( Data ( I_L) )
213+ if bn > HDNode . curveOrder {
214+ if index < UInt32 . max {
215+ return self . derive ( index: index+ 1 , derivePrivateKey: false , hardened: hardened)
216+ }
217+ return nil
218+ }
219+
220+ guard
221+ let tempKey = bn. serialize ( ) . setLengthLeft ( 32 ) ,
222+ SECP256K1 . verifyPrivateKey ( privateKey: tempKey) ,
223+ let pubKeyCandidate = SECP256K1 . privateToPublic ( privateKey: tempKey, compressed: true ) ,
224+ ( pubKeyCandidate. bytes [ 0 ] == 0x02 || pubKeyCandidate. bytes [ 0 ] == 0x03 ) ,
225+ let newPublicKey = SECP256K1 . combineSerializedPublicKeys ( keys: [ self . publicKey, pubKeyCandidate] , outputCompressed: true ) ,
226+ ( newPublicKey. bytes [ 0 ] == 0x02 || newPublicKey. bytes [ 0 ] == 0x03 ) ,
227+ self . depth < UInt8 . max
228+ else { return nil }
229+
230+ return createNode ( chainCode: chainCode, depth: depth + 1 , publicKey: newPublicKey, childNumber: index)
231+ }
232+
233+ private func createNode( chainCode: Data , depth: UInt8 , publicKey: Data , privateKey: Data ? = nil , childNumber: UInt32 ) -> HDNode ? {
238234 let newNode = HDNode ( )
239- newNode. chaincode = cc
240- newNode. depth = self . depth + 1
241- newNode. publicKey = pubKeyCandidate
242- newNode. privateKey = privKeyCandidate
243- newNode. childNumber = trueIndex
244- guard let fprint = try ? RIPEMD160 . hash ( message: self . publicKey. sha256 ( ) ) [ 0 ..< 4 ] ,
245- let path = path
235+ newNode. chaincode = chainCode
236+ newNode. depth = depth
237+ newNode. publicKey = publicKey
238+ newNode. privateKey = privateKey
239+ newNode. childNumber = childNumber
240+ guard
241+ let fprint = try ? RIPEMD160 . hash ( message: self . publicKey. sha256 ( ) ) [ 0 ..< 4 ] ,
242+ let path = path
246243 else { return nil }
247244 newNode. parentFingerprint = fprint
248245 var newPath = String ( )
@@ -254,58 +251,60 @@ extension HDNode {
254251 }
255252 newNode. path = newPath
256253 return newNode
257-
258254 }
259255
260- public func derive( path: String , derivePrivateKey: Bool = true ) -> HDNode ? {
256+ private func calculateHMACInput( _ index: UInt32 , privateKey: Data ? = nil , hardened: Bool ) -> Data {
257+ var inputForHMAC = Data ( )
261258
262- let components = path. components ( separatedBy: " / " )
263- var currentNode : HDNode = self
264- var firstComponent = 0
265- if path. hasPrefix ( " m " ) {
266- firstComponent = 1
267- }
268- for component in components [ firstComponent ..< components. count] {
269- var hardened = false
270- if component. hasSuffix ( " ' " ) {
271- hardened = true
272- }
273- guard let index = UInt32 ( component. trimmingCharacters ( in: CharacterSet ( charactersIn: " ' " ) ) ) else { return nil }
274- guard let newNode = currentNode. derive ( index: index, derivePrivateKey: derivePrivateKey, hardened: hardened) else { return nil }
275- currentNode = newNode
259+ if let privateKey = privateKey, ( index >= ( UInt32 ( 1 ) << 31 ) || hardened) {
260+ inputForHMAC. append ( Data ( [ UInt8 ( 0x00 ) ] ) )
261+ inputForHMAC. append ( privateKey)
262+ } else {
263+ inputForHMAC. append ( self . publicKey)
276264 }
277- return currentNode
265+
266+ inputForHMAC. append ( index. serialize32 ( ) )
267+ return inputForHMAC
278268 }
279269
280- public func serializeToString( serializePublic: Bool = true ) -> String ? {
281- guard let data = self . serialize ( serializePublic: serializePublic) else { return nil }
282- let encoded = Base58 . base58FromBytes ( data. bytes)
283- return encoded
270+ /// Calculates entropy used for private or public key derivation.
271+ /// - Parameters:
272+ /// - index: index
273+ /// - privateKey: private key data or `nil` if entropy is calculated for a public key;
274+ /// - hardened: is hardened key
275+ /// - Returns: 64 bytes entropy or `nil`.
276+ private func calculateEntropy( index: UInt32 , privateKey: Data ? = nil , hardened: Bool ) -> [ UInt8 ] ? {
277+ let inputForHMAC = calculateHMACInput ( index, privateKey: privateKey, hardened: hardened)
278+ let hmac = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
279+ guard let entropy = try ? hmac. authenticate ( inputForHMAC. bytes) , entropy. count == 64 else { return nil }
280+ return entropy
284281 }
285282
286- public func serialize( serializePublic: Bool = true ) -> Data ? {
283+ public func serializeToString( serializePublic: Bool = true , version: HDversion = HDversion ( ) ) -> String ? {
284+ guard let data = self . serialize ( serializePublic: serializePublic, version: version) else { return nil }
285+ return Base58 . base58FromBytes ( data. bytes)
286+ }
287287
288+ public func serialize( serializePublic: Bool = true , version: HDversion = HDversion ( ) ) -> Data ? {
288289 var data = Data ( )
289-
290- guard serializePublic || privateKey != nil else {
291- return nil
292- }
293-
290+ /// Public or private key
291+ let keyData : Data
294292 if serializePublic {
295- data. append ( HDversion . publicPrefix)
293+ keyData = publicKey
294+ data. append ( version. publicPrefix)
296295 } else {
297- data. append ( HDversion . privatePrefix)
296+ guard let privateKey = privateKey else { return nil }
297+ keyData = privateKey
298+ data. append ( version. privatePrefix)
298299 }
299- data. append ( contentsOf: [ self . depth] )
300- data. append ( self . parentFingerprint)
301- data. append ( self . childNumber. serialize32 ( ) )
302- data. append ( self . chaincode)
303- if serializePublic {
304- data. append ( self . publicKey)
305- } else {
300+ data. append ( contentsOf: [ depth] )
301+ data. append ( parentFingerprint)
302+ data. append ( childNumber. serialize32 ( ) )
303+ data. append ( chaincode)
304+ if !serializePublic {
306305 data. append ( contentsOf: [ 0x00 ] )
307- data. append ( self . privateKey!)
308306 }
307+ data. append ( keyData)
309308 let hashedData = data. sha256 ( ) . sha256 ( )
310309 let checksum = hashedData [ 0 ..< 4 ]
311310 data. append ( checksum)
0 commit comments