1+ // web3swift
12//
23// Created by Alex Vlasov.
34// Copyright © 2018 Alex Vlasov. All rights reserved.
@@ -23,12 +24,11 @@ extension UInt32 {
2324}
2425
2526public class HDNode {
26- public struct HDversion {
27- public var privatePrefix : Data = Data . fromHex ( " 0x0488ADE4 " ) !
28- public var publicPrefix : Data = Data . fromHex ( " 0x0488B21E " ) !
29- public init ( ) {
3027
31- }
28+ private struct HDversion {
29+ public static var privatePrefix : Data ? = Data . fromHex ( " 0x0488ADE4 " )
30+ public static var publicPrefix : Data ? = Data . fromHex ( " 0x0488B21E " )
31+
3232 }
3333 public var path : String ? = " m "
3434 public var privateKey : Data ? = nil
@@ -51,11 +51,6 @@ public class HDNode {
5151 }
5252 }
5353 }
54- public var hasPrivate : Bool {
55- get {
56- return privateKey != nil
57- }
58- }
5954
6055 init ( ) {
6156 publicKey = Data ( )
@@ -72,7 +67,7 @@ public class HDNode {
7267 guard data. count == 82 else { return nil }
7368 let header = data [ 0 ..< 4 ]
7469 var serializePrivate = false
75- if header == HDNode . HDversion ( ) . privatePrefix {
70+ if header == HDversion . privatePrefix {
7671 serializePrivate = true
7772 }
7873 depth = data [ 4 ..< 5 ] . bytes [ 0 ]
@@ -94,8 +89,10 @@ public class HDNode {
9489
9590 public init ? ( seed: Data ) {
9691 guard seed. count >= 16 else { return nil }
97- let hmacKey = " Bitcoin seed " . data ( using: . ascii) !
98- let hmac : Authenticator = 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+
9996 guard let entropy = try ? hmac. authenticate ( seed. bytes) else { return nil }
10097 guard entropy. count == 64 else { return nil }
10198 let I_L = entropy [ 0 ..< 32 ]
@@ -104,7 +101,7 @@ public class HDNode {
104101 let privKeyCandidate = Data ( I_L)
105102 guard SECP256K1 . verifyPrivateKey ( privateKey: privKeyCandidate) else { return nil }
106103 guard let pubKeyCandidate = SECP256K1 . privateToPublic ( privateKey: privKeyCandidate, compressed: true ) else { return nil }
107- guard pubKeyCandidate. bytes [ 0 ] == 0x02 || pubKeyCandidate. bytes [ 0 ] == 0x03 else { return nil }
104+ guard pubKeyCandidate. bytes. first == 0x02 || pubKeyCandidate. bytes. first == 0x03 else { return nil }
108105 publicKey = pubKeyCandidate
109106 privateKey = privKeyCandidate
110107 depth = 0x00
@@ -120,91 +117,99 @@ public class HDNode {
120117}
121118
122119extension HDNode {
123- public func derive ( index: UInt32 , derivePrivateKey: Bool , hardened: Bool = false ) -> HDNode ? {
124- if derivePrivateKey {
125- if self . hasPrivate { // derive private key when is itself extended private key
126- var entropy : Array < 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)
120+ public func derive( index: UInt32 , derivePrivateKey: Bool , hardened: Bool = false ) -> HDNode ? {
121+ derivePrivateKey ?
122+ deriveAlongPrivateKey ( index: index, derivePrivateKey: derivePrivateKey, hardened: hardened)
123+ :
124+ deriveWithoutPrivateKey ( index: index, derivePrivateKey: derivePrivateKey, hardened: hardened)
125+ }
126+ public func deriveAlongPrivateKey( index: UInt32 , derivePrivateKey: Bool , hardened: Bool = false ) -> HDNode ? {
127+ guard let privateKey = self . privateKey else {
128+ return nil
129+ } // derive private key when is itself extended private key
130+ var entropy : Array < UInt8 >
131+ var trueIndex : UInt32
132+ if index >= ( UInt32 ( 1 ) << 31 ) || hardened {
133+ trueIndex = index
134+ if trueIndex < ( UInt32 ( 1 ) << 31 ) {
135+ trueIndex = trueIndex + ( UInt32 ( 1 ) << 31 )
194136 }
195- } else { // deriving only the public key
196- var entropy : Array < 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
137+ let hmac : Authenticator = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
138+ var inputForHMAC = Data ( )
139+ inputForHMAC. append ( Data ( [ UInt8 ( 0x00 ) ] ) )
140+ inputForHMAC. append ( privateKey)
141+ inputForHMAC. append ( trueIndex. serialize32 ( ) )
142+ guard let ent = try ? hmac. authenticate ( inputForHMAC. bytes) else { return nil }
143+ guard ent. count == 64 else { return nil }
144+ entropy = ent
145+ } else {
146+ trueIndex = index
147+ let hmac : Authenticator = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
148+ var inputForHMAC = Data ( )
149+ inputForHMAC. append ( self . publicKey)
150+ inputForHMAC. append ( trueIndex. serialize32 ( ) )
151+ guard let ent = try ? hmac. authenticate ( inputForHMAC. bytes) else { return nil }
152+ guard ent. count == 64 else { return nil }
153+ entropy = ent
154+ }
155+ let I_L = entropy [ 0 ..< 32 ]
156+ let I_R = entropy [ 32 ..< 64 ]
157+ let cc = Data ( I_R)
158+ let bn = BigUInt ( Data ( I_L) )
159+ if bn > HDNode . curveOrder {
160+ if trueIndex < UInt32 . max {
161+ return self . derive ( index: index+ 1 , derivePrivateKey: derivePrivateKey, hardened: hardened)
207162 }
163+ return nil
164+ }
165+ let newPK = ( bn + BigUInt( privateKey) ) % HDNode. curveOrder
166+ if newPK == BigUInt ( 0 ) {
167+ if trueIndex < UInt32 . max {
168+ return self . derive ( index: index+ 1 , derivePrivateKey: derivePrivateKey, hardened: hardened)
169+ }
170+ return nil
171+ }
172+ guard let privKeyCandidate = newPK. serialize ( ) . setLengthLeft ( 32 ) else { return nil }
173+ guard SECP256K1 . verifyPrivateKey ( privateKey: privKeyCandidate) else { return nil }
174+ guard let pubKeyCandidate = SECP256K1 . privateToPublic ( privateKey: privKeyCandidate, compressed: true ) else { return nil }
175+ guard pubKeyCandidate. bytes. first == 0x02 || pubKeyCandidate. bytes. first == 0x03 else { return nil }
176+ guard self . depth < UInt8 . max else { return nil }
177+ let newNode = HDNode ( )
178+ newNode. chaincode = cc
179+ newNode. depth = self . depth + 1
180+ newNode. publicKey = pubKeyCandidate
181+ newNode. privateKey = privKeyCandidate
182+ newNode. childNumber = trueIndex
183+ guard let fprint = try ? RIPEMD160 . hash ( message: self . publicKey. sha256 ( ) ) [ 0 ..< 4 ] else {
184+ return nil
185+ }
186+ newNode. parentFingerprint = fprint
187+ var newPath = String ( )
188+ if newNode. isHardened {
189+ newPath = ( self . path ?? " " ) + " / "
190+ newPath += String ( newNode. index % HDNode. hardenedIndexPrefix) + " ' "
191+ } else {
192+ newPath = ( self . path ?? " " ) + " / " + String( newNode. index)
193+ }
194+ newNode. path = newPath
195+ return newNode
196+ }
197+
198+ public func deriveWithoutPrivateKey( index: UInt32 , derivePrivateKey: Bool , hardened: Bool = false ) -> HDNode ? {
199+ // deriving only the public key
200+ var entropy : Array < UInt8 > // derive public key when is itself public key
201+ guard !hardened && index < ( UInt32 ( 1 ) << 31 ) else {
202+ return nil // no derivation of hardened public key from extended public key
203+ }
204+
205+ let hmac : Authenticator = HMAC ( key: self . chaincode. bytes, variant: . sha2( . sha512) )
206+ var inputForHMAC = Data ( )
207+ inputForHMAC. append ( self . publicKey)
208+ inputForHMAC. append ( index. serialize32 ( ) )
209+ guard let ent = try ? hmac. authenticate ( inputForHMAC. bytes) else { return nil }
210+ guard ent. count == 64 else { return nil }
211+ entropy = ent
212+
208213 let I_L = entropy [ 0 ..< 32 ]
209214 let I_R = entropy [ 32 ..< 64 ]
210215 let cc = Data ( I_R)
@@ -218,9 +223,9 @@ extension HDNode {
218223 guard let tempKey = bn. serialize ( ) . setLengthLeft ( 32 ) else { return nil }
219224 guard SECP256K1 . verifyPrivateKey ( privateKey: tempKey) else { return nil }
220225 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 }
226+ guard pubKeyCandidate. bytes. first == 0x02 || pubKeyCandidate. bytes. first == 0x03 else { return nil }
222227 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 }
228+ guard newPublicKey. bytes. first == 0x02 || newPublicKey. bytes. first == 0x03 else { return nil }
224229 guard self . depth < UInt8 . max else { return nil }
225230 let newNode = HDNode ( )
226231 newNode. chaincode = cc
@@ -233,17 +238,17 @@ extension HDNode {
233238 newNode. parentFingerprint = fprint
234239 var newPath = String ( )
235240 if newNode. isHardened {
236- newPath = self . path! + " / "
241+ newPath = ( self . path ?? " " ) + " / "
237242 newPath += String ( newNode. index % HDNode. hardenedIndexPrefix) + " ' "
238243 } else {
239- newPath = self . path! + " / " + String( newNode. index)
244+ newPath = ( self . path ?? " " ) + " / " + String( newNode. index)
240245 }
241246 newNode. path = newPath
242247 return newNode
243- }
244248 }
245249
246- public func derive ( path: String , derivePrivateKey: Bool = true ) -> HDNode ? {
250+ public func derive( path: String , derivePrivateKey: Bool = true ) -> HDNode ? {
251+
247252 let components = path. components ( separatedBy: " / " )
248253 var currentNode : HDNode = self
249254 var firstComponent = 0
@@ -262,19 +267,24 @@ extension HDNode {
262267 return currentNode
263268 }
264269
265- public func serializeToString( serializePublic: Bool = true , version : HDversion = HDversion ( ) ) -> String ? {
266- guard let data = self . serialize ( serializePublic: serializePublic, version : version ) else { return nil }
270+ public func serializeToString( serializePublic: Bool = true ) -> String ? {
271+ guard let data = self . serialize ( serializePublic: serializePublic) else { return nil }
267272 let encoded = Base58 . base58FromBytes ( data. bytes)
268273 return encoded
269274 }
270275
271- public func serialize( serializePublic: Bool = true , version: HDversion = HDversion ( ) ) -> Data ? {
276+ public func serialize( serializePublic: Bool = true ) -> Data ? {
277+
272278 var data = Data ( )
273- if ( !serializePublic && !self . hasPrivate) { return nil }
279+
280+ guard serializePublic || privateKey != nil else {
281+ return nil
282+ }
283+
274284 if serializePublic {
275- data. append ( version . publicPrefix)
285+ data. append ( HDversion . publicPrefix! )
276286 } else {
277- data. append ( version . privatePrefix)
287+ data. append ( HDversion . privatePrefix! )
278288 }
279289 data. append ( contentsOf: [ self . depth] )
280290 data. append ( self . parentFingerprint)
0 commit comments