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)
@@ -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;