Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift4.2 #168

Merged
merged 11 commits into from
Sep 11, 2019
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ playground.xcworkspace
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
Package.resolved
.build/

# CocoaPods
Expand Down
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
language: objective-c
osx_image: xcode9.4
osx_image: xcode10
cache:
directories:
- Libraries
script:
- xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME" -configuration "$CONFIGURATION"
-sdk "$SDK" -destination "$DESTINATION" -derivedDataPath build
-enableCodeCoverage YES ENABLE_TESTABILITY=YES "$ACTION"
- swift -version
- swift test
after_success:
- ruby scripts/coverage.rb "$SCHEME"
Expand Down
12 changes: 8 additions & 4 deletions BitcoinKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
2949920220F228B400D078B6 /* UnspentTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2949920120F228B400D078B6 /* UnspentTransaction.swift */; };
2949920420F22A1500D078B6 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2949920320F22A1500D078B6 /* TestHelpers.swift */; };
2949920620F22DCA00D078B6 /* UnsignedTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2949920520F22DCA00D078B6 /* UnsignedTransaction.swift */; };
294D6CB6215A124700B75928 /* SerializationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294D6CB5215A124700B75928 /* SerializationTests.swift */; };
294DDE32211A05D200B7F645 /* OP_RETURN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294DDE31211A05D200B7F645 /* OP_RETURN.swift */; };
294DDE3B211B31B100B7F645 /* OP_NOP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294DDE3A211B31B100B7F645 /* OP_NOP.swift */; };
294DDE3D211B31C100B7F645 /* OP_VER.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294DDE3C211B31C100B7F645 /* OP_VER.swift */; };
Expand Down Expand Up @@ -384,6 +385,7 @@
2949920120F228B400D078B6 /* UnspentTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnspentTransaction.swift; sourceTree = "<group>"; };
2949920320F22A1500D078B6 /* TestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = "<group>"; };
2949920520F22DCA00D078B6 /* UnsignedTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsignedTransaction.swift; sourceTree = "<group>"; };
294D6CB5215A124700B75928 /* SerializationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SerializationTests.swift; sourceTree = "<group>"; };
294DDE31211A05D200B7F645 /* OP_RETURN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OP_RETURN.swift; sourceTree = "<group>"; };
294DDE3A211B31B100B7F645 /* OP_NOP.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OP_NOP.swift; sourceTree = "<group>"; };
294DDE3C211B31C100B7F645 /* OP_VER.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OP_VER.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -577,6 +579,7 @@
6E20AED62112D417008A9810 /* MurmurHashTests.swift */,
6E797C442116C8A5003BEDFD /* OpCodeFactoryTests.swift */,
29089F0D2122BE7200E0C305 /* MockHelperTests.swift */,
294D6CB5215A124700B75928 /* SerializationTests.swift */,
);
name = BitcoinKitTests;
path = Tests/BitcoinKitTests;
Expand Down Expand Up @@ -1235,6 +1238,7 @@
29F5D1E02110495F007DA3BF /* OpCodeTests.swift in Sources */,
6E20AEC92112C31A008A9810 /* LegacyAddressTests.swift in Sources */,
6E20AED12112C6AA008A9810 /* PaymentURITests.swift in Sources */,
294D6CB6215A124700B75928 /* SerializationTests.swift in Sources */,
CF432AF220F0CF9100AD4020 /* Base58Tests.swift in Sources */,
2949920420F22A1500D078B6 /* TestHelpers.swift in Sources */,
29F5D1E421106772007DA3BF /* BigNumberTests.swift in Sources */,
Expand Down Expand Up @@ -1404,7 +1408,7 @@
SKIP_INSTALL = YES;
SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Libraries";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
Expand Down Expand Up @@ -1442,7 +1446,7 @@
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Libraries";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
Expand All @@ -1462,7 +1466,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.bitcoinkit.BitcoinKitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
Expand All @@ -1482,7 +1486,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.bitcoinkit.BitcoinKitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
Expand Down
4 changes: 2 additions & 2 deletions BitcoinKit/BitcoinKitPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ NS_ASSUME_NONNULL_BEGIN
@interface _HDKey : NSObject

@property (nonatomic, readonly, nullable) NSData *privateKey;
@property (nonatomic, readonly, nullable) NSData *publicKey;
@property (nonatomic, readonly) NSData *publicKey;
@property (nonatomic, readonly) NSData *chainCode;
@property (nonatomic, readonly) uint8_t depth;
@property (nonatomic, readonly) uint32_t fingerprint;
@property (nonatomic, readonly) uint32_t childIndex;

