Skip to content

Commit 9e59d57

Browse files
committed
Fix tests: introduce PathAddressStorage for BIP32 keystore
1 parent f2756ac commit 9e59d57

File tree

5 files changed

+83
-25
lines changed

5 files changed

+83
-25
lines changed

Sources/web3swift/KeystoreManager/BIP32Keystore.swift

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,18 @@ public class BIP32Keystore: AbstractKeystore {
1414

1515
public var addresses: [EthereumAddress]? {
1616
get {
17-
if self.paths.count == 0 {
17+
let addresses = self.addressStorage.addresses
18+
if addresses.count == 0 {
1819
return nil
1920
}
20-
var allAccounts = [EthereumAddress]()
21-
for (_, address) in paths {
22-
allAccounts.append(address)
23-
}
24-
return allAccounts
21+
return addresses
2522
}
2623
}
2724

2825
public var isHDKeystore: Bool = true
2926

3027
public func UNSAFE_getPrivateKeyData(password: String, account: EthereumAddress) throws -> Data {
31-
if let key = self.paths.keyForValue(value: account) {
28+
if let key = addressStorage.path(by: account) {
3229
guard let decryptedRootNode = try? self.getPrefixNodeData(password) else {throw AbstractKeystoreError.encryptionError("Failed to decrypt a keystore")}
3330
guard let rootNode = HDNode(decryptedRootNode) else {throw AbstractKeystoreError.encryptionError("Failed to deserialize a root node")}
3431
guard rootNode.depth == (self.rootPrefix.components(separatedBy: "/").count - 1) else {throw AbstractKeystoreError.encryptionError("Derivation depth mismatch")}
@@ -44,8 +41,10 @@ public class BIP32Keystore: AbstractKeystore {
4441
// --------------
4542

4643
public var keystoreParams: KeystoreParamsBIP32?
47-
public var paths: [String:EthereumAddress] = [String:EthereumAddress]()
4844
public var rootPrefix: String
45+
46+
private (set) var addressStorage: PathAddressStorage
47+
4948
public convenience init?(_ jsonString: String) {
5049
let lowercaseJSON = jsonString.lowercased()
5150
guard let jsonData = lowercaseJSON.data(using: .utf8) else {return nil}
@@ -57,9 +56,7 @@ public class BIP32Keystore: AbstractKeystore {
5756
if (keystorePars.version != 3) {return nil}
5857
if (keystorePars.crypto.version != nil && keystorePars.crypto.version != "1") {return nil}
5958
if (!keystorePars.isHDWallet) {return nil}
60-
for (p, ad) in keystorePars.pathToAddress {
61-
paths[p] = EthereumAddress(ad)
62-
}
59+
addressStorage = PathAddressStorage(pathAddressPairs: keystorePars.pathAddressPairs)
6360
if keystorePars.rootPath == nil {
6461
keystorePars.rootPath = HDNode.defaultPathPrefix
6562
}
@@ -74,6 +71,7 @@ public class BIP32Keystore: AbstractKeystore {
7471
}
7572

7673
public init? (seed: Data, password: String = "web3swift", prefixPath: String = HDNode.defaultPathMetamaskPrefix, aesMode: String = "aes-128-cbc") throws {
74+
addressStorage = PathAddressStorage()
7775
guard let rootNode = HDNode(seed: seed)?.derive(path: prefixPath, derivePrivateKey: true) else {return nil}
7876
self.rootPrefix = prefixPath
7977
try createNewAccount(parentNode: rootNode, password: password)
@@ -93,7 +91,7 @@ public class BIP32Keystore: AbstractKeystore {
9391

9492
func createNewAccount(parentNode: HDNode, password: String = "web3swift") throws {
9593
var newIndex = UInt32(0)
96-
for (p, _) in paths {
94+
for p in addressStorage.paths {
9795
guard let idx = UInt32(p.components(separatedBy: "/").last!) else {continue}
9896
if idx >= newIndex {
9997
newIndex = idx + 1
@@ -108,7 +106,7 @@ public class BIP32Keystore: AbstractKeystore {
108106
} else {
109107
newPath = prefixPath + "/" + String(newNode.index)
110108
}
111-
paths[newPath] = newAddress
109+
addressStorage.add(address: newAddress, for: newPath)
112110
}
113111

114112
public func createNewCustomChildAccount(password: String = "web3swift", path: String) throws {
@@ -143,7 +141,7 @@ public class BIP32Keystore: AbstractKeystore {
143141
} else {
144142
newPath = prefixPath + "/" + pathAppendix!
145143
}
146-
paths[newPath] = newAddress
144+
addressStorage.add(address: newAddress, for: newPath)
147145
guard let serializedRootNode = rootNode.serialize(serializePublic: false) else {throw AbstractKeystoreError.keyDerivationError}
148146
try encryptDataToStorage(password, data: serializedRootNode, aesMode: self.keystoreParams!.crypto.cipher)
149147
}
@@ -183,12 +181,8 @@ public class BIP32Keystore: AbstractKeystore {
183181
let kdfparams = KdfParamsV3(salt: saltData.toHexString(), dklen: dkLen, n: N, p: P, r: R, c: nil, prf: nil)
184182
let cipherparams = CipherParamsV3(iv: IV.toHexString())
185183
let crypto = CryptoParamsV3(ciphertext: encryptedKeyData.toHexString(), cipher: aesMode, cipherparams: cipherparams, kdf: "scrypt", kdfparams: kdfparams, mac: mac.toHexString(), version: nil)
186-
var pathToAddress = [String:String]()
187-
for (path, address) in paths {
188-
pathToAddress[path] = address.address
189-
}
190184
var keystorePars = KeystoreParamsBIP32(crypto: crypto, id: UUID().uuidString.lowercased(), version: 3)
191-
keystorePars.pathToAddress = pathToAddress
185+
keystorePars.pathAddressPairs = addressStorage.toPathAddressPairs()
192186
keystorePars.rootPath = self.rootPrefix
193187
keystoreParams = keystorePars
194188
}

Sources/web3swift/KeystoreManager/BIP32KeystoreJSONStructure.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,25 @@
66

77
import Foundation
88

9+
public struct PathAddressPair: Codable {
10+
let path: String
11+
let address: String
12+
}
13+
914
public struct KeystoreParamsBIP32: Decodable, Encodable {
1015
var crypto: CryptoParamsV3
1116
var id: String?
1217
var version: Int = 32
1318
var isHDWallet: Bool
14-
var pathToAddress: [String:String]
19+
var pathAddressPairs: [PathAddressPair]
1520
var rootPath: String?
1621

1722
public init(crypto cr: CryptoParamsV3, id i: String, version ver: Int, rootPath: String? = nil) {
1823
crypto = cr
1924
id = i
2025
version = ver
2126
isHDWallet = true
22-
pathToAddress = [String:String]()
27+
pathAddressPairs = [PathAddressPair]()
2328
self.rootPath = rootPath
2429
}
2530

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// PathAddressStorage.swift
3+
// web3swift
4+
//
5+
// Created by Andrew Podkovyrin on 08.08.2020.
6+
// Copyright © 2020 Matter Labs. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public struct PathAddressStorage {
12+
private(set) var addresses: [EthereumAddress]
13+
private(set) var paths: [String]
14+
15+
init() {
16+
addresses = []
17+
paths = []
18+
}
19+
20+
mutating func add(address: EthereumAddress, for path: String) {
21+
addresses.append(address)
22+
paths.append(path)
23+
}
24+
25+
func path(by address: EthereumAddress) -> String? {
26+
guard let index = addresses.firstIndex(of: address) else { return nil }
27+
return paths[index]
28+
}
29+
}
30+
31+
extension PathAddressStorage {
32+
init(pathAddressPairs: [PathAddressPair]) {
33+
var addresses = [EthereumAddress]()
34+
var paths = [String]()
35+
for pair in pathAddressPairs {
36+
guard let address = EthereumAddress(pair.address) else { continue }
37+
addresses.append(address)
38+
paths.append(pair.path)
39+
}
40+
41+
assert(addresses.count == paths.count)
42+
43+
self.addresses = addresses
44+
self.paths = paths
45+
}
46+
47+
func toPathAddressPairs() -> [PathAddressPair] {
48+
var pathAddressPairs = [PathAddressPair]()
49+
for (index, path) in paths.enumerated() {
50+
let address = addresses[index]
51+
let pair = PathAddressPair(path: path, address: address.address)
52+
pathAddressPairs.append(pair)
53+
}
54+
return pathAddressPairs
55+
}
56+
}

Tests/web3swiftTests/web3swift_keystores_Tests.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class web3swift_Keystores_tests: XCTestCase {
137137
let account = keystore!.addresses![1]
138138
let key = try! keystore!.UNSAFE_getPrivateKeyData(password: "", account: account)
139139
XCTAssertNotNil(key)
140-
print(keystore!.paths)
140+
print(keystore!.addressStorage.paths)
141141
}
142142

143143
func testByBIP32keystoreSaveAndDeriva() {
@@ -155,9 +155,8 @@ class web3swift_Keystores_tests: XCTestCase {
155155
print(keystore!.addresses![1].address)
156156
print(recreatedStore!.addresses![0].address)
157157
print(recreatedStore!.addresses![1].address)
158-
// This will fail. It wont fail if use scrypt from pod 'scrypt', '2.0', not from CryptoSwift
159-
XCTAssert(keystore?.addresses![0] == recreatedStore?.addresses![1])
160-
XCTAssert(keystore?.addresses![1] == recreatedStore?.addresses![0])
158+
XCTAssert(keystore?.addresses![0] == recreatedStore?.addresses![0])
159+
XCTAssert(keystore?.addresses![1] == recreatedStore?.addresses![1])
161160
}
162161

163162
// func testPBKDF2() {

web3swift.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
13C3392521B6C62400F33F5E /* secp256k1_ec_mult_static_context.h in Headers */ = {isa = PBXBuildFile; fileRef = 13C338F621B6C62400F33F5E /* secp256k1_ec_mult_static_context.h */; };
5454
13C3392621B6C62400F33F5E /* scratch.h in Headers */ = {isa = PBXBuildFile; fileRef = 13C338F721B6C62400F33F5E /* scratch.h */; };
5555
13C3392821B6C68900F33F5E /* secp256k1.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13C3388E21B6C2DD00F33F5E /* secp256k1.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
56+
2AC22E362525C2000072F037 /* PathAddressStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AC22E352525C2000072F037 /* PathAddressStorage.swift */; };
5657
3A7EA35E2280EA9A005120C2 /* Encodable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7EA35D2280EA9A005120C2 /* Encodable+Extensions.swift */; };
5758
3A7EA3602280EB27005120C2 /* Decodable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7EA35F2280EB27005120C2 /* Decodable+Extensions.swift */; };
5859
3AA8151C2276E42F00F5DB52 /* EventFiltering.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA815172276E42F00F5DB52 /* EventFiltering.swift */; };
@@ -249,6 +250,7 @@
249250
13C338F721B6C62400F33F5E /* scratch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scratch.h; sourceTree = "<group>"; };
250251
13CE02B021FC846800CE7148 /* RELEASE_GUIDE.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = RELEASE_GUIDE.md; sourceTree = "<group>"; };
251252
13CE02B121FC846900CE7148 /* BUILD_GUIDE.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = BUILD_GUIDE.md; sourceTree = "<group>"; };
253+
2AC22E352525C2000072F037 /* PathAddressStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PathAddressStorage.swift; sourceTree = "<group>"; };
252254
3A7EA35D2280EA9A005120C2 /* Encodable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Encodable+Extensions.swift"; sourceTree = "<group>"; };
253255
3A7EA35F2280EB27005120C2 /* Decodable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Decodable+Extensions.swift"; sourceTree = "<group>"; };
254256
3AA815172276E42F00F5DB52 /* EventFiltering.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventFiltering.swift; sourceTree = "<group>"; };
@@ -641,6 +643,7 @@
641643
3AA815302276E44100F5DB52 /* KeystoreManager */ = {
642644
isa = PBXGroup;
643645
children = (
646+
2AC22E352525C2000072F037 /* PathAddressStorage.swift */,
644647
3AA815312276E44100F5DB52 /* KeystoreManager.swift */,
645648
3AA815322276E44100F5DB52 /* IBAN.swift */,
646649
3AA815332276E44100F5DB52 /* BIP39.swift */,
@@ -1304,6 +1307,7 @@
13041307
3AA815D62276E44100F5DB52 /* Web3+ReadingTransaction.swift in Sources */,
13051308
3AA815AC2276E44100F5DB52 /* NameHash.swift in Sources */,
13061309
3AA8151C2276E42F00F5DB52 /* EventFiltering.swift in Sources */,
1310+
2AC22E362525C2000072F037 /* PathAddressStorage.swift in Sources */,
13071311
);
13081312
runOnlyForDeploymentPostprocessing = 0;
13091313
};

0 commit comments

Comments
 (0)