From 74b3f33f2b94efb4c52be45af9eb6adc1a065b3c Mon Sep 17 00:00:00 2001 From: Kevin Lohman Date: Wed, 24 Jan 2018 11:03:30 -0800 Subject: [PATCH 1/2] Allow for signing inputs on existing transactions from outside of Builder (so you can load a transaction from a 3rd party, and sign it). --- CoreBitcoin/BTCTransaction.h | 4 +++ CoreBitcoin/BTCTransaction.m | 47 +++++++++++++++++++++++++++++ CoreBitcoin/BTCTransactionBuilder.m | 36 +--------------------- 3 files changed, 52 insertions(+), 35 deletions(-) diff --git a/CoreBitcoin/BTCTransaction.h b/CoreBitcoin/BTCTransaction.h index cc14824a..1168a726 100644 --- a/CoreBitcoin/BTCTransaction.h +++ b/CoreBitcoin/BTCTransaction.h @@ -11,6 +11,7 @@ static const BTCAmount BTCTransactionDefaultFeeRate = 10000; // 10K satoshis per @class BTCScript; @class BTCTransactionInput; @class BTCTransactionOutput; +@class BTCKey; /*! * Converts string transaction ID (reversed tx hash in hex format) to transaction hash. @@ -128,6 +129,9 @@ NSString* BTCTransactionIDFromHash(NSData* txhash) DEPRECATED_ATTRIBUTE; // You should supply the output script of the previous transaction, desired hash type and input index in this transaction. - (NSData*) signatureHashForScript:(BTCScript*)subscript inputIndex:(uint32_t)inputIndex hashType:(BTCSignatureHashType)hashType error:(NSError**)errorOut; +// Attempts to sign the index at position i with key, returns failure / success +- (BOOL)attemptToSignInputAtIndex:(uint32_t)i withKey:(BTCKey *)key error:(NSError **)errorOut; + // Adds input script - (void) addInput:(BTCTransactionInput*)input; diff --git a/CoreBitcoin/BTCTransaction.m b/CoreBitcoin/BTCTransaction.m index d21ad9c4..e2e717a9 100644 --- a/CoreBitcoin/BTCTransaction.m +++ b/CoreBitcoin/BTCTransaction.m @@ -8,6 +8,8 @@ #import "BTCScript.h" #import "BTCErrors.h" #import "BTCHashID.h" +#import "BTCKey.h" +#import "BTCAddress.h" NSData* BTCTransactionHashFromID(NSString* txid) { return BTCHashFromID(txid); @@ -335,7 +337,52 @@ - (BOOL) parseStream:(NSInputStream*)stream { #pragma mark - Signing a transaction +// Attempts to sign the index at position i with key, returns failure / success +- (BOOL)attemptToSignInputAtIndex:(uint32_t)i withKey:(BTCKey *)key error:(NSError **)errorOut +{ + BTCTransactionInput *txin = self.inputs[i]; + + // We stored output script here earlier. + BTCScript* outputScript = txin.signatureScript; + + NSData* cpk = key.compressedPublicKey; + NSData* ucpk = key.uncompressedPublicKey; + + BTCSignatureHashType hashtype = SIGHASH_ALL; + + NSData* sighash = [self signatureHashForScript:[outputScript copy] inputIndex:i hashType:hashtype error:errorOut]; + if (!sighash) { + return NO; + } + + // Most common case: P2PKH with compressed pubkey (because of BIP32) + BTCScript* p2cpkhScript = [[BTCScript alloc] initWithAddress:[BTCPublicKeyAddress addressWithData:BTCHash160(cpk)]]; + if ([outputScript.data isEqual:p2cpkhScript.data]) { + txin.signatureScript = [[[BTCScript new] appendData:[key signatureForHash:sighash hashType:hashtype]] appendData:cpk]; + return YES; + } + + // Less common case: P2PKH with uncompressed pubkey (when not using BIP32) + BTCScript* p2ucpkhScript = [[BTCScript alloc] initWithAddress:[BTCPublicKeyAddress addressWithData:BTCHash160(ucpk)]]; + if ([outputScript.data isEqual:p2ucpkhScript.data]) { + txin.signatureScript = [[[BTCScript new] appendData:[key signatureForHash:sighash hashType:hashtype]] appendData:ucpk]; + return YES; + } + + BTCScript* p2cpkScript = [[[BTCScript new] appendData:cpk] appendOpcode:OP_CHECKSIG]; + BTCScript* p2ucpkScript = [[[BTCScript new] appendData:ucpk] appendOpcode:OP_CHECKSIG]; + + if ([outputScript.data isEqual:p2cpkScript] || + [outputScript.data isEqual:p2ucpkScript]) { + txin.signatureScript = [[BTCScript new] appendData:[key signatureForHash:sighash hashType:hashtype]]; + return YES; + } else { + // Not supported script type. + // Try custom signature. + } + return NO; +} // Hash for signing a transaction. // You should supply the output script of the previous transaction, desired hash type and input index in this transaction. diff --git a/CoreBitcoin/BTCTransactionBuilder.m b/CoreBitcoin/BTCTransactionBuilder.m index a92c7b0a..b7feb2d2 100644 --- a/CoreBitcoin/BTCTransactionBuilder.m +++ b/CoreBitcoin/BTCTransactionBuilder.m @@ -294,41 +294,7 @@ - (BOOL) attemptToSignTransactionInput:(BTCTransactionInput*)txin tx:(BTCTransac } if (key) { - NSData* cpk = key.compressedPublicKey; - NSData* ucpk = key.uncompressedPublicKey; - - BTCSignatureHashType hashtype = SIGHASH_ALL; - - NSData* sighash = [tx signatureHashForScript:[outputScript copy] inputIndex:i hashType:hashtype error:errorOut]; - if (!sighash) { - return NO; - } - - // Most common case: P2PKH with compressed pubkey (because of BIP32) - BTCScript* p2cpkhScript = [[BTCScript alloc] initWithAddress:[BTCPublicKeyAddress addressWithData:BTCHash160(cpk)]]; - if ([outputScript.data isEqual:p2cpkhScript.data]) { - txin.signatureScript = [[[BTCScript new] appendData:[key signatureForHash:sighash hashType:hashtype]] appendData:cpk]; - return YES; - } - - // Less common case: P2PKH with uncompressed pubkey (when not using BIP32) - BTCScript* p2ucpkhScript = [[BTCScript alloc] initWithAddress:[BTCPublicKeyAddress addressWithData:BTCHash160(ucpk)]]; - if ([outputScript.data isEqual:p2ucpkhScript.data]) { - txin.signatureScript = [[[BTCScript new] appendData:[key signatureForHash:sighash hashType:hashtype]] appendData:ucpk]; - return YES; - } - - BTCScript* p2cpkScript = [[[BTCScript new] appendData:cpk] appendOpcode:OP_CHECKSIG]; - BTCScript* p2ucpkScript = [[[BTCScript new] appendData:ucpk] appendOpcode:OP_CHECKSIG]; - - if ([outputScript.data isEqual:p2cpkScript] || - [outputScript.data isEqual:p2ucpkScript]) { - txin.signatureScript = [[BTCScript new] appendData:[key signatureForHash:sighash hashType:hashtype]]; - return YES; - } else { - // Not supported script type. - // Try custom signature. - } + [tx attemptToSignInputAtIndex:i withKey:key error:errorOut]; } // if key // Ask to sign the transaction input to sign this if that's some kind of special input or script. From 898ec46d494663df14b7420d2b9a16fc5e4a2d5a Mon Sep 17 00:00:00 2001 From: Kevin Lohman Date: Wed, 24 Jan 2018 11:03:57 -0800 Subject: [PATCH 2/2] Fix warnings about void being needed in non-prototype. --- CoreBitcoin/BTCBase58.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CoreBitcoin/BTCBase58.m b/CoreBitcoin/BTCBase58.m index 7e8a0bd1..963f9627 100644 --- a/CoreBitcoin/BTCBase58.m +++ b/CoreBitcoin/BTCBase58.m @@ -27,7 +27,7 @@ __block BIGNUM bn; BN_init(&bn); BN_zero(&bn); __block BIGNUM bnChar; BN_init(&bnChar); - void(^finish)() = ^{ + void(^finish)(void) = ^{ if (pctx) BN_CTX_free(pctx); BN_clear_free(&bn58); BN_clear_free(&bn); @@ -134,7 +134,7 @@ __block BIGNUM dv; BN_init(&dv); BN_zero(&dv); __block BIGNUM rem; BN_init(&rem); BN_zero(&rem); - void(^finish)() = ^{ + void(^finish)(void) = ^{ if (pctx) BN_CTX_free(pctx); BN_clear_free(&bn58); BN_clear_free(&bn0);