diff --git a/Cartfile b/Cartfile index 1751663..7176f40 100644 --- a/Cartfile +++ b/Cartfile @@ -2,3 +2,4 @@ github "mxcl/PromiseKit" ~> 6.0 github "attaswift/BigInt" ~> 3.1 github "krzyzanowskim/CryptoSwift" github "Boilertalk/secp256k1.swift" +github "v57/BlueCryptor" ~> 1.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index b2d65b4..0738bbf 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,5 +1,6 @@ github "Boilertalk/secp256k1.swift" "0.1.4" github "attaswift/BigInt" "v3.1.0" github "attaswift/SipHash" "v1.2.2" -github "krzyzanowskim/CryptoSwift" "0.13.0" -github "mxcl/PromiseKit" "6.5.2" +github "krzyzanowskim/CryptoSwift" "0.13.1" +github "mxcl/PromiseKit" "6.6.1" +github "v57/BlueCryptor" "1.0.22" diff --git a/Package.swift b/Package.swift index 71fefc6..1af2d35 100644 --- a/Package.swift +++ b/Package.swift @@ -14,6 +14,7 @@ let package = Package( .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "0.12.0"), .package(url: "https://github.com/Boilertalk/secp256k1.swift.git", from: "0.1.1"), .package(url: "https://github.com/mxcl/PromiseKit.git", from: "6.4.0"), + .package(url: "https://github.com/v57/BlueCryptor.git", from: "1.0.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/README.md b/README.md index 4ce4bc3..3a4a8fb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# We just released web3swift 2.0 [check it out](https://github.com/BANKEX/web3swift/releases/tag/2.0.0) -### also check our [Discord Channel](https://discord.gg/3ETv2ST) + +### You can ask for help in our [Discord Channel](https://discord.gg/3ETv2ST)

Support @@ -57,7 +57,7 @@ Don't forget to set the iOS version in a Podfile, otherwise you get an error if Add this to the dependency section of your `Package.swift` manifest: ```Swift - .package(url: "https://github.com/BANKEX/web3swift.git", from: "2.0.0") + .package(url: "https://github.com/BANKEX/web3swift.git", from: "2.1.0") ``` - **CocoaPods:** Put this in your `Podfile`: @@ -69,7 +69,7 @@ Don't forget to set the iOS version in a Podfile, otherwise you get an error if - **Carthage:** Put this in your `Cartfile`: ``` - github "BANKEX/web3swift" ~> 2.0 + github "BANKEX/web3swift" ~> 2.1 ``` diff --git a/Sources/ABIv2/ABIv2Decoding.swift b/Sources/ABIv2/ABIv2Decoding.swift index bb25fe8..228cf5d 100644 --- a/Sources/ABIv2/ABIv2Decoding.swift +++ b/Sources/ABIv2/ABIv2Decoding.swift @@ -31,7 +31,7 @@ public struct ABIv2Decoder { /// - data: Data to decode /// - Returns: Array of decoded types public static func decode(types: [ABIv2.Element.ParameterType], data: Data) -> [AnyObject]? { -// print("Full data: \n" + data.toHexString()) +// print("Full data: \n" + data.hex) var toReturn = [AnyObject]() var consumed: UInt64 = 0 for i in 0 ..< types.count { @@ -59,7 +59,7 @@ public struct ABIv2Decoder { } switch type { case let .uint(bits): -// print("Uint256 element itself: \n" + elementItself.toHexString()) +// print("Uint256 element itself: \n" + elementItself.hex) guard elementItself.count >= 32 else { break } let mod = BigUInt(1) << bits let dataSlice = elementItself[0 ..< 32] @@ -67,7 +67,7 @@ public struct ABIv2Decoder { // print("Uint256 element is: \n" + String(v)) return (v as AnyObject, type.memoryUsage) case let .int(bits): -// print("Int256 element itself: \n" + elementItself.toHexString()) +// print("Int256 element itself: \n" + elementItself.hex) guard elementItself.count >= 32 else { break } let mod = BigInt(1) << bits let dataSlice = elementItself[0 ..< 32] @@ -75,14 +75,14 @@ public struct ABIv2Decoder { // print("Int256 element is: \n" + String(v)) return (v as AnyObject, type.memoryUsage) case .address: -// print("Address element itself: \n" + elementItself.toHexString()) +// print("Address element itself: \n" + elementItself.hex) guard elementItself.count >= 32 else { break } let dataSlice = elementItself[12 ..< 32] let address = Address(dataSlice) // print("Address element is: \n" + String(address.address)) return (address as AnyObject, type.memoryUsage) case .bool: -// print("Bool element itself: \n" + elementItself.toHexString()) +// print("Bool element itself: \n" + elementItself.hex) guard elementItself.count >= 32 else { break } let dataSlice = elementItself[0 ..< 32] let v = BigUInt(dataSlice) @@ -93,13 +93,13 @@ public struct ABIv2Decoder { return (false as AnyObject, type.memoryUsage) } case let .bytes(length): -// print("Bytes32 element itself: \n" + elementItself.toHexString()) +// print("Bytes32 element itself: \n" + elementItself.hex) guard elementItself.count >= 32 else { break } let dataSlice = elementItself[0 ..< length] -// print("Bytes32 element is: \n" + String(dataSlice.toHexString())) +// print("Bytes32 element is: \n" + String(dataSlice.hex)) return (dataSlice as AnyObject, type.memoryUsage) case .string: -// print("String element itself: \n" + elementItself.toHexString()) +// print("String element itself: \n" + elementItself.hex) guard elementItself.count >= 32 else { break } var dataSlice = elementItself[0 ..< 32] let length = UInt64(BigUInt(dataSlice)) @@ -109,18 +109,18 @@ public struct ABIv2Decoder { // print("String element is: \n" + String(string)) return (string as AnyObject, type.memoryUsage) case .dynamicBytes: -// print("Bytes element itself: \n" + elementItself.toHexString()) +// print("Bytes element itself: \n" + elementItself.hex) guard elementItself.count >= 32 else { break } var dataSlice = elementItself[0 ..< 32] let length = UInt64(BigUInt(dataSlice)) guard elementItself.count >= 32 + length else { break } dataSlice = elementItself[32 ..< 32 + length] -// print("Bytes element is: \n" + String(dataSlice.toHexString())) +// print("Bytes element is: \n" + String(dataSlice.hex)) return (dataSlice as AnyObject, type.memoryUsage) case let .array(type: subType, length: length): switch type.arraySize { case .dynamicSize: -// print("Dynamic array element itself: \n" + elementItself.toHexString()) +// print("Dynamic array element itself: \n" + elementItself.hex) if subType.isStatic { // uint[] like, expect length and elements guard elementItself.count >= 32 else { break } @@ -146,7 +146,7 @@ public struct ABIv2Decoder { dataSlice = Data(elementItself[32 ..< elementItself.count]) var subpointer: UInt64 = 0 var toReturn = [AnyObject]() -// print("Dynamic array sub element itself: \n" + dataSlice.toHexString()) +// print("Dynamic array sub element itself: \n" + dataSlice.hex) for _ in 0 ..< length { let (v, c) = decodeSignleType(type: subType, data: dataSlice, pointer: subpointer) guard let valueUnwrapped = v, let consumedUnwrapped = c else { break } @@ -156,7 +156,7 @@ public struct ABIv2Decoder { return (toReturn as AnyObject, nextElementPointer) } case let .staticSize(staticLength): -// print("Static array element itself: \n" + elementItself.toHexString()) +// print("Static array element itself: \n" + elementItself.hex) guard length == staticLength else { break } var toReturn = [AnyObject]() var consumed: UInt64 = 0 @@ -175,7 +175,7 @@ public struct ABIv2Decoder { break } case let .tuple(types: subTypes): -// print("Tuple element itself: \n" + elementItself.toHexString()) +// print("Tuple element itself: \n" + elementItself.hex) var toReturn = [AnyObject]() var consumed: UInt64 = 0 for i in 0 ..< subTypes.count { @@ -191,23 +191,23 @@ public struct ABIv2Decoder { return (toReturn as AnyObject, nextElementPointer) } case .function: -// print("Function element itself: \n" + elementItself.toHexString()) +// print("Function element itself: \n" + elementItself.hex) guard elementItself.count >= 32 else { break } let dataSlice = elementItself[8 ..< 32] -// print("Function element is: \n" + String(dataSlice.toHexString())) +// print("Function element is: \n" + String(dataSlice.hex)) return (dataSlice as AnyObject, type.memoryUsage) } return (nil, nil) } fileprivate static func followTheData(type: ABIv2.Element.ParameterType, data: Data, pointer: UInt64 = 0) -> (elementEncoding: Data?, nextElementPointer: UInt64?) { -// print("Follow the data: \n" + data.toHexString()) +// print("Follow the data: \n" + data.hex) // print("At pointer: \n" + String(pointer)) if type.isStatic { guard data.count >= pointer + type.memoryUsage else { return (nil, nil) } let elementItself = data[pointer ..< pointer + type.memoryUsage] let nextElement = pointer + type.memoryUsage -// print("Got element itself: \n" + elementItself.toHexString()) +// print("Got element itself: \n" + elementItself.hex) // print("Next element pointer: \n" + String(nextElement)) return (Data(elementItself), nextElement) } else { @@ -230,7 +230,7 @@ public struct ABIv2Decoder { let elementPointer = UInt64(bn) let elementItself = data[elementPointer ..< UInt64(data.count)] let nextElement = pointer + type.memoryUsage -// print("Got element itself: \n" + elementItself.toHexString()) +// print("Got element itself: \n" + elementItself.hex) // print("Next element pointer: \n" + String(nextElement)) return (Data(elementItself), nextElement) } diff --git a/Sources/ABIv2/ABIv2Encoding.swift b/Sources/ABIv2/ABIv2Encoding.swift index be62181..f0c2713 100644 --- a/Sources/ABIv2/ABIv2Encoding.swift +++ b/Sources/ABIv2/ABIv2Encoding.swift @@ -259,7 +259,7 @@ public struct ABIv2Encoder { toReturn.append(encoding) } let total = lengthEncoding + toReturn -// print("Dynamic array of static types encoding :\n" + String(total.toHexString())) +// print("Dynamic array of static types encoding :\n" + String(total.hex)) return total } else { // create new context @@ -292,7 +292,7 @@ public struct ABIv2Encoder { } } let total = lengthEncoding + headsConcatenated + tailsConcatenated -// print("Dynamic array of dynamic types encoding :\n" + String(total.toHexString())) +// print("Dynamic array of dynamic types encoding :\n" + String(total.hex)) return total } case let .staticSize(staticLength): @@ -307,7 +307,7 @@ public struct ABIv2Encoder { guard let encoding = enc else { break } toReturn.append(encoding) } -// print("Static array of static types encoding :\n" + String(toReturn.toHexString())) +// print("Static array of static types encoding :\n" + String(toReturn.hex)) let total = toReturn return total } else { @@ -335,7 +335,7 @@ public struct ABIv2Encoder { tailsPointer = tailsPointer + BigUInt(tail.count) } let total = headsConcatenated + tailsConcatenated -// print("Static array of dynamic types encoding :\n" + String(total.toHexString())) +// print("Static array of dynamic types encoding :\n" + String(total.hex)) return total } case .notArray: diff --git a/Sources/ABIv2/ABIv2ParameterTypes.swift b/Sources/ABIv2/ABIv2ParameterTypes.swift index d988d1d..7eaf160 100644 --- a/Sources/ABIv2/ABIv2ParameterTypes.swift +++ b/Sources/ABIv2/ABIv2ParameterTypes.swift @@ -179,12 +179,12 @@ extension ABIv2.Element.Function { /// Function hash in hex public var methodString: String { - return String(signature.sha3(.keccak256).prefix(8)) + return signature.keccak256().hex } /// Function hash public var methodEncoding: Data { - return signature.data(using: .ascii)!.sha3(.keccak256)[0..<4] + return signature.data(using: .ascii)!.keccak256()[0..<4] } } @@ -198,7 +198,7 @@ extension ABIv2.Element.Event { /// Event hash public var topic: Data { - return signature.data(using: .ascii)!.sha3(.keccak256) + return signature.data(using: .ascii)!.keccak256() } } diff --git a/Sources/Contract/ComparisonExtensions.swift b/Sources/Contract/ComparisonExtensions.swift index f050b39..d016fda 100644 --- a/Sources/Contract/ComparisonExtensions.swift +++ b/Sources/Contract/ComparisonExtensions.swift @@ -39,9 +39,9 @@ extension String: EventFilterComparable { public func isEqualTo(_ other: AnyObject) -> Bool { switch other { case let oth as String: - return data.sha3(.keccak256) == oth.data.sha3(.keccak256) + return data.keccak256() == oth.data.keccak256() case let oth as Data: - return data.sha3(.keccak256) == oth.sha3(.keccak256) + return data.keccak256() == oth.keccak256() default: return false } @@ -56,13 +56,13 @@ extension Data: EventFilterComparable { if self == data { return true } - let hash = data.sha3(.keccak256) + let hash = data.keccak256() return self == hash case let oth as Data: if self == oth { return true } - let hash = oth.sha3(.keccak256) + let hash = oth.keccak256() return self == hash default: return false diff --git a/Sources/Contract/EthereumFilterEncodingExtensions.swift b/Sources/Contract/EthereumFilterEncodingExtensions.swift index 5dd0316..560fff7 100644 --- a/Sources/Contract/EthereumFilterEncodingExtensions.swift +++ b/Sources/Contract/EthereumFilterEncodingExtensions.swift @@ -11,32 +11,32 @@ import Foundation extension BigUInt: EventFilterEncodable { public func eventFilterEncoded() -> String? { - return abiEncode(bits: 256)?.toHexString().withHex + return abiEncode(bits: 256)?.hex.withHex } } extension BigInt: EventFilterEncodable { public func eventFilterEncoded() -> String? { - return abiEncode(bits: 256)?.toHexString().withHex + return abiEncode(bits: 256)?.hex.withHex } } extension Data: EventFilterEncodable { public func eventFilterEncoded() -> String? { guard let padded = self.setLengthLeft(32) else { return nil } - return padded.toHexString().withHex + return padded.hex.withHex } } extension Address: EventFilterEncodable { public func eventFilterEncoded() -> String? { guard let padded = self.addressData.setLengthLeft(32) else { return nil } - return padded.toHexString().withHex + return padded.hex.withHex } } extension String: EventFilterEncodable { public func eventFilterEncoded() -> String? { - return data.sha3(.keccak256).toHexString().withHex + return data.keccak256().hex.withHex } } diff --git a/Sources/Contract/EventFiltering.swift b/Sources/Contract/EventFiltering.swift index 934cb8f..0aa7f54 100644 --- a/Sources/Contract/EventFiltering.swift +++ b/Sources/Contract/EventFiltering.swift @@ -68,7 +68,7 @@ internal func encodeTopicToGetLogs(contract: ContractV2, eventName: String?, fil } var topics = [[String?]?]() if eventTopic != nil { - topics.append([eventTopic!.toHexString().withHex]) + topics.append([eventTopic!.hex.withHex]) } else { topics.append(nil as [String?]?) } diff --git a/Sources/Convenience/CryptoExtensions.swift b/Sources/Convenience/CryptoExtensions.swift index 7e4da1a..45af02a 100644 --- a/Sources/Convenience/CryptoExtensions.swift +++ b/Sources/Convenience/CryptoExtensions.swift @@ -6,7 +6,7 @@ // Copyright © 2017 Alexander Vlasov. All rights reserved. // -import CryptoSwift +import Cryptor import Foundation /** @@ -98,8 +98,11 @@ private class OldScrypt { V.deallocate() } + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ - let barray = try PKCS5.PBKDF2(password: password, salt: [UInt8](salt), iterations: 1, keyLength: p * 128 * r, variant: .sha256).calculate() + + let pw = String(data: Data(password), encoding: .utf8)! + let barray = try PBKDF.deriveKey(fromPassword: pw, salt: salt, prf: .sha256, rounds: 1, derivedKeyLength: UInt(p * 128 * r)) barray.withUnsafeBytes { p in B.copyMemory(from: p.baseAddress!, byteCount: barray.count) @@ -115,7 +118,8 @@ private class OldScrypt { let pointer = B.assumingMemoryBound(to: UInt8.self) let bufferPointer = UnsafeBufferPointer(start: pointer, count: p * 128 * r) let block = [UInt8](bufferPointer) - return try PKCS5.PBKDF2(password: password, salt: block, iterations: 1, keyLength: dkLen, variant: .sha256).calculate() + return try PBKDF.deriveKey(fromPassword: pw, salt: block, prf: .sha256, rounds: 1, derivedKeyLength: UInt(dkLen)) +// return try PKCS5.PBKDF2(password: password, salt: block, iterations: 1, keyLength: dkLen, variant: .sha256).calculate() } /// Computes `B = SMix_r(B, N)`. diff --git a/Sources/Convenience/Data+Extension.swift b/Sources/Convenience/Data+Extension.swift index a00295a..b7f5c25 100644 --- a/Sources/Convenience/Data+Extension.swift +++ b/Sources/Convenience/Data+Extension.swift @@ -7,6 +7,9 @@ // import Foundation +import CryptoSwift +import Cryptor + /// Data errors public enum DataError: Error { @@ -21,6 +24,12 @@ public enum DataError: Error { } } +extension Data { + func sha256() -> Data { + return digest(using: .sha256) + } +} + public extension Data { /// Inits with array of type init(fromArray values: [T]) { diff --git a/Sources/Convenience/LibSecp256k1Extension.swift b/Sources/Convenience/LibSecp256k1Extension.swift index 96f53af..2c66dae 100644 --- a/Sources/Convenience/LibSecp256k1Extension.swift +++ b/Sources/Convenience/LibSecp256k1Extension.swift @@ -266,7 +266,6 @@ struct SECP256K1 { https://github.com/MaiaVictor/eth-lib/blob/d959c54faa1e1ac8d474028ed1568c5dce27cc7a/src/account.js#L60 */ v = v < 2 ? v : 1 - (v % 2) - let result = serializedSignature.withUnsafeBytes { (serPtr: UnsafePointer) -> Int32 in withUnsafeMutablePointer(to: &recoverableSignature, { (signaturePointer: UnsafeMutablePointer) in secp256k1_ecdsa_recoverable_signature_parse_compact(context!, signaturePointer, serPtr, v) @@ -324,7 +323,7 @@ struct SECP256K1 { static func recoverSender(hash: Data, signature: Data) throws -> Address { let pubKey = try SECP256K1.recoverPublicKey(hash: hash, signature: signature, compressed: false) try pubKey.checkPublicKeySize() - let addressData = Data(pubKey.sha3(.keccak256)[12 ..< 32]) + let addressData = Data(pubKey.keccak256()[12 ..< 32]) return Address(addressData) } diff --git a/Sources/Encryption/AES.swift b/Sources/Encryption/AES.swift new file mode 100644 index 0000000..dfc0397 --- /dev/null +++ b/Sources/Encryption/AES.swift @@ -0,0 +1,198 @@ +// +// AES.swift +// web3swift +// +// Created by Dmitry on 30/11/2018. +// + +import Foundation +import CommonCrypto + +//extension Data { +// var bytes: Array { +// return Array(self) +// } +//} + +enum AesMode { + case ctr + case cbc + var cc: CCMode { + switch self { + case .cbc: + return CCMode(kCCModeCBC) + case .ctr: + return CCMode(kCCModeCTR) + } + } + enum Error: Swift.Error { + case invalidType(String) + } + init(_ string: String) throws { + switch string { + case "aes-128-ctr": self = .ctr + case "aes-128-cbc": self = .cbc + default: throw Error.invalidType(string) + } + } + func blockMode(_ iv: Data) -> BlockMode { + switch self { + case .ctr: return CTR(iv: iv.bytes) + case .cbc: return CBC(iv: iv.bytes) + } + } +} + +enum AESPadding { + case noPadding, pkcs5, pkcs7 + var cc: CCPadding { + switch self { + case .noPadding: + return CCPadding(ccNoPadding) + case .pkcs5: + return CCPadding(ccPKCS7Padding) + case .pkcs7: + return CCPadding(ccPKCS7Padding) + } + } +} +struct BlockMode { + var mode: AesMode + var iv: Data +} + +func CBC(iv: [UInt8]) -> BlockMode { + return BlockMode(mode: .cbc, iv: Data(iv)) +} +func CTR(iv: [UInt8]) -> BlockMode { + return BlockMode(mode: .ctr, iv: Data(iv)) +} + +class AES { + var blockMode: BlockMode + var padding: AESPadding + var key: Data + init(key: [UInt8], blockMode: BlockMode, padding: AESPadding) { + self.blockMode = blockMode + self.padding = padding + self.key = Data(key) + } + + func encrypt(_ digest: [UInt8]) throws -> [UInt8] { + return try AES128(key: key, iv: blockMode.iv).encrypt(Data(digest), padding: padding, mode: blockMode.mode).bytes + } + func encrypt(_ digest: Data) throws -> Data { + return try AES128(key: key, iv: blockMode.iv).encrypt(digest, padding: padding, mode: blockMode.mode) + } + + func decrypt(_ digest: [UInt8]) throws -> [UInt8] { + return try AES128(key: key, iv: blockMode.iv).decrypt(Data(digest), padding: padding, mode: blockMode.mode).bytes + } + func decrypt(_ digest: Data) throws -> Data { + return try AES128(key: key, iv: blockMode.iv).decrypt(digest, padding: padding, mode: blockMode.mode) + } +} + +private extension CCCryptorStatus { + func check() throws { + guard self == kCCSuccess else { throw AES128.Error.cryptoFailed(status: self) } + } +} +private extension Data { + func pointer(_ body: (UnsafePointer?) throws -> ()) rethrows { + try withUnsafeBytes(body) + } +} + +//PBKDF.deriveKey(fromPassword: mnemonics.decomposedStringWithCompatibilityMapping, salt: saltData, prf: .sha512, rounds: 2048, derivedKeyLength: 64) +struct AES128 { + private var key: Data + private var iv: Data + + init(key: Data, iv: Data) throws { + guard key.count == kCCKeySizeAES128 else { + throw Error.badKeyLength + } + guard iv.count == kCCBlockSizeAES128 else { + throw Error.badInputVectorLength + } + self.key = key + self.iv = iv + } + + enum Error: Swift.Error { + case keyGeneration(status: Int) + case cryptoFailed(status: CCCryptorStatus) + case badKeyLength + case badInputVectorLength + } + + func encrypt(_ digest: Data, padding: AESPadding, mode: AesMode) throws -> Data { + return try crypt(input: digest, operation: CCOperation(kCCEncrypt), padding: padding, mode: mode) + } + + func decrypt(_ encrypted: Data, padding: AESPadding, mode: AesMode) throws -> Data { + return try crypt(input: encrypted, operation: CCOperation(kCCDecrypt), padding: padding, mode: mode) + } + + private func crypt(input: Data, operation: CCOperation, padding: AESPadding, mode: AesMode) throws -> Data { + var outLength = Int(0) + var outBytes = [UInt8](repeating: 0, count: input.count + kCCBlockSizeAES128) + var length = 0 + + var cryptor: CCCryptorRef! + try iv.pointer { ivBytes in + try key.pointer { keyBytes in + try CCCryptorCreateWithMode(operation, mode.cc, CCAlgorithm(kCCAlgorithmAES128), padding.cc, ivBytes, keyBytes, key.count, nil, 0, 0, CCModeOptions(kCCModeOptionCTR_BE), &cryptor).check() + } + } + try input.pointer { encryptedBytes in + try CCCryptorUpdate(cryptor, encryptedBytes, input.count, &outBytes, outBytes.count, &outLength).check() + } + length += outLength + try CCCryptorFinal(cryptor, &outBytes + outLength, outBytes.count, &outLength).check() + length += outLength + + return Data(bytes: UnsafePointer(outBytes), count: length) + } + + static func createKey(password: Data, salt: Data) throws -> Data { + let length = kCCKeySizeAES256 + var status = Int32(0) + var derivedBytes = [UInt8](repeating: 0, count: length) + password.withUnsafeBytes { (passwordBytes: UnsafePointer!) in + salt.withUnsafeBytes { (saltBytes: UnsafePointer!) in + status = CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), // algorithm + passwordBytes, // password + password.count, // passwordLen + saltBytes, // salt + salt.count, // saltLen + CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1), // prf + 10000, // rounds + &derivedBytes, // derivedKey + length) // derivedKeyLen + } + } + guard status == 0 else { + throw Error.keyGeneration(status: Int(status)) + } + return Data(bytes: UnsafePointer(derivedBytes), count: length) + } + + static func randomIv() -> Data { + return randomData(length: kCCBlockSizeAES128) + } + + static func randomSalt() -> Data { + return randomData(length: 8) + } + + static func randomData(length: Int) -> Data { + var data = Data(count: length) + let status = data.withUnsafeMutableBytes { mutableBytes in + SecRandomCopyBytes(kSecRandomDefault, length, mutableBytes) + } + assert(status == Int32(0)) + return data + } +} diff --git a/Sources/Encryption/DerivedKey.swift b/Sources/Encryption/DerivedKey.swift index a495eb3..a23c093 100644 --- a/Sources/Encryption/DerivedKey.swift +++ b/Sources/Encryption/DerivedKey.swift @@ -7,28 +7,7 @@ // import Foundation -import CryptoSwift - -enum AesMode { - case ctr - case cbc - enum Error: Swift.Error { - case invalidType(String) - } - init(_ string: String) throws { - switch string { - case "aes-128-ctr": self = .ctr - case "aes-128-cbc": self = .cbc - default: throw Error.invalidType(string) - } - } - func blockMode(_ iv: Data) -> BlockMode { - switch self { - case .ctr: return CTR(iv: iv.bytes) - case .cbc: return CBC(iv: iv.bytes) - } - } -} +import Cryptor protocol DerivedKey { func calculate(password: Data) throws -> Data @@ -54,41 +33,111 @@ enum DerivedKeyType { func derivedKey(_ json: DictionaryReader) throws -> DerivedKey { switch self { case .scrypt: return try Scrypt(json: json) - case .pbkdf2: return try PBKDF2(json: json) + case .pbkdf2: return try PBKDF2Object(json: json) } } } -extension HMAC.Variant { +//extension HMAC.Variant { +// init(_ string: String) throws { +// switch string { +// case "hmac-sha256": +// self = HMAC.Variant.sha256 +// case "hmac-sha384": +// self = HMAC.Variant.sha384 +// case "hmac-sha512": +// self = HMAC.Variant.sha512 +// default: +// throw PBKDF2Object.Error.unknownHmacAlgorithm(string) +// } +// } +// var digestLength: Int { +// switch self { +// case .sha1: +// return 20 +// case .sha256: +// return SHA2.Variant.sha256.digestLength +// case .sha384: +// return SHA2.Variant.sha384.digestLength +// case .sha512: +// return SHA2.Variant.sha512.digestLength +// case .md5: +// return 16 +// } +// } +//} + + +enum HmacVariant { + case sha1, sha224, sha256, sha384, sha512 + var cc: PBKDF.PseudoRandomAlgorithm { + switch self { + case .sha1: return .sha1 + case .sha224: return .sha224 + case .sha256: return .sha256 + case .sha384: return .sha384 + case .sha512: return .sha512 + } + } + var c: HMAC.Algorithm { + switch self { + case .sha1: return .sha1 + case .sha224: return .sha224 + case .sha256: return .sha256 + case .sha384: return .sha384 + case .sha512: return .sha512 + } + } + init(_ string: String) throws { switch string { case "hmac-sha256": - self = HMAC.Variant.sha256 + self = HmacVariant.sha256 case "hmac-sha384": - self = HMAC.Variant.sha384 + self = HmacVariant.sha384 case "hmac-sha512": - self = HMAC.Variant.sha512 + self = HmacVariant.sha512 default: - throw PBKDF2.Error.unknownHmacAlgorithm(string) + throw PBKDF2Object.Error.unknownHmacAlgorithm(string) } } var digestLength: Int { switch self { case .sha1: - return 20 + return 160 / 8 + case .sha224: + return 224 / 8 case .sha256: - return SHA2.Variant.sha256.digestLength + return 256 / 8 case .sha384: - return SHA2.Variant.sha384.digestLength + return 384 / 8 case .sha512: - return SHA2.Variant.sha512.digestLength - case .md5: - return 16 + return 512 / 8 } } } -class PBKDF2: DerivedKey { +extension HMAC { + enum HMACError: Error { + case authenticationFailed + } + convenience init(key: [UInt8], variant: HmacVariant) { + self.init(using: variant.c, key: Data(key)) + } + func authenticate(_ bytes: [UInt8]) throws -> [UInt8] { + if let data = update(byteArray: bytes)?.final() { + return data + } else { + throw HMACError.authenticationFailed + } + } +} +func BetterPBKDF(password: [UInt8], salt: [UInt8], iterations: Int, keyLength: Int, variant: HmacVariant) throws -> [UInt8] { + let string = String(bytes: password, encoding: .utf8)! + return try PBKDF.deriveKey(fromPassword: string, salt: salt, prf: variant.cc, rounds: UInt32(iterations), derivedKeyLength: UInt(keyLength)) +} + +class PBKDF2Object: DerivedKey { enum Error: Swift.Error { case unknownHmacAlgorithm(String) case invalidParameters @@ -101,19 +150,19 @@ class PBKDF2: DerivedKey { } } } - let variant: HMAC.Variant + let variant: HmacVariant let keyLength: Int let iterations: Int let salt: [UInt8] - init(salt: Data, iterations: Int, keyLength: Int, variant: HMAC.Variant) { + init(salt: Data, iterations: Int, keyLength: Int, variant: HmacVariant) { self.salt = Array(salt) self.keyLength = keyLength self.iterations = iterations self.variant = variant } init(json: DictionaryReader) throws { - variant = try HMAC.Variant(json.at("prf").string()) + variant = try HmacVariant(json.at("prf").string()) keyLength = try json.at("dklen").int() iterations = try json.at("c").int() salt = try Array(json.at("salt").data()) @@ -124,9 +173,8 @@ class PBKDF2: DerivedKey { } func calculate(password: Data) throws -> Data { - let derivedKey = try! PKCS5.PBKDF2(password: Array(password), salt: Array(salt), iterations: iterations, keyLength: keyLength, variant: variant) do { - return try Data(derivedKey.calculate()) + return try Data(BetterPBKDF(password: Array(password), salt: Array(salt), iterations: iterations, keyLength: keyLength, variant: variant)) } catch { throw DecryptionError.invalidPassword } @@ -208,7 +256,7 @@ class Scrypt: DerivedKey { } /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ - let barray = try PBKDF2(salt: salt, iterations: 1, keyLength: p * 128 * r, variant: .sha256).calculate(password: password) + let barray = try PBKDF2Object(salt: salt, iterations: 1, keyLength: p * 128 * r, variant: .sha256).calculate(password: password) Array(barray).withUnsafeBytes { p in B.copyMemory(from: p.baseAddress!, byteCount: barray.count) @@ -224,7 +272,7 @@ class Scrypt: DerivedKey { let pointer = B.assumingMemoryBound(to: UInt8.self) let bufferPointer = UnsafeBufferPointer(start: pointer, count: p * 128 * r) let block = Data(buffer: bufferPointer) - return try PBKDF2(salt: block, iterations: 1, keyLength: dkLen, variant: .sha256).calculate(password: password) + return try PBKDF2Object(salt: block, iterations: 1, keyLength: dkLen, variant: .sha256).calculate(password: password) } /// Computes `B = SMix_r(B, N)`. diff --git a/Sources/Encryption/PrivateKey.swift b/Sources/Encryption/PrivateKey.swift new file mode 100644 index 0000000..057f2a3 --- /dev/null +++ b/Sources/Encryption/PrivateKey.swift @@ -0,0 +1,113 @@ +// +// PrivateKey.swift +// web3swift +// +// Created by Dmitry on 29/11/2018. +// Copyright © 2018 Bankex Foundation. All rights reserved. +// + +import Foundation +import BigInt + +/** + Secp256k1 private key. + + Used in ethereum accounts. You can get public key, address and sign some data + + ## Performance + + > Operations per second in debug and release build mode + ``` + Generate Private key: + release debug + 175772 160180 + + PrivateKey -> Public Key: + release debug + 26642 9036 + + PrivateKey -> Address: + release debug + 11894 2058 + ``` + */ +public class PrivateKey { + /// Private key data + public var privateKey: Data + + /// Singleton that generates public key from private key + public lazy var publicKey: Data = try! SECP256K1.privateToPublic(privateKey: privateKey) + + /// Singleton that generates address from public key + public lazy var address: Address = try! Web3Utils.publicToAddress(publicKey) + + /// Generates random private key. All generated keys are verified + public init() { + self.privateKey = .random(length: 32) + } + + /// Init with private key data. run .verify() to verify it + public init(_ privateKey: Data) { + self.privateKey = privateKey + } + + + /// Signs hash with private key signature + /// + /// - Parameter hash: 32 bytes hash. To get hash call data.keccak256() + /// - Returns: Signature that you can use in your transactions + /// - Throws: If hash size invalid hash size or private key. Call privateKey.verify() + public func sign(hash: Data) throws -> Signature { + let signature = try SECP256K1.signForRecovery(hash: hash, privateKey: privateKey).serializedSignature + return Signature(data: signature) + } + + + /// Verifies the private key. Also every 32 byte private keys are valid + /// + /// - Throws: SECP256K1Error.invalidPrivateKey + public func verify() throws { + try SECP256K1.verifyPrivateKey(privateKey: privateKey) + } +} + + +/// Signature of some hash. You can get it by calling PrivateKey.sign(hash:) +public class Signature { + /// Signature data + public let data: Data + + /// Init with data. Don't forget to call .check(compressed:) if you want to init with custom data + /// + /// - Parameter data: Signature data + public init(data: Data) { + self.data = data + } + + + /// Checks for signature + /// + /// - Parameter compressed: Checks for compressed signature (33 bytes long) + /// - Throws: SECP256K1Error.invalidSignatureSize or SECP256DataError.signatureCorrupted + public func check(compressed: Bool = false) throws { + if compressed { + guard data.count == 33 else { throw SECP256K1Error.invalidSignatureSize } + } else { + guard data.count == 65 else { throw SECP256K1Error.invalidSignatureSize } + } + guard v < 4 else { throw SECP256DataError.signatureCorrupted } + } + + /// Signature first 32 bytes + public lazy var r = BigUInt(data[0..<32]) + /// Signature next 32 bytes + public lazy var s = BigUInt(data[32..<64]) + /// Last signature byte. Should be less than 4 + public lazy var v: UInt8 = { + var v = data.last! + if v >= 27 { + v = v - 27 + } + return v + }() +} diff --git a/Sources/HookedFunctions/Web3+BrowserFunctions.swift b/Sources/HookedFunctions/Web3+BrowserFunctions.swift index 7190f31..3a2694d 100644 --- a/Sources/HookedFunctions/Web3+BrowserFunctions.swift +++ b/Sources/HookedFunctions/Web3+BrowserFunctions.swift @@ -75,7 +75,7 @@ public class Web3BrowserFunctions: Web3OptionsInheritable { public func sign(_ personalMessage: Data, account: String, password: String = "BANKEXFOUNDATION") -> String? { let keystoreManager = self.web3.provider.attachedKeystoreManager guard let signature = try? Web3Signer.signPersonalMessage(personalMessage, keystore: keystoreManager, account: Address(account), password: password) else { return nil } - return signature.toHexString().withHex + return signature.hex.withHex } /** @@ -244,7 +244,7 @@ public class Web3BrowserFunctions: Web3OptionsInheritable { guard let keystore = keystoreManager.walletForAddress(from) else { throw TransactionError.privateKeyNotFound(forAddress: from) } try Web3Signer.signTX(transaction: &transaction, keystore: keystore, account: from, password: password) - guard let signedData = transaction.encode(forSignature: false, chainId: nil)?.toHexString().withHex else { throw TransactionError.cannotEncodeTransaction } + guard let signedData = transaction.encode(forSignature: false, chainId: nil)?.hex.withHex else { throw TransactionError.cannotEncodeTransaction } return signedData } } diff --git a/Sources/Keystore/Accounts.swift b/Sources/Keystore/Accounts.swift deleted file mode 100644 index 8103555..0000000 --- a/Sources/Keystore/Accounts.swift +++ /dev/null @@ -1,198 +0,0 @@ -// -// Accounts.swift -// web3swift -// -// Created by Dmitry on 27/11/2018. -// Copyright © 2018 Bankex Foundation. All rights reserved. -// - -import Foundation -import CryptoSwift - -/* -## Version 3 - -{ - "crypto" : { - "cipher" : "aes-128-ctr", - "cipherparams" : { - "iv" : "83dbcc02d8ccb40e466191a123791e0e" - }, - "ciphertext" : "d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c", - "kdf" : "scrypt", - "kdfparams" : { - "dklen" : 32, - "n" : 262144, - "r" : 1, - "p" : 8, - "salt" : "ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19" - }, - "mac" : "2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097" - }, - "id" : "3198bc9c-6672-5ab3-d995-4942343ae5b6", - "version" : 3 -} - -## Version 2 - -``` -{ - "crypto": { - "cipher": "aes-128-cbc", - "ciphertext": "07533e172414bfa50e99dba4a0ce603f654ebfa1ff46277c3e0c577fdc87f6bb4e4fe16c5a94ce6ce14cfa069821ef9b", - "cipherparams": { - "iv": "16d67ba0ce5a339ff2f07951253e6ba8" - }, - "kdf": "scrypt", - "kdfparams": { - "dklen": 32, - "n": 262144, - "p": 1, - "r": 8, - "salt": "06870e5e6a24e183a5c807bd1c43afd86d573f7db303ff4853d135cd0fd3fe91" - }, - "mac": "8ccded24da2e99a11d48cda146f9cc8213eb423e2ea0d8427f41c3be414424dd", - "version": 1 - }, - "id": "0498f19a-59db-4d54-ac95-33901b4f1870", - "version": 2 -} -``` - -## Version 1 - -``` -{ - "Address": "d4584b5f6229b7be90727b0fc8c6b91bb427821f", - "Crypto": { - "CipherText": "07533e172414bfa50e99dba4a0ce603f654ebfa1ff46277c3e0c577fdc87f6bb4e4fe16c5a94ce6ce14cfa069821ef9b", - "IV": "16d67ba0ce5a339ff2f07951253e6ba8", - "KeyHeader": { - "Kdf": "scrypt", - "KdfParams": { - "DkLen": 32, - "N": 262144, - "P": 1, - "R": 8, - "SaltLen": 32 - }, - "Version": "1" - }, - "MAC": "8ccded24da2e99a11d48cda146f9cc8213eb423e2ea0d8427f41c3be414424dd", - "Salt": "06870e5e6a24e183a5c807bd1c43afd86d573f7db303ff4853d135cd0fd3fe91" - }, - "Id": "0498f19a-59db-4d54-ac95-33901b4f1870", - "Version": "1" -} -``` -*/ - -/* -public struct KeystoreParamsV3: Decodable, Encodable { - var address: String? - var crypto: CryptoParamsV3 - var id: String? - var version: Int - - /// Init with all params - public init(address ad: String?, crypto cr: CryptoParamsV3, id i: String, version ver: Int) { - address = ad - crypto = cr - id = i - version = ver - } -} -/// Keystore encryption info -public struct CryptoParamsV3: Decodable, Encodable { - var ciphertext: String - var cipher: String - var cipherparams: CipherParamsV3 - var kdf: String - var kdfparams: KdfParamsV3 - var mac: String - var version: String? -} -*/ - - - - - -/* -class Accounts { - var accounts: [LockedAccount] - init(json: DictionaryReader) throws { - let version = try json.at("version").int() - let id = try json.at("id").string() - - - /* - { - "crypto" : { - "cipher" : "aes-128-ctr", - "cipherparams" : { - "iv" : "83dbcc02d8ccb40e466191a123791e0e" - }, - "ciphertext" : "d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c", - "kdf" : "scrypt", - "kdfparams" : { - "dklen" : 32, - "n" : 262144, - "r" : 1, - "p" : 8, - "salt" : "ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19" - }, - "mac" : "2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097" - }, - "id" : "3198bc9c-6672-5ab3-d995-4942343ae5b6", - "version" : 3 - } - */ - } -} -*/ - -class JsonLockedAccount { - enum ParsingError: Swift.Error { - case invalidCipherText(String) - } - - let derivedKey: DerivedKey - let encryptedPrivateKey: Data - let blockMode: BlockMode - let mac: Data - init(json: DictionaryReader) throws { - let crypto = try json.at("crypto") - derivedKey = try DerivedKeyType(crypto.at("kdf").string()).derivedKey(crypto.at("kdfparams")) - - encryptedPrivateKey = try crypto.at("ciphertext").data() - guard encryptedPrivateKey.count == 32 else { throw ParsingError.invalidCipherText(encryptedPrivateKey.hex) } - blockMode = try AesMode(crypto.at("cipher").string()).blockMode(crypto.at("cipherparams").at("iv").data()) - mac = try crypto.at("mac").data() - } - - func unlock(password: Data) throws -> Account { - let derivedKey = try self.derivedKey.calculate(password: password) - var dataForMAC = Data() - dataForMAC.append(derivedKey.suffix(16)) - dataForMAC.append(encryptedPrivateKey) - let mac = dataForMAC.sha3(.keccak256) - guard self.mac.constantTimeComparisonTo(mac) else { throw DecryptionError.invalidPassword } - - let decryptionKey = derivedKey.suffix(16) - let aesCipher = try AES(key: decryptionKey.bytes, blockMode: blockMode, padding: .noPadding) - let privateKey = try aesCipher.decrypt(encryptedPrivateKey.bytes) - return Account(privateKey: Data(privateKey)) - } -} - -class LockedAccount { - -} - -class Account { - var privateKey: Data - init(privateKey: Data) { - self.privateKey = privateKey - } -} diff --git a/Sources/KeystoreManager/BIP32HDNode.swift b/Sources/KeystoreManager/BIP32HDNode.swift index 109116a..c7c0385 100644 --- a/Sources/KeystoreManager/BIP32HDNode.swift +++ b/Sources/KeystoreManager/BIP32HDNode.swift @@ -7,7 +7,7 @@ // import BigInt -import CryptoSwift +import Cryptor import Foundation extension UInt32 { @@ -143,7 +143,7 @@ public class HDNode { public init(seed: Data) throws { guard seed.count >= 16 else { throw Error.invalidSeedSize } let hmacKey = "Bitcoin seed".data(using: .ascii)! - let hmac: Authenticator = HMAC(key: hmacKey.bytes, variant: HMAC.Variant.sha512) + let hmac = HMAC(key: hmacKey.bytes, variant: .sha512) let entropy = try hmac.authenticate(seed.bytes) try entropy.checkEntropySize() let I_L = entropy[0 ..< 32] @@ -216,7 +216,7 @@ public class HDNode { if trueIndex < HDNode.hardenedIndexPrefix { trueIndex = trueIndex + HDNode.hardenedIndexPrefix } - let hmac: Authenticator = HMAC(key: chaincode.bytes, variant: .sha512) + let hmac = HMAC(key: chaincode.bytes, variant: .sha512) var inputForHMAC = Data() inputForHMAC.append(Data([UInt8(0x00)])) inputForHMAC.append(privateKey!) @@ -225,7 +225,7 @@ public class HDNode { try entropy.checkEntropySize() } else { trueIndex = index - let hmac: Authenticator = HMAC(key: chaincode.bytes, variant: .sha512) + let hmac = HMAC(key: chaincode.bytes, variant: .sha512) var inputForHMAC = Data() inputForHMAC.append(publicKey) inputForHMAC.append(trueIndex.serialize32()) @@ -269,7 +269,7 @@ public class HDNode { return newNode } else { // deriving only the public key guard !(index >= HDNode.hardenedIndexPrefix || hardened) else { throw DeriveError.noHardenedDerivation } - let hmac: Authenticator = HMAC(key: self.chaincode.bytes, variant: .sha512) + let hmac = HMAC(key: self.chaincode.bytes, variant: .sha512) var inputForHMAC = Data() inputForHMAC.append(publicKey) inputForHMAC.append(index.serialize32()) diff --git a/Sources/KeystoreManager/BIP32Keystore.swift b/Sources/KeystoreManager/BIP32Keystore.swift index 0e53123..0d12dfa 100644 --- a/Sources/KeystoreManager/BIP32Keystore.swift +++ b/Sources/KeystoreManager/BIP32Keystore.swift @@ -6,7 +6,6 @@ // Copyright © 2018 Bankex Foundation. All rights reserved. // -import CryptoSwift import Foundation private extension Dictionary where Value: Equatable { @@ -71,18 +70,18 @@ public class BIP32Keystore: AbstractKeystore { /// Init with json file public init?(_ jsonData: Data) { - guard var keystorePars = try? JSONDecoder().decode(KeystoreParamsBIP32.self, from: jsonData) else { return nil } - if keystorePars.version != 3 { return nil } - if keystorePars.crypto.version != nil && keystorePars.crypto.version != "1" { return nil } - if !keystorePars.isHDWallet { return nil } - for (p, ad) in keystorePars.pathToAddress { + guard var keystoreParams = try? JSONDecoder().decode(KeystoreParamsBIP32.self, from: jsonData) else { return nil } + if keystoreParams.version != 3 { return nil } + if keystoreParams.crypto.version != nil && keystoreParams.crypto.version != "1" { return nil } + if !keystoreParams.isHDWallet { return nil } + for (p, ad) in keystoreParams.pathToAddress { paths[p] = Address(ad) } - if keystorePars.rootPath == nil { - keystorePars.rootPath = HDNode.defaultPathPrefix + if keystoreParams.rootPath == nil { + keystoreParams.rootPath = HDNode.defaultPathPrefix } - keystoreParams = keystorePars - rootPrefix = keystoreParams!.rootPath! + self.keystoreParams = keystoreParams + rootPrefix = keystoreParams.rootPath! } /// Init with mnemonics @@ -194,12 +193,13 @@ public class BIP32Keystore: AbstractKeystore { let last16bytes = derivedKey[(derivedKey.count - 16) ... (derivedKey.count - 1)] let encryptionKey = derivedKey[0 ... 15] let IV = Data.random(length: 16) + var aesCipher: AES? switch aesMode { case "aes-128-cbc": - aesCipher = try? AES(key: encryptionKey.bytes, blockMode: CBC(iv: IV.bytes), padding: .pkcs7) + aesCipher = AES(key: encryptionKey.bytes, blockMode: CBC(iv: IV.bytes), padding: .pkcs7) case "aes-128-ctr": - aesCipher = try? AES(key: encryptionKey.bytes, blockMode: CTR(iv: IV.bytes), padding: .pkcs7) + aesCipher = AES(key: encryptionKey.bytes, blockMode: CTR(iv: IV.bytes), padding: .pkcs7) default: aesCipher = nil } @@ -211,10 +211,10 @@ public class BIP32Keystore: AbstractKeystore { var dataForMAC = Data() dataForMAC.append(last16bytes) dataForMAC.append(encryptedKeyData) - let mac = dataForMAC.sha3(.keccak256) - let kdfparams = KdfParamsV3(salt: saltData.toHexString(), dklen: dkLen, n: N, p: P, r: R, c: nil, prf: nil) - let cipherparams = CipherParamsV3(iv: IV.toHexString()) - let crypto = CryptoParamsV3(ciphertext: encryptedKeyData.toHexString(), cipher: aesMode, cipherparams: cipherparams, kdf: "scrypt", kdfparams: kdfparams, mac: mac.toHexString(), version: nil) + let mac = dataForMAC.keccak256() + let kdfparams = KdfParamsV3(salt: saltData.hex, dklen: dkLen, n: N, p: P, r: R, c: nil, prf: nil) + let cipherparams = CipherParamsV3(iv: IV.hex) + let crypto = CryptoParamsV3(ciphertext: encryptedKeyData.hex, cipher: aesMode, cipherparams: cipherparams, kdf: "scrypt", kdfparams: kdfparams, mac: mac.hex, version: nil) var pathToAddress = [String: String]() for (path, address) in paths { pathToAddress[path] = address.address @@ -248,20 +248,9 @@ public class BIP32Keystore: AbstractKeystore { passwordDerivedKey = scrypt(password: password, salt: saltData, length: derivedLen, N: N, R: R, P: P) case "pbkdf2": guard let algo = keystorePars.crypto.kdfparams.prf else { return nil } - var hashVariant: HMAC.Variant? - switch algo { - case "hmac-sha256": - hashVariant = HMAC.Variant.sha256 - case "hmac-sha384": - hashVariant = HMAC.Variant.sha384 - case "hmac-sha512": - hashVariant = HMAC.Variant.sha512 - default: - hashVariant = nil - } - guard hashVariant != nil else { return nil } + let hashVariant = try HmacVariant(algo) guard let c = keystorePars.crypto.kdfparams.c else { return nil } - guard let derivedArray = try? PKCS5.PBKDF2(password: Array(password.utf8), salt: saltData.bytes, iterations: c, keyLength: derivedLen, variant: hashVariant!).calculate() else { return nil } + guard let derivedArray = try? BetterPBKDF(password: Array(password.utf8), salt: saltData.bytes, iterations: c, keyLength: derivedLen, variant: hashVariant) else { return nil } passwordDerivedKey = Data(bytes: derivedArray) default: return nil @@ -273,7 +262,7 @@ public class BIP32Keystore: AbstractKeystore { guard let cipherText = Data.fromHex(keystorePars.crypto.ciphertext) else { return nil } guard cipherText.count % 32 == 0 else { return nil } dataForMAC.append(cipherText) - let mac = dataForMAC.sha3(.keccak256) + let mac = dataForMAC.keccak256() guard let calculatedMac = Data.fromHex(keystorePars.crypto.mac), mac.constantTimeComparisonTo(calculatedMac) else { return nil } let cipher = keystorePars.crypto.cipher let decryptionKey = derivedKey[0 ... 15] @@ -281,10 +270,10 @@ public class BIP32Keystore: AbstractKeystore { var decryptedPK: Array? switch cipher { case "aes-128-ctr": - guard let aesCipher = try? AES(key: decryptionKey.bytes, blockMode: CTR(iv: IV.bytes), padding: .pkcs7) else { return nil } + let aesCipher = AES(key: decryptionKey.bytes, blockMode: CTR(iv: IV.bytes), padding: .pkcs7) decryptedPK = try aesCipher.decrypt(cipherText.bytes) case "aes-128-cbc": - guard let aesCipher = try? AES(key: decryptionKey.bytes, blockMode: CBC(iv: IV.bytes), padding: .pkcs7) else { return nil } + let aesCipher = AES(key: decryptionKey.bytes, blockMode: CBC(iv: IV.bytes), padding: .pkcs7) decryptedPK = try? aesCipher.decrypt(cipherText.bytes) default: return nil diff --git a/Sources/KeystoreManager/BIP39.swift b/Sources/KeystoreManager/BIP39.swift index 3a65ebf..3f8e8a3 100644 --- a/Sources/KeystoreManager/BIP39.swift +++ b/Sources/KeystoreManager/BIP39.swift @@ -6,7 +6,7 @@ // Copyright © 2018 Bankex Foundation. All rights reserved. // -import CryptoSwift +import Cryptor import Foundation /// Mnemonics language @@ -157,7 +157,6 @@ public class Mnemonics { /// Generate seed from mnemonics string. This function will ignore dictionary and won't check for mnemonics error public static func seed(from mnemonics: String, password: String) -> Data { - let mnemData = Array(mnemonics.decomposedStringWithCompatibilityMapping.utf8) let salt = "mnemonic" + password let saltData = Array(salt.decomposedStringWithCompatibilityMapping.utf8) @@ -165,7 +164,7 @@ public class Mnemonics { // or keyLength > variant.digestLength * 256 // and .calculate() won't throw any errors // so i feel free to use "try!" - let seed = try! PKCS5.PBKDF2(password: mnemData, salt: saltData, iterations: 2048, keyLength: 64, variant: .sha512).calculate() + let seed = try! PBKDF.deriveKey(fromPassword: mnemonics.decomposedStringWithCompatibilityMapping, salt: saltData, prf: .sha512, rounds: 2048, derivedKeyLength: 64) return Data(bytes: seed) } @@ -221,14 +220,15 @@ public class Mnemonics { var fullEntropy = Data() fullEntropy.append(entropy) fullEntropy.append(checksum[0 ..< (checksumBits + 7) / 8]) - var wordList = [String]() + let separator = language.separator + let words = language.words + var indexes = [Int]() for i in 0 ..< fullEntropy.count * 8 / 11 { let bits = fullEntropy.bitsInRange(i * 11, 11) let index = Int(bits) - let word = language.words[index] - wordList.append(word) + indexes.append(index) } - self.string = wordList.joined(separator: language.separator) + self.string = indexes.map { words[$0] }.joined(separator: separator) self.language = language } diff --git a/Sources/KeystoreManager/EthereumAddress.swift b/Sources/KeystoreManager/EthereumAddress.swift index 04bc160..cc35efa 100644 --- a/Sources/KeystoreManager/EthereumAddress.swift +++ b/Sources/KeystoreManager/EthereumAddress.swift @@ -84,10 +84,7 @@ public struct Address { public var addressData: Data { switch type { case .normal: - guard let dataArray = Data.fromHex(_address) else { return Data() } - return dataArray - // guard let d = dataArray.setLengthLeft(20) else { return Data()} - // return d + return Data.fromHex(_address) ?? Data() case .contractDeployment: return Data() } @@ -107,7 +104,7 @@ public struct Address { /// Converts address to checksum address public static func toChecksumAddress(_ addr: String) -> String? { let address = addr.lowercased().withoutHex - guard let hash = address.data(using: .ascii)?.sha3(.keccak256).toHexString() else { return nil } + guard let hash = address.data(using: .ascii)?.keccak256().hex else { return nil } var ret = "0x" for (i, char) in address.enumerated() { @@ -145,7 +142,7 @@ public struct Address { /// - Parameter type: Address type. default: .normal /// - Important: addressData is not the utf8 format of hex string public init(_ addressData: Data, type: AddressType = .normal) { - _address = addressData.toHexString().withHex + _address = addressData.hex.withHex self.type = type } @@ -172,6 +169,12 @@ extension Address: Equatable { } } +extension Address: Hashable { + public var hashValue: Int { + return address.hashValue + } +} + extension Address: CustomStringConvertible { /// - Returns: Address hex string formatted to checksum public var description: String { diff --git a/Sources/KeystoreManager/EthereumKeystoreV3.swift b/Sources/KeystoreManager/EthereumKeystoreV3.swift index b099a85..fdcb0fc 100644 --- a/Sources/KeystoreManager/EthereumKeystoreV3.swift +++ b/Sources/KeystoreManager/EthereumKeystoreV3.swift @@ -6,7 +6,6 @@ // Copyright © 2017 Bankex Foundation. All rights reserved. // -import CryptoSwift import Foundation /** @@ -107,9 +106,9 @@ public class EthereumKeystoreV3: AbstractKeystore { var aesCipher: AES! switch aesMode { case "aes-128-cbc": - aesCipher = try? AES(key: encryptionKey.bytes, blockMode: CBC(iv: IV.bytes), padding: .noPadding) + aesCipher = AES(key: encryptionKey.bytes, blockMode: CBC(iv: IV.bytes), padding: .noPadding) case "aes-128-ctr": - aesCipher = try? AES(key: encryptionKey.bytes, blockMode: CTR(iv: IV.bytes), padding: .noPadding) + aesCipher = AES(key: encryptionKey.bytes, blockMode: CTR(iv: IV.bytes), padding: .noPadding) default: aesCipher = nil } @@ -119,10 +118,10 @@ public class EthereumKeystoreV3: AbstractKeystore { var dataForMAC = Data() dataForMAC.append(last16bytes) dataForMAC.append(encryptedKeyData) - let mac = dataForMAC.sha3(.keccak256) - let kdfparams = KdfParamsV3(salt: saltData.toHexString(), dklen: dkLen, n: N, p: P, r: R, c: nil, prf: nil) - let cipherparams = CipherParamsV3(iv: IV.toHexString()) - let crypto = CryptoParamsV3(ciphertext: encryptedKeyData.toHexString(), cipher: aesMode, cipherparams: cipherparams, kdf: "scrypt", kdfparams: kdfparams, mac: mac.toHexString(), version: nil) + let mac = dataForMAC.keccak256() + let kdfparams = KdfParamsV3(salt: saltData.hex, dklen: dkLen, n: N, p: P, r: R, c: nil, prf: nil) + let cipherparams = CipherParamsV3(iv: IV.hex) + let crypto = CryptoParamsV3(ciphertext: encryptedKeyData.hex, cipher: aesMode, cipherparams: cipherparams, kdf: "scrypt", kdfparams: kdfparams, mac: mac.hex, version: nil) let pubKey = try Web3Utils.privateToPublic(keyData!) let addr = try Web3Utils.publicToAddress(pubKey) address = addr @@ -153,44 +152,32 @@ public class EthereumKeystoreV3: AbstractKeystore { passwordDerivedKey = scrypt(password: password, salt: saltData, length: derivedLen, N: N, R: R, P: P) case "pbkdf2": guard let algo = keystoreParams.crypto.kdfparams.prf else { return nil } - var hashVariant: HMAC.Variant? - switch algo { - case "hmac-sha256": - hashVariant = HMAC.Variant.sha256 - case "hmac-sha384": - hashVariant = HMAC.Variant.sha384 - case "hmac-sha512": - hashVariant = HMAC.Variant.sha512 - default: - hashVariant = nil - } - guard hashVariant != nil else { return nil } + let hashVariant = try HmacVariant(algo) guard let c = keystoreParams.crypto.kdfparams.c else { return nil } - guard let derivedArray = try? PKCS5.PBKDF2(password: Array(password.utf8), salt: saltData.bytes, iterations: c, keyLength: derivedLen, variant: hashVariant!).calculate() else { return nil } + guard let derivedArray = try? BetterPBKDF(password: Array(password.utf8), salt: saltData.bytes, iterations: c, keyLength: derivedLen, variant: hashVariant) else { return nil } passwordDerivedKey = Data(bytes: derivedArray) default: return nil } guard let derivedKey = passwordDerivedKey else { return nil } var dataForMAC = Data() - let derivedKeyLast16bytes = Data(derivedKey[(derivedKey.count - 16) ... (derivedKey.count - 1)]) - dataForMAC.append(derivedKeyLast16bytes) + dataForMAC.append(derivedKey.suffix(16)) guard let cipherText = Data.fromHex(keystoreParams.crypto.ciphertext) else { return nil } if cipherText.count != 32 { return nil } dataForMAC.append(cipherText) - let mac = dataForMAC.sha3(.keccak256) + let mac = dataForMAC.keccak256() guard let calculatedMac = Data.fromHex(keystoreParams.crypto.mac), mac.constantTimeComparisonTo(calculatedMac) else { return nil } let cipher = keystoreParams.crypto.cipher - let decryptionKey = derivedKey[0 ... 15] + let decryptionKey = derivedKey.prefix(16) guard let IV = Data.fromHex(keystoreParams.crypto.cipherparams.iv) else { return nil } var decryptedPK: Array? switch cipher { case "aes-128-ctr": - guard let aesCipher = try? AES(key: decryptionKey.bytes, blockMode: CTR(iv: IV.bytes), padding: .noPadding) else { return nil } + let aesCipher = AES(key: decryptionKey.bytes, blockMode: CTR(iv: IV.bytes), padding: .noPadding) decryptedPK = try aesCipher.decrypt(cipherText.bytes) case "aes-128-cbc": - guard let aesCipher = try? AES(key: decryptionKey.bytes, blockMode: CBC(iv: IV.bytes), padding: .noPadding) else { return nil } - decryptedPK = try? aesCipher.decrypt(cipherText.bytes) + let aesCipher = AES(key: decryptionKey.bytes, blockMode: CBC(iv: IV.bytes), padding: .noPadding) + decryptedPK = try aesCipher.decrypt(cipherText.bytes) default: return nil } @@ -201,7 +188,9 @@ public class EthereumKeystoreV3: AbstractKeystore { /// Returns json file encoded with v3 standard public func serialize() throws -> Data? { guard let params = self.keystoreParams else { return nil } - let data = try JSONEncoder().encode(params) + let encoder = JSONEncoder() + encoder.outputFormatting = .prettyPrinted + let data = try encoder.encode(params) return data } } diff --git a/Sources/Transaction/BloomFilter.swift b/Sources/Transaction/BloomFilter.swift index 0b86158..dc15db1 100644 --- a/Sources/Transaction/BloomFilter.swift +++ b/Sources/Transaction/BloomFilter.swift @@ -7,7 +7,6 @@ // import BigInt -import CryptoSwift import Foundation /// Ethereum bloom filter @@ -39,7 +38,7 @@ public struct EthereumBloomFilter { } static func bloom9(_ data: Data) -> BigUInt { - var b = data.sha3(.keccak256) + var b = data.keccak256() var r = BigUInt(0) let mask = BigUInt(2047) for i in stride(from: 0, to: 6, by: 2) { diff --git a/Sources/Transaction/EthereumTransaction.swift b/Sources/Transaction/EthereumTransaction.swift index 5309dbe..ff6cb52 100644 --- a/Sources/Transaction/EthereumTransaction.swift +++ b/Sources/Transaction/EthereumTransaction.swift @@ -56,7 +56,7 @@ public struct EthereumTransaction: CustomStringConvertible { public var hash: Data? { let chainId = inferedChainID ?? self.chainID guard let encoded = self.encode(forSignature: false, chainId: chainId) else { return nil } - return encoded.sha3(.keccak256) + return encoded.keccak256() } /// Init with transaction parameters @@ -169,7 +169,7 @@ hash: \(String(describing: hash)) public var txhash: String? { guard sender != nil else { return nil } guard let hash = self.hash else { return nil } - let txid = hash.toHexString().withHex.lowercased() + let txid = hash.hex.withHex.lowercased() return txid } @@ -209,13 +209,13 @@ hash: \(String(describing: hash)) var params = TransactionParameters(from: from?.address.lowercased(), to: toString) let gasEncoding = gasLimit.abiEncode(bits: 256) - params.gas = gasEncoding?.toHexString().withHex.stripLeadingZeroes() + params.gas = gasEncoding?.hex.withHex.stripLeadingZeroes() let gasPriceEncoding = gasPrice.abiEncode(bits: 256) - params.gasPrice = gasPriceEncoding?.toHexString().withHex.stripLeadingZeroes() + params.gasPrice = gasPriceEncoding?.hex.withHex.stripLeadingZeroes() let valueEncoding = value.abiEncode(bits: 256) - params.value = valueEncoding?.toHexString().withHex.stripLeadingZeroes() + params.value = valueEncoding?.hex.withHex.stripLeadingZeroes() if data != Data() { - params.data = data.toHexString().withHex + params.data = data.hex.withHex } else { params.data = "0x" } @@ -229,8 +229,7 @@ hash: \(String(describing: hash)) /// - Returns: Transaction hash public func hashForSignature(chainID: NetworkId? = nil) -> Data? { guard let encoded = self.encode(forSignature: true, chainId: chainID) else { return nil } - let hash = encoded.sha3(.keccak256) - return hash + return encoded.keccak256() } init(_ json: [String: Any]) throws { @@ -323,7 +322,7 @@ hash: \(String(describing: hash)) static func createRawTransaction(transaction: EthereumTransaction) -> JsonRpcRequest? { guard transaction.sender != nil else { return nil } guard let encodedData = transaction.encode() else { return nil } - let hex = encodedData.toHexString().withHex.lowercased() + let hex = encodedData.hex.withHex.lowercased() var request = JsonRpcRequest(method: .sendRawTransaction) let params = [hex] as Array let pars = JsonRpcParams(params: params) diff --git a/Sources/ABIv2/SolidityDataReader.swift b/Sources/Transactions/SolidityDataReader.swift similarity index 100% rename from Sources/ABIv2/SolidityDataReader.swift rename to Sources/Transactions/SolidityDataReader.swift diff --git a/Sources/ABIv2/SolidityDataWriter.swift b/Sources/Transactions/SolidityDataWriter.swift similarity index 84% rename from Sources/ABIv2/SolidityDataWriter.swift rename to Sources/Transactions/SolidityDataWriter.swift index 9afda0f..50ada3d 100644 --- a/Sources/ABIv2/SolidityDataWriter.swift +++ b/Sources/Transactions/SolidityDataWriter.swift @@ -35,7 +35,7 @@ private extension Data { } } class SolidityDataWriter { - private var data: Data + private(set) var data: Data private var dynamicData = [SolidityDataPointer]() var offset = 0 init() { @@ -78,7 +78,19 @@ class SolidityDataWriter { self.data.append(data) } } + func setLength() { + data.replaceSubrange(0..<0, with: length(data.count, offset: 0xc0)) + } + + private func length(_ l: Int, offset: Int) -> Data { + func byte(_ value: Int) -> Data { return Data([UInt8(value)]) } + guard l + offset > 0xf7 else { return byte(l+offset) } + let serialized = BigUInt(l).serialize() + return byte(0xf7+serialized.count) + serialized + } + func done() -> Data { + guard !dynamicData.isEmpty else { return data } for pointer in dynamicData { data.write(data: (data.count - offset).solidityData, at: pointer.position) if pointer.data.count == 0 { diff --git a/Sources/ABIv2/SolidityFunction.swift b/Sources/Transactions/SolidityFunction.swift similarity index 100% rename from Sources/ABIv2/SolidityFunction.swift rename to Sources/Transactions/SolidityFunction.swift diff --git a/Sources/ABIv2/SolidityTypes.swift b/Sources/Transactions/SolidityTypes.swift similarity index 99% rename from Sources/ABIv2/SolidityTypes.swift rename to Sources/Transactions/SolidityTypes.swift index 9994413..dd030d7 100644 --- a/Sources/ABIv2/SolidityTypes.swift +++ b/Sources/Transactions/SolidityTypes.swift @@ -41,6 +41,10 @@ public enum AbiError: Error { ``` */ public class SolidityType: Equatable, CustomStringConvertible { + static let uint256 = SUInt(bits: 256) + static let address = SAddress() + + /// SolidityType array size public enum ArraySize { /// returns number of elements in a static array diff --git a/Sources/Transactions/Transaction.swift b/Sources/Transactions/Transaction.swift new file mode 100644 index 0000000..3c62a7b --- /dev/null +++ b/Sources/Transactions/Transaction.swift @@ -0,0 +1,123 @@ +// +// Transaction.swift +// web3swift +// +// Created by Dmitry on 30/11/2018. +// Copyright © 2018 Bankex Foundation. All rights reserved. +// + +import Foundation +import BigInt + +/// WIP +class Transaction { + var nonce: BigUInt = 0 + var gasPrice: BigUInt + var gasLimit: BigUInt + var to: Address + var value: BigUInt + var data: Data + + init(gasPrice: BigUInt, gasLimit: BigUInt, to: Address, value: BigUInt, data: Data) { + self.gasPrice = gasPrice + self.gasLimit = gasLimit + self.to = to + self.value = value + self.data = data + } + + func write(to data: TransactionDataWriter) { + data.append(nonce) + data.append(gasPrice) + data.append(gasLimit) + data.append(to) + data.append(value) + data.append(self.data) + } + + func write(networkId: NetworkId, to data: TransactionDataWriter) { + data.append(networkId.rawValue) + data.append(0) + data.append(0) + } + + func sign(using privateKey: PrivateKey, networkId: NetworkId? = nil) throws -> SignedTransaction { + let data = TransactionDataWriter() + write(to: data) + if let networkId = networkId { + write(networkId: networkId, to: data) + } + let hash = data.done().keccak256() + let signature = try privateKey.sign(hash: hash) + return SignedTransaction(transaction: self, signature: signature, networkId: networkId) + } +} + +/// WIP +class SignedTransaction { + let transaction: Transaction + let signature: Signature + let networkId: NetworkId? + init(transaction: Transaction, signature: Signature, networkId: NetworkId?) { + self.transaction = transaction + self.signature = signature + self.networkId = networkId + } + + func data() -> Data { + let data = TransactionDataWriter() + transaction.write(to: data) + if let networkId = networkId?.rawValue { + data.append(BigUInt(signature.v) + 35 + networkId + networkId) + } else { + data.append(BigUInt(signature.v) + 27) + } + data.append(signature.r) + data.append(signature.s) + return data.done() + } +} + +extension Data { + private func byte(_ value: Int) -> Data { + return Data([UInt8(value)]) + } + func length(offset: Int) -> Data { + guard !(count == 1 && self[0] < UInt8(offset)) else { return Data() } + let max = 0x37 + offset + guard count + offset > max else { return byte(count + offset) } + let serialized = BigUInt(count).serialize() + return byte(max + serialized.count) + serialized + } +} + +/// WIP +class TransactionDataWriter { + private(set) var data: Data + init() { + self.data = Data() + } + init(data: Data) { + self.data = data + } + + func append(_ value: BigUInt) { + _append(value.serialize()) + } + func append(_ value: Address) { + _append(value.addressData) + } + func _append(_ value: Data) { + data.append(value.length(offset: 0x80)) + data.append(value) + } + func append(_ value: Data) { + data.append(value.length(offset: 0x80)) + data.append(value) + } + + func done() -> Data { + data.replaceSubrange(0..<0, with: data.length(offset: 0xc0)) + return data + } +} diff --git a/Sources/Utils/EIP67Code.swift b/Sources/Utils/EIP67Code.swift index f8e7441..a3d233b 100644 --- a/Sources/Utils/EIP67Code.swift +++ b/Sources/Utils/EIP67Code.swift @@ -51,7 +51,7 @@ public struct EIP67Code { } else if let number = el.1 as? BigInt { return el.0.abiRepresentation + " " + String(number, radix: 10) } else if let data = el.1 as? Data { - return el.0.abiRepresentation + " " + data.toHexString().withHex + return el.0.abiRepresentation + " " + data.hex.withHex } return "" }).joined(separator: ", ") + ")" @@ -108,7 +108,7 @@ public struct EIP67Code { if let data = self.data { switch data { case let .data(d): - queryItems.append(URLQueryItem(name: "data", value: d.toHexString().withHex)) + queryItems.append(URLQueryItem(name: "data", value: d.hex.withHex)) case let .function(f): if let enc = f.toString() { queryItems.append(URLQueryItem(name: "function", value: enc)) diff --git a/Sources/Utils/RLP.swift b/Sources/Utils/RLP.swift index 556766e..28f3979 100644 --- a/Sources/Utils/RLP.swift +++ b/Sources/Utils/RLP.swift @@ -13,8 +13,8 @@ protocol ArrayType {} extension Array: ArrayType {} struct RLP { - static var length56 = BigUInt(UInt(56)) - static var lengthMax = (BigUInt(UInt(1)) << 256) + static var length56 = BigUInt(56) + static var lengthMax = (BigUInt(1) << 256) static func encode(_ element: AnyObject) -> Data? { if let string = element as? String { @@ -65,7 +65,7 @@ struct RLP { if data.count == 1 && data.bytes[0] < UInt8(0x80) { return data } else { - guard let length = encodeLength(data.count, offset: UInt8(0x80)) else { return nil } + guard let length = encodeLength(data.count, offset: 0x80) else { return nil } var encoded = Data() encoded.append(length) encoded.append(data) diff --git a/Sources/Web3/Web3+Eth.swift b/Sources/Web3/Web3+Eth.swift index 6ec65e1..43b8aba 100644 --- a/Sources/Web3/Web3+Eth.swift +++ b/Sources/Web3/Web3+Eth.swift @@ -266,7 +266,7 @@ public class Web3Eth: Web3OptionsInheritable { /// /// - Returns: Found Block public func getBlockByHashPromise(_ hash: Data, fullTransactions: Bool = false) -> Promise { - let hashString = hash.toHexString().withHex + let hashString = hash.hex.withHex return getBlockByHashPromise(hashString, fullTransactions: fullTransactions) } @@ -294,7 +294,7 @@ public class Web3Eth: Web3OptionsInheritable { /// - Returns: Transaction details for particular transaction hash. Details indicate position of the transaction in a particular block, /// as well as original transaction details such as value, gas limit, gas price, etc. public func getTransactionDetailsPromise(_ txhash: Data) -> Promise { - let hashString = txhash.toHexString().withHex + let hashString = txhash.hex.withHex return getTransactionDetailsPromise(hashString) } @@ -385,7 +385,7 @@ public class Web3Eth: Web3OptionsInheritable { /// was included in block, so it contains logs and status, such as succesful or failed transaction. /// - Important: This function is synchronous! public func getTransactionReceiptPromise(_ txhash: Data) -> Promise { - let hashString = txhash.toHexString().withHex + let hashString = txhash.hex.withHex return getTransactionReceiptPromise(hashString) } diff --git a/Sources/Web3/Web3+Personal.swift b/Sources/Web3/Web3+Personal.swift index 2d15af9..11f9c86 100644 --- a/Sources/Web3/Web3+Personal.swift +++ b/Sources/Web3/Web3+Personal.swift @@ -82,7 +82,7 @@ public class Web3Personal: Web3OptionsInheritable { let queue = web3.requestDispatcher.queue do { if web3.provider.attachedKeystoreManager.isEmpty { - let hexData = message.toHexString().withHex + let hexData = message.hex.withHex let request = JsonRpcRequest(method: .personalSign, parameters: from.address.lowercased(), hexData) return web3.dispatch(request).map(on: queue) { response in guard let value: Data = response.getValue() else { diff --git a/Sources/Web3/Web3+TransactionIntermediate.swift b/Sources/Web3/Web3+TransactionIntermediate.swift index 55833ce..6edbbea 100644 --- a/Sources/Web3/Web3+TransactionIntermediate.swift +++ b/Sources/Web3/Web3+TransactionIntermediate.swift @@ -298,11 +298,10 @@ public class TransactionIntermediate { callPromise.done(on: queue) { data in do { if self.method == "fallback" { - let resultHex = data.toHexString().withHex + let resultHex = data.hex.withHex let response = Web3Response(["result": resultHex as Any]) seal.fulfill(response) } else { - print(data.toHexString()) guard let decodedData = self.contract.decodeReturnData(self.method, data: data) else { throw Web3Error.processingError("Can not decode returned parameters") } @@ -311,9 +310,7 @@ public class TransactionIntermediate { } catch { seal.reject(error) } - }.catch(on: queue) { err in - seal.reject(err) - } + }.catch(on: queue, seal.reject) } return returnPromise } diff --git a/Sources/Web3/Web3+Utils.swift b/Sources/Web3/Web3+Utils.swift index 438077a..ee14e33 100644 --- a/Sources/Web3/Web3+Utils.swift +++ b/Sources/Web3/Web3+Utils.swift @@ -113,7 +113,7 @@ extension Web3Utils { stipped = stipped[1 ... 64] } guard stipped.count == 64 else { throw PublicKeyToAddressError.invalidPublicKeySize } - let sha3 = stipped.sha3(.keccak256) + let sha3 = stipped.keccak256() let addressData = sha3[12 ..< 32] return addressData } @@ -125,7 +125,7 @@ extension Web3Utils { /// Returns the Address object. public static func publicToAddress(_ publicKey: Data) throws -> Address { let addressData = try Web3Utils.publicToAddressData(publicKey) - let address = addressData.toHexString().withHex.lowercased() + let address = addressData.hex return Address(address) } @@ -135,7 +135,7 @@ extension Web3Utils { /// Returns a 0x prefixed hex string. public static func publicToAddressString(_ publicKey: Data) throws -> String { let addressData = try Web3Utils.publicToAddressData(publicKey) - let address = addressData.toHexString().withHex.lowercased() + let address = addressData.hex.withHex.lowercased() return address } @@ -159,7 +159,7 @@ extension Web3Utils { data.append(prefixData) data.append(personalMessage) } - return data.sha3(.keccak256) + return data.keccak256() } /// Parse a user-supplied string using the number of decimals for particular Ethereum unit. @@ -226,13 +226,13 @@ extension Web3Utils { /// returns Ethereum variant of sha3 (keccak256) of data. Returns nil is data is empty public static func keccak256(_ data: Data) -> Data? { if data.count == 0 { return nil } - return data.sha3(.keccak256) + return data.keccak256() } /// returns Ethereum variant of sha3 (keccak256) of data. Returns nil is data is empty public static func sha3(_ data: Data) -> Data? { if data.count == 0 { return nil } - return data.sha3(.keccak256) + return data.keccak256() } /// returns sha256 of data. Returns nil is data is empty diff --git a/Tests/ABITests.swift b/Tests/ABITests.swift index af302f0..c560c05 100644 --- a/Tests/ABITests.swift +++ b/Tests/ABITests.swift @@ -76,8 +76,8 @@ class ABITests: XCTestCase { let data = ABIv2Encoder.encode(types: types, values: [BigUInt(69), true] as [AnyObject]) XCTAssert(data != nil, "failed to encode") let expected = "0x00000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001" - print(data!.toHexString().lowercased()) - XCTAssert(data?.toHexString().lowercased().withHex == expected, "failed to encode") + print(data!.hex.lowercased()) + XCTAssert(data?.hex.lowercased().withHex == expected, "failed to encode") } func testABIv2encoding2() { @@ -87,8 +87,8 @@ class ABITests: XCTestCase { let data = ABIv2Encoder.encode(types: types, values: ["dave"] as [AnyObject]) XCTAssert(data != nil, "failed to encode") let expected = "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000046461766500000000000000000000000000000000000000000000000000000000" - print(data!.toHexString().lowercased()) - XCTAssert(data?.toHexString().lowercased().withHex == expected, "failed to encode") + print(data!.hex.lowercased()) + XCTAssert(data?.hex.lowercased().withHex == expected, "failed to encode") } func testABIv2encoding3() { @@ -103,8 +103,8 @@ class ABITests: XCTestCase { let data = ABIv2Encoder.encode(types: types, values: ["dave".data, true, [BigUInt(1), BigUInt(2), BigUInt(3)]] as [AnyObject]) XCTAssert(data != nil, "failed to encode") let expected = "0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003" - print(data!.toHexString().lowercased()) - XCTAssert(data?.toHexString().lowercased().withHex == expected, "failed to encode") + print(data!.hex.lowercased()) + XCTAssert(data?.hex.lowercased().withHex == expected, "failed to encode") } func testABIv2encoding4() { @@ -117,7 +117,7 @@ class ABITests: XCTestCase { values: [number!] as [AnyObject]) XCTAssertNotNil(data, "failed to encode") let expected = "0xfffffffffffff38dd0f10627f5529bdb2c52d4846810af0ac000000000000001" - let result = data!.toHexString().lowercased().withHex + let result = data!.hex.lowercased().withHex print(result) XCTAssert(result == expected, "failed to encode") } @@ -132,8 +132,8 @@ class ABITests: XCTestCase { values: [string] as [AnyObject]) XCTAssertNotNil(data, "failed to encode") let expected = "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c22068656c6c6f20776f726c642068656c6c6f20776f726c642068656c6c6f20776f726c642068656c6c6f20776f726c64202068656c6c6f20776f726c642068656c6c6f20776f726c642068656c6c6f20776f726c642068656c6c6f20776f726c64202068656c6c6f20776f726c642068656c6c6f20776f726c642068656c6c6f20776f726c642068656c6c6f20776f726c642068656c6c6f20776f726c642068656c6c6f20776f726c642068656c6c6f20776f726c642068656c6c6f20776f726c64000000000000000000000000000000000000000000000000000000000000" - print(data!.toHexString().lowercased().withHex) - XCTAssert(data?.toHexString().lowercased().withHex == expected, "failed to encode") + print(data!.hex.lowercased().withHex) + XCTAssert(data?.hex.lowercased().withHex == expected, "failed to encode") } func testABIv2encoding6() { @@ -150,8 +150,8 @@ class ABITests: XCTestCase { "Hello, world!"] as [AnyObject]) XCTAssert(data != nil, "failed to encode") let expected = "0x00000000000000000000000000000000000000000000000000000000000001230000000000000000000000000000000000000000000000000000000000000080313233343536373839300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004560000000000000000000000000000000000000000000000000000000000000789000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000" - print(data!.toHexString().lowercased()) - XCTAssert(data?.toHexString().lowercased().withHex == expected, "failed to encode") + print(data!.hex.lowercased()) + XCTAssert(data?.hex.lowercased().withHex == expected, "failed to encode") } func testABIv2encoding7() { @@ -162,8 +162,8 @@ class ABITests: XCTestCase { values: [["Hello", "World"]] as [AnyObject]) XCTAssert(data != nil, "failed to encode") let expected = "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000" - print(data!.toHexString().lowercased()) - XCTAssert(data?.toHexString().lowercased() == expected, "failed to encode") + print(data!.hex.lowercased()) + XCTAssert(data?.hex.lowercased() == expected, "failed to encode") } func testABIv2encoding8() { @@ -174,8 +174,8 @@ class ABITests: XCTestCase { values: [["Hello", "World"]] as [AnyObject]) XCTAssert(data != nil, "failed to encode") let expected = "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000" - print(data!.toHexString().lowercased()) - XCTAssert(data?.toHexString().lowercased() == expected, "failed to encode") + print(data!.hex.lowercased()) + XCTAssert(data?.hex.lowercased() == expected, "failed to encode") } func testABIv2Decoding1() { diff --git a/Tests/BetterABI/BetterERC20Tests.swift b/Tests/BetterABI/BetterERC20Tests.swift index e631dd0..a57d13f 100644 --- a/Tests/BetterABI/BetterERC20Tests.swift +++ b/Tests/BetterABI/BetterERC20Tests.swift @@ -24,7 +24,7 @@ class BetterERC20Tests: XCTestCase { let amount = BigUInt(10).power(18) let arguments: [SolidityDataRepresentable] = [user, amount] let request = arguments.data(function: "transfer(address,uint256)") - XCTAssertEqual(request.toHexString(), "a9059cbb0000000000000000000000006a6a0b4aaa60e97386f94c5414522159b45dede80000000000000000000000000000000000000000000000000de0b6b3a7640000") + XCTAssertEqual(request.hex, "a9059cbb0000000000000000000000006a6a0b4aaa60e97386f94c5414522159b45dede80000000000000000000000000000000000000000000000000de0b6b3a7640000") let response = BigUInt(1).solidityData let success = try SolidityDataReader(response).bool() diff --git a/Tests/ERC20Tests.swift b/Tests/ERC20Tests.swift index 0a2675f..e69b044 100644 --- a/Tests/ERC20Tests.swift +++ b/Tests/ERC20Tests.swift @@ -32,7 +32,7 @@ class ERC20Tests: XCTestCase { let parameters = [address, amount] as [AnyObject] let result = method[0].encodeParameters(parameters) print(abiNative) - let hex = result!.toHexString() + let hex = result!.hex print(hex) XCTAssert(hex == "a9059cbb000000000000000000000000e6877a4d8806e9a9f12eb2e8561ea6c1db19978d0000000000000000000000000000000000000000000000000de0b6b3a7640000", "Failed to encode ERC20") let dummyTrue = BigUInt(1).abiEncode(bits: 256) diff --git a/Tests/KeystoreTests.swift b/Tests/KeystoreTests.swift index 0d58b40..8419c66 100644 --- a/Tests/KeystoreTests.swift +++ b/Tests/KeystoreTests.swift @@ -6,8 +6,8 @@ // Copyright © 2018 Bankex Foundation. All rights reserved. // -import CryptoSwift import XCTest +import Cryptor @testable import web3swift @@ -20,13 +20,13 @@ class KeystoresTests: XCTestCase { XCTAssertEqual(mnemonics.string, "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about") mnemonics.password = "TREZOR" var seed = mnemonics.seed() - XCTAssert(seed.toHexString() == "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04") + XCTAssert(seed.hex == "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04") entropy = Data.fromHex("68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c")! mnemonics = try Mnemonics(entropy: entropy) XCTAssertEqual(mnemonics.string, "hamster diagram private dutch cause delay private meat slide toddler razor book happy fancy gospel tennis maple dilemma loan word shrug inflict delay length") mnemonics.password = "TREZOR" seed = mnemonics.seed() - XCTAssert(seed.toHexString() == "64c87cde7e12ecf6704ab95bb1408bef047c22db4cc7491c4271d170a1b213d20b385bc1588d9c7b38f1b39d415665b8a9030c9ec653d75e65f847d8fc1fc440") + XCTAssert(seed.hex == "64c87cde7e12ecf6704ab95bb1408bef047c22db4cc7491c4271d170a1b213d20b385bc1588d9c7b38f1b39d415665b8a9030c9ec653d75e65f847d8fc1fc440") } func testImportAndExport() throws { @@ -35,11 +35,11 @@ class KeystoresTests: XCTestCase { """ let keystore = EthereumKeystoreV3(json)! let data = try keystore.serialize()! - let key = try keystore.UNSAFE_getPrivateKeyData(password: "hello world", account: keystore.addresses[0]).toHexString() + let key = try keystore.UNSAFE_getPrivateKeyData(password: "hello world", account: keystore.addresses[0]).hex let keystore2 = EthereumKeystoreV3(data)! let data2 = try keystore2.serialize()! - let key2 = try keystore2.UNSAFE_getPrivateKeyData(password: "hello world", account: keystore.addresses[0]).toHexString() + let key2 = try keystore2.UNSAFE_getPrivateKeyData(password: "hello world", account: keystore.addresses[0]).hex XCTAssertEqual(data,data2) XCTAssertEqual(key,key2) @@ -49,8 +49,8 @@ class KeystoresTests: XCTestCase { // 0.0021849870681762695 sec to complete let seed = Data.fromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")! let data = Data.fromHex("4869205468657265")! - let hmac = try! HMAC(key: seed.bytes, variant: HMAC.Variant.sha512).authenticate(data.bytes) - XCTAssert(Data(hmac).toHexString() == "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854") + let hmac = try! HMAC(key: seed.bytes, variant: .sha512).authenticate(data.bytes) + XCTAssert(Data(hmac).hex == "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854") } func testMnemonicsWithAllLanguagesAndEntropySizes() { @@ -84,11 +84,11 @@ class KeystoresTests: XCTestCase { func testBIP32keystoreExportPrivateKey() throws { // 6.153380036354065 sec to complete - let mnemonics = try Mnemonics("normal dune pole key case cradle unfold require tornado mercy hospital buyer") - let keystore = try BIP32Keystore(mnemonics: mnemonics, password: "") + let mnemonics = try! Mnemonics("normal dune pole key case cradle unfold require tornado mercy hospital buyer") + let keystore = try! BIP32Keystore(mnemonics: mnemonics, password: "") XCTAssertNotNil(keystore) let account = keystore.addresses[0] - _ = try keystore.UNSAFE_getPrivateKeyData(password: "", account: account) + _ = try! keystore.UNSAFE_getPrivateKeyData(password: "", account: account) } func testBIP32keystoreMatching() throws { @@ -99,7 +99,7 @@ class KeystoresTests: XCTestCase { let account = keystore.addresses[0] let privateKey = try keystore.UNSAFE_getPrivateKeyData(password: "", account: account) let publicKey = try Web3Utils.privateToPublic(privateKey, compressed: true) - XCTAssertEqual(publicKey.toHexString(), "027160bd3a4d938cac609ff3a11fe9233de7b76c22a80d2b575e202cbf26631659") + XCTAssertEqual(publicKey.hex, "027160bd3a4d938cac609ff3a11fe9233de7b76c22a80d2b575e202cbf26631659") } func testBIP32keystoreMatchingRootNode() throws { @@ -120,7 +120,7 @@ class KeystoresTests: XCTestCase { let account = keystore.addresses[0] let key = try keystore.UNSAFE_getPrivateKeyData(password: "", account: account) let pubKey = try Web3Utils.privateToPublic(key, compressed: true) - XCTAssertEqual(pubKey.toHexString(), "027160bd3a4d938cac609ff3a11fe9233de7b76c22a80d2b575e202cbf26631659") + XCTAssertEqual(pubKey.hex, "027160bd3a4d938cac609ff3a11fe9233de7b76c22a80d2b575e202cbf26631659") } func testByBIP32keystoreCreateChildAccount() throws { @@ -169,14 +169,14 @@ class KeystoresTests: XCTestCase { // let pass = "passDATAb00AB7YxDTTl".data // let salt = "saltKEYbcTcXHCBxtjD2".data // let dataArray = try? PKCS5.PBKDF2(password: pass.bytes, salt: salt.bytes, iterations: 100000, keyLength: 65, variant: HMAC.Variant.sha512).calculate() - // XCTAssert(Data(dataArray!).toHexString().withHex.lowercased() == "0x594256B0BD4D6C9F21A87F7BA5772A791A10E6110694F44365CD94670E57F1AECD797EF1D1001938719044C7F018026697845EB9AD97D97DE36AB8786AAB5096E7".lowercased()) + // XCTAssert(Data(dataArray!).hex.withHex.lowercased() == "0x594256B0BD4D6C9F21A87F7BA5772A791A10E6110694F44365CD94670E57F1AECD797EF1D1001938719044C7F018026697845EB9AD97D97DE36AB8786AAB5096E7".lowercased()) // } func testRIPEMD() { // sec to complete let data = "message digest".data(using: .ascii) let hash = RIPEMD160.hash(message: data!) - XCTAssert(hash.toHexString() == "5d0689ef49d2fae572b881b123a85ffa21595f36") + XCTAssert(hash.hex == "5d0689ef49d2fae572b881b123a85ffa21595f36") } func testHD32() throws { @@ -204,7 +204,7 @@ class KeystoresTests: XCTestCase { XCTAssert(nextNode.index == UInt32(0)) XCTAssert(nextNode.isHardened == false) XCTAssert(nextNode.parentFingerprint == Data.fromHex("3442193e")) - XCTAssert(nextNode.publicKey.toHexString() == "027c4b09ffb985c298afe7e5813266cbfcb7780b480ac294b0b43dc21f2be3d13c") + XCTAssert(nextNode.publicKey.hex == "027c4b09ffb985c298afe7e5813266cbfcb7780b480ac294b0b43dc21f2be3d13c") XCTAssert(nextNode.serializeToString() == "xpub68Gmy5EVb2BdFbj2LpWrk1M7obNuaPTpT5oh9QCCo5sRfqSHVYWex97WpDZzszdzHzxXDAzPLVSwybe4uPYkSk4G3gnrPqqkV9RyNzAcNJ1") XCTAssert(nextNode.serializeToString(serializePublic: false) == "xprv9uHRZZhbkedL37eZEnyrNsQPFZYRAvjy5rt6M1nbEkLSo378x1CQQLo2xxBvREwiK6kqf7GRNvsNEchwibzXaV6i5GcsgyjBeRguXhKsi4R") @@ -213,7 +213,7 @@ class KeystoresTests: XCTestCase { XCTAssert(nextNodeHardened.index == UInt32(0)) XCTAssert(nextNodeHardened.isHardened == true) XCTAssert(nextNodeHardened.parentFingerprint == Data.fromHex("3442193e")) - XCTAssert(nextNodeHardened.publicKey.toHexString() == "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56") + XCTAssert(nextNodeHardened.publicKey.hex == "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56") XCTAssert(nextNodeHardened.serializeToString() == "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw") XCTAssert(nextNodeHardened.serializeToString(serializePublic: false) == "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7") diff --git a/Tests/RLPTests.swift b/Tests/RLPTests.swift index 52ee26e..b7ff541 100644 --- a/Tests/RLPTests.swift +++ b/Tests/RLPTests.swift @@ -8,9 +8,36 @@ import BigInt import XCTest - @testable import web3swift + class RLPTests: XCTestCase { + func testNewRlp() throws { + let data = try SolidityFunction(function: "doSome(uint256,uint256)").encode(0x123,0x456) + + let address: Address = "0x6a6a0b4aaa60E97386F94c5414522159b45DEdE8" + var transaction = EthereumTransaction(gasPrice: 0x12345, gasLimit: 0x123123, to: address, value: 0, data: data) + transaction.chainID = .mainnet + + let keystore = try! EthereumKeystoreV3(password: "")! + let privateKey = try! keystore.UNSAFE_getPrivateKeyData(password: "", account: keystore.address!) + + let transaction2 = Transaction(gasPrice: 0x12345, gasLimit: 0x123123, to: address, value: 0, data: data) + let dataWriter = TransactionDataWriter() + transaction2.write(to: dataWriter) + transaction2.write(networkId: .mainnet, to: dataWriter) + + + let unsigned1 = transaction.encode(forSignature: false, chainId: .mainnet)!.hex + let unsigned2 = dataWriter.done().hex + XCTAssertEqual(unsigned1, unsigned2) + + try! Web3Signer.signTX(transaction: &transaction, keystore: keystore, account: keystore.address!, password: "") + + let signed1 = transaction.encode(forSignature: false, chainId: .mainnet)!.hex + let signed2 = try! transaction2.sign(using: PrivateKey(privateKey), networkId: .mainnet).data().hex + XCTAssertEqual(signed1, signed2) + } + func testRLPencodeShortString() { let testString = "dog" let encoded = RLP.encode(testString) diff --git a/Tests/RemoteParsingTests.swift b/Tests/RemoteParsingTests.swift index 496cdb8..e8d7d5c 100644 --- a/Tests/RemoteParsingTests.swift +++ b/Tests/RemoteParsingTests.swift @@ -28,7 +28,7 @@ class RemoteParsingTests: XCTestCase { XCTAssert(decoded["_from"] as! Address == "0xdbf493e8d7db835192c02b992bd1ab72e96fd2e3") XCTAssert(decoded["_value"] as! BigUInt == BigUInt("3946fe37ffce3a0000", radix: 16)!) XCTAssert(pres[0].contractAddress == "0x45245bc59219eeaaf6cd3f382e078a461ff9de7b") - XCTAssert(pres[0].transactionReceipt!.transactionHash.toHexString().withHex == "0xcb235e8c6ecda032bc82c1084d2159ab82e7e4de35be703da6e80034bc577673") + XCTAssert(pres[0].transactionReceipt!.transactionHash.hex.withHex == "0xcb235e8c6ecda032bc82c1084d2159ab82e7e4de35be703da6e80034bc577673") } func testEventParsing2usingABIv2() throws { @@ -52,7 +52,7 @@ class RemoteParsingTests: XCTestCase { for p in present { print("Block " + String(i) + "\n") print("Emitted by contract " + p.contractAddress.address + "\n") - print("TX hash " + p.transactionReceipt!.transactionHash.toHexString().withHex + "\n") + print("TX hash " + p.transactionReceipt!.transactionHash.hex.withHex + "\n") print("From " + (p.decodedResult["_from"] as! Address).address + "\n") print("From " + (p.decodedResult["_to"] as! Address).address + "\n") print("Value " + String(p.decodedResult["_value"] as! BigUInt) + "\n") diff --git a/Tests/RinkebyPersonalSignatureTests.swift b/Tests/RinkebyPersonalSignatureTests.swift index 926f09a..caec04c 100644 --- a/Tests/RinkebyPersonalSignatureTests.swift +++ b/Tests/RinkebyPersonalSignatureTests.swift @@ -24,9 +24,9 @@ class RinkebyPersonalSignatureTests: XCTestCase { let signature = try web3.personal.signPersonalMessage(message: message, from: expectedAddress, password: "") let unmarshalledSignature = try SECP256K1.unmarshalSignature(signatureData: signature) print("V = " + String(unmarshalledSignature.v)) - print("R = " + Data(unmarshalledSignature.r).toHexString()) - print("S = " + Data(unmarshalledSignature.s).toHexString()) - try! print("Personal hash = " + Web3Utils.hashPersonalMessage(message).toHexString()) + print("R = " + Data(unmarshalledSignature.r).hex) + print("S = " + Data(unmarshalledSignature.s).hex) + try! print("Personal hash = " + Web3Utils.hashPersonalMessage(message).hex) let signer = try web3.personal.ecrecover(personalMessage: message, signature: signature) XCTAssert(expectedAddress == signer, "Failed to sign personal message") } @@ -43,9 +43,9 @@ class RinkebyPersonalSignatureTests: XCTestCase { let signature = try web3.personal.signPersonalMessage(message: messageData, from: expectedAddress, password: "") let unmarshalledSignature = try SECP256K1.unmarshalSignature(signatureData: signature) print("V = " + String(unmarshalledSignature.v)) - print("R = " + Data(unmarshalledSignature.r).toHexString()) - print("S = " + Data(unmarshalledSignature.s).toHexString()) - try print("Personal hash = " + Web3Utils.hashPersonalMessage(messageData).toHexString()) + print("R = " + Data(unmarshalledSignature.r).hex) + print("S = " + Data(unmarshalledSignature.s).hex) + try print("Personal hash = " + Web3Utils.hashPersonalMessage(messageData).hex) let jsonString = "[{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"constant\":true,\"inputs\":[{\"name\":\"_message\",\"type\":\"string\"}],\"name\":\"hashPersonalMessage\",\"outputs\":[{\"name\":\"hash\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_message\",\"type\":\"string\"},{\"name\":\"v\",\"type\":\"uint8\"},{\"name\":\"r\",\"type\":\"bytes32\"},{\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"recoverSigner\",\"outputs\":[{\"name\":\"signer\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"}]" let contract = try web3.contract(jsonString, at: "0x6f1745a39059268e8e4572e97897b50e4aab62a8") var options = Web3Options.default diff --git a/Tests/SECP256K1Tests.swift b/Tests/SECP256K1Tests.swift index 7f7e017..e695287 100644 --- a/Tests/SECP256K1Tests.swift +++ b/Tests/SECP256K1Tests.swift @@ -6,10 +6,7 @@ // Copyright © 2018 Bankex Foundation. All rights reserved. // -import XCTest - import BigInt -import CryptoSwift import XCTest @testable import web3swift diff --git a/Tests/ScryptTests.swift b/Tests/ScryptTests.swift index 12e4053..480291b 100644 --- a/Tests/ScryptTests.swift +++ b/Tests/ScryptTests.swift @@ -6,7 +6,6 @@ // Copyright © 2018 Bankex Foundation. All rights reserved. // -import CryptoSwift import Foundation import XCTest diff --git a/Tests/TransactionTests.swift b/Tests/TransactionTests.swift index 6143a37..0de685c 100644 --- a/Tests/TransactionTests.swift +++ b/Tests/TransactionTests.swift @@ -31,7 +31,7 @@ class TransactionsTests: XCTestCase { print(transaction) let hash = transaction.hashForSignature(chainID: 1) let expectedHash = "0xdaf5a779ae972f972197303d7b574746c7ef83eadac0f2791ad23db92e4c8e53".withoutHex - XCTAssert(hash!.toHexString() == expectedHash, "Transaction signature failed") + XCTAssert(hash!.hex == expectedHash, "Transaction signature failed") try Web3Signer.EIP155Signer.sign(transaction: &transaction, privateKey: privateKeyData, useExtraEntropy: false) print(transaction) XCTAssert(transaction.v == 37, "Transaction signature failed") diff --git a/web3swift.podspec b/web3swift.podspec index 51cf47a..8602a01 100644 --- a/web3swift.podspec +++ b/web3swift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'web3swift' - spec.version = '2.0.9' + spec.version = '2.1' spec.ios.deployment_target = "8.0" spec.osx.deployment_target = "10.10" spec.tvos.deployment_target = "9.0" @@ -15,4 +15,5 @@ Pod::Spec.new do |spec| spec.dependency 'BigInt', '~> 3.1' spec.dependency 'CryptoSwift', '~> 0.12' spec.dependency 'secp256k1.swift' + spec.dependency 'BlueCryptor', :git => 'https://github.com/v57/BlueCryptor.git' end diff --git a/web3swift.xcodeproj/project.pbxproj b/web3swift.xcodeproj/project.pbxproj index adc9995..9ed4bae 100644 --- a/web3swift.xcodeproj/project.pbxproj +++ b/web3swift.xcodeproj/project.pbxproj @@ -119,8 +119,10 @@ 13975204219AFA6D0044D2B0 /* ERC20Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1317BDE7218C526C00D6D095 /* ERC20Tests.swift */; }; 13975205219AFA6D0044D2B0 /* TransactionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1317BDE9218C526C00D6D095 /* TransactionTests.swift */; }; 13975206219AFA6D0044D2B0 /* SECP256K1Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1317BDEA218C526C00D6D095 /* SECP256K1Tests.swift */; }; + 139947F221B0586200EA5DB6 /* PrivateKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 139947F121B0586200EA5DB6 /* PrivateKey.swift */; }; + 13A93F5A21B0A36900F115E4 /* AES.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13A93F5921B0A36900F115E4 /* AES.swift */; }; + 13A93F6021B172D900F115E4 /* Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13A93F5F21B172D900F115E4 /* Transaction.swift */; }; 13AC5D3E21A5D109009D0309 /* SolidityDataReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13AC5D3D21A5D109009D0309 /* SolidityDataReader.swift */; }; - 13BBADB121AD38DA0017F55F /* Accounts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13BBADB021AD38DA0017F55F /* Accounts.swift */; }; 13D2576E21ADCD4400D382D1 /* DerivedKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13D2576D21ADCD4400D382D1 /* DerivedKey.swift */; }; /* End PBXBuildFile section */ @@ -246,8 +248,10 @@ 13765D6921964A9B005C483C /* W3Transaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = W3Transaction.swift; sourceTree = ""; }; 139751B7219AF76D0044D2B0 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 139751B9219AF76D0044D2B0 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; }; + 139947F121B0586200EA5DB6 /* PrivateKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateKey.swift; sourceTree = ""; }; + 13A93F5921B0A36900F115E4 /* AES.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AES.swift; sourceTree = ""; }; + 13A93F5F21B172D900F115E4 /* Transaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Transaction.swift; sourceTree = ""; }; 13AC5D3D21A5D109009D0309 /* SolidityDataReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolidityDataReader.swift; sourceTree = ""; }; - 13BBADB021AD38DA0017F55F /* Accounts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Accounts.swift; sourceTree = ""; }; 13D2576D21ADCD4400D382D1 /* DerivedKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DerivedKey.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -298,8 +302,8 @@ children = ( 133E673A219EFE630054758F /* Guides.swift */, 1317BD58218C526300D6D095 /* Migration.swift */, + 13A93F5D21B172A800F115E4 /* Transactions */, 133E696521A6B8940054758F /* Migration-iOS.swift */, - 13BBADAF21AD38C20017F55F /* Keystore */, 13D2577021ADEE3D00D382D1 /* Encryption */, 133970582199D22A0027E27C /* Deprecated */, 1317BCFE218C526300D6D095 /* Transaction */, @@ -413,10 +417,6 @@ 1317BD41218C526300D6D095 /* ABIv2Decoding.swift */, 1317BD42218C526300D6D095 /* ABIv2ParameterTypes.swift */, 1317BD44218C526300D6D095 /* ABIv2Encoding.swift */, - 1317BD43218C526300D6D095 /* SolidityFunction.swift */, - 13AC5D3D21A5D109009D0309 /* SolidityDataReader.swift */, - 1317BD45218C526300D6D095 /* SolidityDataWriter.swift */, - 1317BD46218C526300D6D095 /* SolidityTypes.swift */, ); path = ABIv2; sourceTree = ""; @@ -444,9 +444,9 @@ children = ( 1317BD5A218C526300D6D095 /* RIPEMD160+StackOveflow.swift */, 1317BD5B218C526300D6D095 /* UInt256.swift */, - 1317BD5C218C526300D6D095 /* CryptoExtensions.swift */, 1317BD5D218C526300D6D095 /* String+Extension.swift */, 1317BD5E218C526300D6D095 /* LibSecp256k1Extension.swift */, + 1317BD5C218C526300D6D095 /* CryptoExtensions.swift */, 1317BD5F218C526300D6D095 /* NSRegularExpressionExtension.swift */, 1317BD61218C526300D6D095 /* Data+Extension.swift */, 1317BD62218C526300D6D095 /* NativeTypesEncoding+Extensions.swift */, @@ -527,18 +527,24 @@ path = Deprecated; sourceTree = ""; }; - 13BBADAF21AD38C20017F55F /* Keystore */ = { + 13A93F5D21B172A800F115E4 /* Transactions */ = { isa = PBXGroup; children = ( - 13BBADB021AD38DA0017F55F /* Accounts.swift */, + 1317BD43218C526300D6D095 /* SolidityFunction.swift */, + 13AC5D3D21A5D109009D0309 /* SolidityDataReader.swift */, + 1317BD45218C526300D6D095 /* SolidityDataWriter.swift */, + 1317BD46218C526300D6D095 /* SolidityTypes.swift */, + 13A93F5F21B172D900F115E4 /* Transaction.swift */, ); - path = Keystore; + path = Transactions; sourceTree = ""; }; 13D2577021ADEE3D00D382D1 /* Encryption */ = { isa = PBXGroup; children = ( + 13A93F5921B0A36900F115E4 /* AES.swift */, 13D2576D21ADCD4400D382D1 /* DerivedKey.swift */, + 139947F121B0586200EA5DB6 /* PrivateKey.swift */, ); path = Encryption; sourceTree = ""; @@ -691,6 +697,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 13A93F6021B172D900F115E4 /* Transaction.swift in Sources */, 133E696621A6B8940054758F /* Migration-iOS.swift in Sources */, 1317BDBF218C526300D6D095 /* UInt256.swift in Sources */, 13765D6F21964A9B005C483C /* W3Web3.swift in Sources */, @@ -738,8 +745,8 @@ 1317BDA7218C526300D6D095 /* ABIv2TypeParser.swift in Sources */, 1317BDAF218C526300D6D095 /* BlockExplorer.swift in Sources */, 1317BDAC218C526300D6D095 /* SolidityDataWriter.swift in Sources */, - 13BBADB121AD38DA0017F55F /* Accounts.swift in Sources */, 1317BD83218C526300D6D095 /* Web3+Protocols.swift in Sources */, + 13A93F5A21B0A36900F115E4 /* AES.swift in Sources */, 1317BD85218C526300D6D095 /* Web3+Eth.swift in Sources */, 1317BD70218C526300D6D095 /* TransactionSigner.swift in Sources */, 13397055219984480027E27C /* SecurityToken.swift in Sources */, @@ -770,6 +777,7 @@ 1317BDBE218C526300D6D095 /* RIPEMD160+StackOveflow.swift in Sources */, 1317BDC2218C526300D6D095 /* LibSecp256k1Extension.swift in Sources */, 1317BD71218C526300D6D095 /* EthereumTransaction.swift in Sources */, + 139947F221B0586200EA5DB6 /* PrivateKey.swift in Sources */, 1317BD8B218C526300D6D095 /* EIP67Code.swift in Sources */, 1317BD88218C526300D6D095 /* Web3+Structures.swift in Sources */, 1317BD81218C526300D6D095 /* Web3+Contract.swift in Sources */, @@ -875,6 +883,7 @@ MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; + SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos watchos watchsimulator"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.2; @@ -935,6 +944,7 @@ MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; + SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos watchos watchsimulator"; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 4.2;