aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2015-03-24 05:54:36 -0700
committerPieter Wuille <pieter.wuille@gmail.com>2015-03-24 05:55:51 -0700
commit2afd919f212e8499d5549e29ac9b8a2d825873d9 (patch)
tree60f4f7129a97c951acf34828cf28d707b4233664
parent03106221d49920527e7cdb979865c816c06ee305 (diff)
parent18051c7fbd224e32d9a5fea96f1083210cea3a14 (diff)
Merge pull request #5208
18051c7 Abstract out Ctransaction-specific signing into TransactionSignatureCreator (Pieter Wuille)
-rw-r--r--src/script/sign.cpp89
-rw-r--r--src/script/sign.h41
2 files changed, 90 insertions, 40 deletions
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 14119f7e2c..eab629cd91 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -17,22 +17,31 @@ using namespace std;
typedef vector<unsigned char> valtype;
-bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
+TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn) {}
+
+bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode) const
{
CKey key;
- if (!keystore.GetKey(address, key))
+ if (!keystore->GetKey(address, key))
return false;
- vector<unsigned char> vchSig;
+ uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
if (!key.Sign(hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
- scriptSigRet << vchSig;
+ return true;
+}
+static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
+{
+ vector<unsigned char> vchSig;
+ if (!creator.CreateSig(vchSig, address, scriptCode))
+ return false;
+ scriptSigRet << vchSig;
return true;
}
-bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
+static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
{
int nSigned = 0;
int nRequired = multisigdata.front()[0];
@@ -40,20 +49,20 @@ bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint2
{
const valtype& pubkey = multisigdata[i];
CKeyID keyID = CPubKey(pubkey).GetID();
- if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
+ if (Sign1(keyID, creator, scriptCode, scriptSigRet))
++nSigned;
}
return nSigned==nRequired;
}
/**
- * Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
+ * Sign scriptPubKey using signature made with creator.
* Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
* unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
* Returns false if scriptPubKey could not be completely satisfied.
*/
-bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType,
- CScript& scriptSigRet, txnouttype& whichTypeRet)
+static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,
+ CScript& scriptSigRet, txnouttype& whichTypeRet)
{
scriptSigRet.clear();
@@ -69,39 +78,32 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
return false;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
- return Sign1(keyID, keystore, hash, nHashType, scriptSigRet);
+ return Sign1(keyID, creator, scriptPubKey, scriptSigRet);
case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
- if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
+ if (!Sign1(keyID, creator, scriptPubKey, scriptSigRet))
return false;
else
{
CPubKey vch;
- keystore.GetPubKey(keyID, vch);
+ creator.KeyStore().GetPubKey(keyID, vch);
scriptSigRet << ToByteVector(vch);
}
return true;
case TX_SCRIPTHASH:
- return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet);
+ return creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptSigRet);
case TX_MULTISIG:
scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
- return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet));
+ return (SignN(vSolutions, creator, scriptPubKey, scriptSigRet));
}
return false;
}
-bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
+bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, CScript& scriptSig)
{
- assert(nIn < txTo.vin.size());
- CTxIn& txin = txTo.vin[nIn];
-
- // Leave out the signature from the hash, since a signature can't sign itself.
- // The checksig op will also drop the signatures from its hash.
- uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType);
-
txnouttype whichType;
- if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType))
+ if (!SignStep(creator, fromPubKey, scriptSig, whichType))
return false;
if (whichType == TX_SCRIPTHASH)
@@ -109,21 +111,29 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutabl
// Solver returns the subscript that need to be evaluated;
// the final scriptSig is the signatures from that
// and then the serialized subscript:
- CScript subscript = txin.scriptSig;
-
- // Recompute txn hash using subscript in place of scriptPubKey:
- uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType);
+ CScript subscript = scriptSig;
txnouttype subType;
bool fSolved =
- Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH;
+ SignStep(creator, subscript, scriptSig, subType) && subType != TX_SCRIPTHASH;
// Append serialized subscript whether or not it is completely signed:
- txin.scriptSig << static_cast<valtype>(subscript);
+ scriptSig << static_cast<valtype>(subscript);
if (!fSolved) return false;
}
// Test solution
- return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&txTo, nIn));
+ return VerifyScript(scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
+}
+
+bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
+{
+ assert(nIn < txTo.vin.size());
+ CTxIn& txin = txTo.vin[nIn];
+
+ CTransaction txToConst(txTo);
+ TransactionSignatureCreator creator(&keystore, &txToConst, nIn, nHashType);
+
+ return ProduceSignature(creator, fromPubKey, txin.scriptSig);
}
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
@@ -144,7 +154,7 @@ static CScript PushAll(const vector<valtype>& values)
return result;
}
-static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const vector<valtype>& vSolutions,
const vector<valtype>& sigs1, const vector<valtype>& sigs2)
{
@@ -174,7 +184,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction&
if (sigs.count(pubkey))
continue; // Already got a sig for this pubkey
- if (TransactionSignatureChecker(&txTo, nIn).CheckSig(sig, pubkey, scriptPubKey))
+ if (checker.CheckSig(sig, pubkey, scriptPubKey))
{
sigs[pubkey] = sig;
break;
@@ -199,7 +209,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction&
return result;
}
-static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const txnouttype txType, const vector<valtype>& vSolutions,
vector<valtype>& sigs1, vector<valtype>& sigs2)
{
@@ -233,12 +243,12 @@ static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction
Solver(pubKey2, txType2, vSolutions2);
sigs1.pop_back();
sigs2.pop_back();
- CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2);
+ CScript result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2);
result << spk;
return result;
}
case TX_MULTISIG:
- return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2);
+ return CombineMultisig(scriptPubKey, checker, vSolutions, sigs1, sigs2);
}
return CScript();
@@ -247,6 +257,13 @@ static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
const CScript& scriptSig1, const CScript& scriptSig2)
{
+ TransactionSignatureChecker checker(&txTo, nIn);
+ return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2);
+}
+
+CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
+ const CScript& scriptSig1, const CScript& scriptSig2)
+{
txnouttype txType;
vector<vector<unsigned char> > vSolutions;
Solver(scriptPubKey, txType, vSolutions);
@@ -256,5 +273,5 @@ CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo,
vector<valtype> stack2;
EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
- return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
+ return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
}
diff --git a/src/script/sign.h b/src/script/sign.h
index e197d5fab3..0c4cf61e5e 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -8,19 +8,52 @@
#include "script/interpreter.h"
+class CKeyID;
class CKeyStore;
class CScript;
class CTransaction;
struct CMutableTransaction;
+/** Virtual base class for signature creators. */
+class BaseSignatureCreator {
+protected:
+ const CKeyStore* keystore;
+
+public:
+ BaseSignatureCreator(const CKeyStore* keystoreIn) : keystore(keystoreIn) {}
+ const CKeyStore& KeyStore() const { return *keystore; };
+ virtual ~BaseSignatureCreator() {}
+ virtual const BaseSignatureChecker& Checker() const =0;
+
+ /** Create a singular (non-script) signature. */
+ virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const =0;
+};
+
+/** A signature creator for transactions. */
+class TransactionSignatureCreator : public BaseSignatureCreator {
+ const CTransaction* txTo;
+ unsigned int nIn;
+ int nHashType;
+ const TransactionSignatureChecker checker;
+
+public:
+ TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn=SIGHASH_ALL);
+ const BaseSignatureChecker& Checker() const { return checker; }
+ bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
+};
+
+/** Produce a script signature using a generic signature creator. */
+bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig);
+
+/** Produce a script signature for a transaction. */
bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
-/**
- * Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
- * combine them intelligently and return the result.
- */
+/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */
+CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const CScript& scriptSig1, const CScript& scriptSig2);
+
+/** Combine two script signatures on transactions. */
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
#endif // BITCOIN_SCRIPT_SIGN_H