1
+ // web3swift
1
2
//
2
3
// Created by Alex Vlasov.
3
4
// Copyright © 2018 Alex Vlasov. All rights reserved.
@@ -23,12 +24,11 @@ extension UInt32 {
23
24
}
24
25
25
26
public 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 ( ) {
30
27
31
- }
28
+ private struct HDversion {
29
+ public static var privatePrefix : Data ? = Data . fromHex ( " 0x0488ADE4 " )
30
+ public static var publicPrefix : Data ? = Data . fromHex ( " 0x0488B21E " )
31
+
32
32
}
33
33
public var path : String ? = " m "
34
34
public var privateKey : Data ?
@@ -51,11 +51,6 @@ public class HDNode {
51
51
}
52
52
}
53
53
}
54
- public var hasPrivate : Bool {
55
- get {
56
- return privateKey != nil
57
- }
58
- }
59
54
60
55
init ( ) {
61
56
publicKey = Data ( )
@@ -72,7 +67,7 @@ public class HDNode {
72
67
guard data. count == 82 else { return nil }
73
68
let header = data [ 0 ..< 4 ]
74
69
var serializePrivate = false
75
- if header == HDNode . HDversion ( ) . privatePrefix {
70
+ if header == HDversion . privatePrefix {
76
71
serializePrivate = true
77
72
}
78
73
depth = data [ 4 ..< 5 ] . bytes [ 0 ]
@@ -94,8 +89,10 @@ public class HDNode {
94
89
95
90
public init ? ( seed: Data ) {
96
91
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
+
99
96
guard let entropy = try ? hmac. authenticate ( seed. bytes) else { return nil }
100
97
guard entropy. count == 64 else { return nil }
101
98
let I_L = entropy [ 0 ..< 32 ]
@@ -104,7 +101,7 @@ public class HDNode {
104
101
let privKeyCandidate = Data ( I_L)
105
102
guard SECP256K1 . verifyPrivateKey ( privateKey: privKeyCandidate) else { return nil }
106
103
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 }
108
105
publicKey = pubKeyCandidate
109
106
privateKey = privKeyCandidate
110
107
depth = 0x00
@@ -120,91 +117,99 @@ public class HDNode {
120
117
}
121
118
122
119
extension 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 : [ 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 )
194
136
}
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
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)
207
162
}
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
+
208
213
let I_L = entropy [ 0 ..< 32 ]
209
214
let I_R = entropy [ 32 ..< 64 ]
210
215
let cc = Data ( I_R)
@@ -218,9 +223,9 @@ extension HDNode {
218
223
guard let tempKey = bn. serialize ( ) . setLengthLeft ( 32 ) else { return nil }
219
224
guard SECP256K1 . verifyPrivateKey ( privateKey: tempKey) else { return nil }
220
225
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 }
222
227
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 }
224
229
guard self . depth < UInt8 . max else { return nil }
225
230
let newNode = HDNode ( )
226
231
newNode. chaincode = cc
@@ -233,17 +238,17 @@ extension HDNode {
233
238
newNode. parentFingerprint = fprint
234
239
var newPath = String ( )
235
240
if newNode. isHardened {
236
- newPath = self . path! + " / "
241
+ newPath = ( self . path ?? " " ) + " / "
237
242
newPath += String ( newNode. index % HDNode. hardenedIndexPrefix) + " ' "
238
243
} else {
239
- newPath = self . path! + " / " + String( newNode. index)
244
+ newPath = ( self . path ?? " " ) + " / " + String( newNode. index)
240
245
}
241
246
newNode. path = newPath
242
247
return newNode
243
- }
244
248
}
245
249
246
- public func derive ( path: String , derivePrivateKey: Bool = true ) -> HDNode ? {
250
+ public func derive( path: String , derivePrivateKey: Bool = true ) -> HDNode ? {
251
+
247
252
let components = path. components ( separatedBy: " / " )
248
253
var currentNode : HDNode = self
249
254
var firstComponent = 0
@@ -262,19 +267,24 @@ extension HDNode {
262
267
return currentNode
263
268
}
264
269
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 }
267
272
let encoded = Base58 . base58FromBytes ( data. bytes)
268
273
return encoded
269
274
}
270
275
271
- public func serialize( serializePublic: Bool = true , version: HDversion = HDversion ( ) ) -> Data ? {
276
+ public func serialize( serializePublic: Bool = true ) -> Data ? {
277
+
272
278
var data = Data ( )
273
- if !serializePublic && !self . hasPrivate { return nil }
279
+
280
+ guard serializePublic || privateKey != nil else {
281
+ return nil
282
+ }
283
+
274
284
if serializePublic {
275
- data. append ( version . publicPrefix)
285
+ data. append ( HDversion . publicPrefix! )
276
286
} else {
277
- data. append ( version . privatePrefix)
287
+ data. append ( HDversion . privatePrefix! )
278
288
}
279
289
data. append ( contentsOf: [ self . depth] )
280
290
data. append ( self . parentFingerprint)
0 commit comments