Skip to content
Permalink
Browse files

Add _Crypto.signMessage() and fix for Linux.

  • Loading branch information...
usatie committed Sep 19, 2018
1 parent ae1ff03 commit 71539f6fca0055695e74739b7183387d261e6b87
@@ -7,5 +7,6 @@ framework module BitcoinKit {
explicit module Private {
header "BitcoinKitPrivate.h"
link "crypto"
link "secp256k1"
}
}
@@ -57,4 +57,8 @@ NS_ASSUME_NONNULL_BEGIN

@end

@interface _Crypto : NSObject
+ (NSData *)signMessage:(NSData *)message withPrivateKey:(NSData *)privateKey;
@end

NS_ASSUME_NONNULL_END
@@ -29,6 +29,7 @@
#import <openssl/hmac.h>
#import <openssl/ec.h>
#import <openssl/bn.h>
#import <secp256k1.h>

@implementation _Hash

@@ -206,3 +207,21 @@ - (_HDKey *)derivedAtIndex:(uint32_t)index hardened:(BOOL)hardened {
}

@end

@implementation _Crypto

+ (NSData *)signMessage:(NSData *)message withPrivateKey:(NSData *)privateKey {
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_ecdsa_signature signature;
secp256k1_ecdsa_signature normalizedSignature;
secp256k1_ecdsa_sign(ctx, &signature, message.bytes, privateKey.bytes, NULL, NULL);
secp256k1_ecdsa_signature_normalize(ctx, &normalizedSignature, &signature);
size_t siglen = 128;
NSMutableData *der = [NSMutableData dataWithLength:siglen];
secp256k1_ecdsa_signature_serialize_der(ctx, der.mutableBytes, &siglen, &normalizedSignature);
der.length = siglen;
secp256k1_context_destroy(ctx);
return der;
}

@end
@@ -17,7 +17,8 @@ let package = Package(
dependencies: ["BitcoinKitPrivate", "secp256k1", "Random"]
),
.target(
name: "BitcoinKitPrivate"
name: "BitcoinKitPrivate",
dependencies: ["COpenSSL", "secp256k1"]
),
.testTarget(
name: "BitcoinKitTests",
@@ -57,35 +57,22 @@ public struct Crypto {
}

public static func sign(_ data: Data, privateKey: PrivateKey) throws -> Data {
let ctx = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN))!
defer { secp256k1_context_destroy(ctx) }

let signature = UnsafeMutablePointer<secp256k1_ecdsa_signature>.allocate(capacity: 1)
defer { signature.deallocate() }
let status = data.withUnsafeBytes { (ptr: UnsafePointer<UInt8>) in
privateKey.data.withUnsafeBytes { secp256k1_ecdsa_sign(ctx, signature, ptr, $0, nil, nil) }
}
guard status == 1 else { throw CryptoError.signFailed }

let normalizedsig = UnsafeMutablePointer<secp256k1_ecdsa_signature>.allocate(capacity: 1)
defer { normalizedsig.deallocate() }
secp256k1_ecdsa_signature_normalize(ctx, normalizedsig, signature)

var length: size_t = 128
var der = Data(count: length)
guard der.withUnsafeMutableBytes({ return secp256k1_ecdsa_signature_serialize_der(ctx, $0, &length, normalizedsig) }) == 1 else { throw CryptoError.noEnoughSpace }
der.count = length

return der
#if BitcoinKitXcode
return _Crypto.signMessage(data, withPrivateKey: privateKey.data)
#else
return try _Crypto.signMessage(data, withPrivateKey: privateKey.data)
#endif
}

public static func verifySignature(_ signature: Data, message: Data, publicKey: Data) throws -> Bool {
#if BitcoinKitXcode
let ctx = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_VERIFY))!
defer { secp256k1_context_destroy(ctx) }

let signaturePointer = UnsafeMutablePointer<secp256k1_ecdsa_signature>.allocate(capacity: 1)
defer { signaturePointer.deallocate() }
guard signature.withUnsafeBytes({ secp256k1_ecdsa_signature_parse_der(ctx, signaturePointer, $0, signature.count) }) == 1 else {
print("signature : ", signature.hex)
throw CryptoError.signatureParseFailed
}

@@ -98,8 +85,10 @@ public struct Crypto {
guard message.withUnsafeBytes ({ secp256k1_ecdsa_verify(ctx, signaturePointer, $0, pubkeyPointer) }) == 1 else {
return false
}

return true
#else
return try _Crypto.verifySignature(signature, message: message, publicKey: publicKey)
#endif
}

public static func verifySigData(for tx: Transaction, inputIndex: Int, utxo: TransactionOutput, sigData: Data, pubKeyData: Data) throws -> Bool {
@@ -23,7 +23,6 @@
//
import Foundation
import secp256k1

public enum ScriptVerification {
case StrictEncoding // enforce strict conformance to DER and SEC2 for signatures and pubkeys (aka SCRIPT_VERIFY_STRICTENC)
@@ -8,6 +8,7 @@
import Foundation
import COpenSSL
import secp256k1

public class _Hash {
public static func sha1(_ data: Data) -> Data {
@@ -243,3 +244,58 @@ public class _HDKey {
}
}
}

public class _Crypto {
public static func signMessage(_ data: Data, withPrivateKey privateKey: Data) throws -> Data {
let ctx = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN))!
defer { secp256k1_context_destroy(ctx) }

let signature = UnsafeMutablePointer<secp256k1_ecdsa_signature>.allocate(capacity: 1)
defer { signature.deallocate() }
let status = data.withUnsafeBytes { (ptr: UnsafePointer<UInt8>) in
privateKey.withUnsafeBytes { secp256k1_ecdsa_sign(ctx, signature, ptr, $0, nil, nil) }
}
guard status == 1 else { throw CryptoError.signFailed }

let normalizedsig = UnsafeMutablePointer<secp256k1_ecdsa_signature>.allocate(capacity: 1)
defer { normalizedsig.deallocate() }
secp256k1_ecdsa_signature_normalize(ctx, normalizedsig, signature)

var length: size_t = 128
var der = Data(count: length)
guard der.withUnsafeMutableBytes({ return secp256k1_ecdsa_signature_serialize_der(ctx, $0, &length, normalizedsig) }) == 1 else { throw CryptoError.noEnoughSpace }
der.count = length

return der
}

public static func verifySignature(_ signature: Data, message: Data, publicKey: Data) throws -> Bool {
let ctx = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_VERIFY))!
defer { secp256k1_context_destroy(ctx) }

let signaturePointer = UnsafeMutablePointer<secp256k1_ecdsa_signature>.allocate(capacity: 1)
defer { signaturePointer.deallocate() }
guard signature.withUnsafeBytes({ secp256k1_ecdsa_signature_parse_der(ctx, signaturePointer, $0, signature.count) }) == 1 else {
throw CryptoError.signatureParseFailed
}

let pubkeyPointer = UnsafeMutablePointer<secp256k1_pubkey>.allocate(capacity: 1)
defer { pubkeyPointer.deallocate() }
guard publicKey.withUnsafeBytes({ secp256k1_ec_pubkey_parse(ctx, pubkeyPointer, $0, publicKey.count) }) == 1 else {
throw CryptoError.publicKeyParseFailed
}

guard message.withUnsafeBytes ({ secp256k1_ecdsa_verify(ctx, signaturePointer, $0, pubkeyPointer) }) == 1 else {
return false
}

return true
}

public enum CryptoError: Error {
case signFailed
case noEnoughSpace
case signatureParseFailed
case publicKeyParseFailed
}
}

0 comments on commit 71539f6

Please sign in to comment.
You can’t perform that action at this time.