- (instancetype)initWithPrivateKey:(nullable NSData *)privateKey publicKey:(nullable NSData *)publicKey chainCode:(NSData *)chainCode depth:(uint8_t)depth fingerprint:(uint32_t)fingerprint childIndex:(uint32_t)childIndex;
- (instancetype)initWithPrivateKey:(nullable NSData *)privateKey publicKey:(NSData *)publicKey chainCode:(NSData *)chainCode depth:(uint8_t)depth fingerprint:(uint32_t)fingerprint childIndex:(uint32_t)childIndex;
- (nullable _HDKey *)derivedAtIndex:(uint32_t)childIndex hardened:(BOOL)hardened;

@end
Expand Down
2 changes: 1 addition & 1 deletion Sources/BitcoinKit/Core/Keys/HDPublicKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public class HDPublicKey {
guard let derivedKey = _HDKey(privateKey: nil, publicKey: raw, chainCode: chainCode, depth: depth, fingerprint: fingerprint, childIndex: childIndex).derived(at: index, hardened: false) else {
throw DerivationError.derivationFailed
}
return HDPublicKey(raw: derivedKey.publicKey!, chainCode: derivedKey.chainCode, network: network, depth: derivedKey.depth, fingerprint: derivedKey.fingerprint, childIndex: derivedKey.childIndex)
return HDPublicKey(raw: derivedKey.publicKey, chainCode: derivedKey.chainCode, network: network, depth: derivedKey.depth, fingerprint: derivedKey.fingerprint, childIndex: derivedKey.childIndex)
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/BitcoinKit/Core/Keys/QRCodeGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public struct QRCodeGenerator {
"inputMessage": string.data(using: .utf8)!,
"inputCorrectionLevel": "L"
]
guard let image = CIFilter(name: "CIQRCodeGenerator", withInputParameters: parameters)?.outputImage else {
guard let image = CIFilter(name: "CIQRCodeGenerator", parameters: parameters)?.outputImage else {
return nil
}

Expand Down
6 changes: 5 additions & 1 deletion Sources/BitcoinKit/Core/Serialization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ extension Data {
}

func to<T>(type: T.Type) -> T {
return self.withUnsafeBytes { $0.pointee }
var data = self
while data.count < MemoryLayout<T>.size {
data.append(0)
}
return data.withUnsafeBytes { $0.pointee }
}

func to(type: String.Type) -> String {
Expand Down
19 changes: 15 additions & 4 deletions Sources/BitcoinKit/Networking/Peer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,13 @@ public class Peer: NSObject, StreamDelegate {
inputStream.delegate = self
outputStream.delegate = self

inputStream.schedule(in: .current, forMode: .commonModes)
outputStream.schedule(in: .current, forMode: .commonModes)
#if BitcoinKitXcode
inputStream.schedule(in: .current, forMode: .common)
outputStream.schedule(in: .current, forMode: .common)
#else
inputStream.schedule(in: .current, forMode: RunLoopMode.commonModes)
outputStream.schedule(in: .current, forMode: RunLoopMode.commonModes)
#endif

inputStream.open()
outputStream.open()
Expand All @@ -104,8 +109,14 @@ public class Peer: NSObject, StreamDelegate {

inputStream.delegate = nil
outputStream.delegate = nil
inputStream.remove(from: .current, forMode: .commonModes)
outputStream.remove(from: .current, forMode: .commonModes)
#if BitcoinKitXcode
inputStream.remove(from: .current, forMode: .common)
outputStream.remove(from: .current, forMode: .common)
#else
inputStream.remove(from: .current, forMode: RunLoopMode.commonModes)
outputStream.remove(from: .current, forMode: RunLoopMode.commonModes)
#endif

inputStream.close()
outputStream.close()
readStream = nil
Expand Down
4 changes: 2 additions & 2 deletions Sources/BitcoinKit/Scripts/OP_CODE/Splice/OP_SPLIT.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ public struct OpSplit: OpCodeProtocol {
throw OpCodeExecutionError.error("Invalid OP_SPLIT range")
}

let n1: Data = data.subdata(in: Range(0..<Int(position)))
let n2: Data = data.subdata(in: Range(Int(position)..<data.count))
let n1: Data = data.subdata(in: 0..<Int(position))
let n2: Data = data.subdata(in: Int(position)..<data.count)

// Replace existing stack values by the new values.
context.stack[context.stack.count - 2] = n1
Expand Down
2 changes: 1 addition & 1 deletion Sources/BitcoinKit/Scripts/OP_CODE/Stack/OP_2ROT.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public struct Op2Rot: OpCodeProtocol {
let x1: Data = context.data(at: -6)
let x2: Data = context.data(at: -5)
let count: Int = context.stack.count
context.stack.removeSubrange(Range(count - 6 ..< count - 4))
context.stack.removeSubrange(count - 6 ..< count - 4)
context.stack.append(x1)
context.stack.append(x2)
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/BitcoinKit/Scripts/Script.swift
Original file line number Diff line number Diff line change
Expand Up @@ -396,15 +396,15 @@ public class Script {

public func subScript(from index: Int) throws -> Script {
let subScript: Script = Script()
for chunk in chunks[Range(index..<chunks.count)] {
for chunk in chunks[index..<chunks.count] {
try subScript.appendData(chunk.chunkData)
}
return subScript
}

public func subScript(to index: Int) throws -> Script {
let subScript: Script = Script()
for chunk in chunks[Range(0..<index)] {
for chunk in chunks[0..<index] {
try subScript.appendData(chunk.chunkData)
}
return subScript
Expand Down
2 changes: 1 addition & 1 deletion Sources/BitcoinKit/Scripts/ScriptChunk.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public struct DataChunk: ScriptChunk {
loc += 4
}

return scriptData.subdata(in: Range((range.lowerBound + loc)..<(range.upperBound)))
return scriptData.subdata(in: (range.lowerBound + loc)..<(range.upperBound))
}

public var string: String {
Expand Down
4 changes: 2 additions & 2 deletions Sources/BitcoinKit/Scripts/ScriptChunkHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public struct ScriptChunkHelper {

if opcode > OpCode.OP_PUSHDATA4 {
// simple opcode
let range = Range(offset..<offset + MemoryLayout.size(ofValue: opcode))
let range = (offset..<offset + MemoryLayout.size(ofValue: opcode))
return OpcodeChunk(scriptData: scriptData, range: range)
} else {
// push data
Expand Down Expand Up @@ -119,7 +119,7 @@ public struct ScriptChunkHelper {
guard offset + chunkLength <= count else {
throw ScriptChunkError.error("Parse DataChunk failed. Push data is out of bounds error.")
}
let range: Range<Int> = Range(offset..<offset + chunkLength)
let range = (offset..<offset + chunkLength)
return DataChunk(scriptData: scriptData, range: range)
}
}
84 changes: 45 additions & 39 deletions Sources/BitcoinKitPrivate/BitcoinKit.Private.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,18 @@ public class _Hash {
}

public static func hmacsha512(_ data: Data, key: Data) -> Data {
var result = [UInt8](repeating: 0, count: Int(SHA512_DIGEST_LENGTH))
var length: UInt32 = UInt32(SHA512_DIGEST_LENGTH)
var length = UInt32(SHA512_DIGEST_LENGTH)
var result = Data(count: Int(length))

data.withUnsafeBytes { (dataPtr: UnsafePointer<UInt8>) in
key.withUnsafeBytes { (keyPtr: UnsafePointer<UInt8>) in
HMAC(EVP_sha512(), keyPtr, Int32(key.count), dataPtr, data.count, &result, &length)
return
result.withUnsafeMutableBytes { (resultPtr: UnsafeMutablePointer<UInt8>) in
HMAC(EVP_sha512(), keyPtr, Int32(key.count), dataPtr, data.count, resultPtr, &length)
return
}
}
}
return Data(result)
return result
}
}

Expand Down Expand Up @@ -115,13 +118,13 @@ public class _Key {

public class _HDKey {
public let privateKey: Data?
public let publicKey: Data?
public let publicKey: Data
public let chainCode: Data
public let depth: UInt8
public let fingerprint: UInt32
public let childIndex: UInt32

public init(privateKey: Data?, publicKey: Data?, chainCode: Data, depth: UInt8, fingerprint: UInt32, childIndex: UInt32) {
public init(privateKey: Data?, publicKey: Data, chainCode: Data, depth: UInt8, fingerprint: UInt32, childIndex: UInt32) {
self.privateKey = privateKey
self.publicKey = publicKey
self.chainCode = chainCode
Expand All @@ -130,21 +133,27 @@ public class _HDKey {
self.childIndex = childIndex
}
public func derived(at index: UInt32, hardened: Bool) -> _HDKey? {

// index should be 0 through 2^31-1
guard index < 0x80000000 else {
return nil
}
let ctx = BN_CTX_new()
defer {
BN_CTX_free(ctx)
}
var data = Data()
if hardened {
data.append(0) // padding
data += privateKey ?? Data()
guard let privateKey = privateKey else {
return nil
}
data.append(0) // pads the private key to make it 33 bytes long
data += privateKey
} else {
data += publicKey ?? Data()
data += publicKey
}

var childIndex = UInt32(hardened ? (0x80000000 | index) : index).bigEndian
data.append(UnsafeBufferPointer(start: &childIndex, count: 1))

let digest = _Hash.hmacsha512(data, key: self.chainCode)
let derivedPrivateKey = digest[0..<32]
let derivedChainCode = digest[32..<(32+32)]
Expand All @@ -158,6 +167,7 @@ public class _HDKey {
defer {
BN_free(factor)
}

derivedPrivateKey.withUnsafeBytes { (ptr: UnsafePointer<UInt8>) in
BN_bin2bn(ptr, Int32(derivedPrivateKey.count), factor)
return
Expand All @@ -167,6 +177,7 @@ public class _HDKey {
return nil
}

var result: Data = Data()
if let privateKey = self.privateKey {
let privateKeyNum = BN_new()!
defer {
Expand All @@ -186,20 +197,12 @@ public class _HDKey {
return nil
}
let numBytes = ((BN_num_bits(privateKeyNum)+7)/8) // BN_num_bytes
var result = [UInt8](repeating: 0, count: Int(numBytes))
BN_bn2bin(privateKeyNum, &result)
let fingerprintData = _Hash.sha256ripemd160(publicKey ?? Data())
let fingerprintArray = fingerprintData.withUnsafeBytes {
[UInt32](UnsafeBufferPointer(start: $0, count: fingerprintData.count))
result = Data(count: Int(numBytes))
result.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) in
BN_bn2bin(privateKeyNum, ptr)
return
}
let reusltData = Data(result)
return _HDKey(privateKey: reusltData,
publicKey: reusltData,
chainCode: derivedChainCode,
depth: depth + 1,
fingerprint: fingerprintArray[0],
childIndex: childIndex)
} else if let publicKey = self.publicKey {
} else {
let publicKeyNum = BN_new()
defer {
BN_free(publicKeyNum)
Expand All @@ -213,6 +216,7 @@ public class _HDKey {
let point = EC_POINT_new(group)
defer {
EC_POINT_free(point)
EC_GROUP_free(group)
}
EC_POINT_bn2point(group, publicKeyNum, point, ctx)
EC_POINT_mul(group, point, factor, point, BN_value_one(), ctx)
Expand All @@ -225,23 +229,25 @@ public class _HDKey {
defer {
BN_free(n)
}
var result = [UInt8](repeating: 0, count: 33)
EC_POINT_point2bn(group, point, POINT_CONVERSION_COMPRESSED, n, ctx)
BN_bn2bin(n, &result)
let fingerprintData = _Hash.sha256ripemd160(publicKey)
let fingerprintArray = fingerprintData.withUnsafeBytes {
[UInt32](UnsafeBufferPointer(start: $0, count: fingerprintData.count))
result = Data(count: 33)
result.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) in
BN_bn2bin(n, ptr)
return
}
let reusltData = Data(result)
return _HDKey(privateKey: reusltData,
publicKey: reusltData,
chainCode: derivedChainCode,
depth: depth + 1,
fingerprint: fingerprintArray[0],
childIndex: childIndex)
} else {
return nil
}

let fingerprintData = _Hash.sha256ripemd160(publicKey)
let fingerprint = fingerprintData.withUnsafeBytes{ (p: UnsafePointer<UInt32>) in
p.pointee
}
return _HDKey(privateKey: result,
publicKey: result,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are really both of privateKey and publicKey the same value?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh this is kind of bad architecture of _HDKey.
I think _HDKey should be refactored, but it's not in the scope of this PR.

chainCode: derivedChainCode,
depth: depth + 1,
fingerprint: fingerprint,
childIndex: childIndex)

}
}

Expand Down
Loading