Skip to content

Commit 2afd919

Browse files
committed
Merge pull request #5208
18051c7 Abstract out Ctransaction-specific signing into TransactionSignatureCreator (Pieter Wuille)
2 parents 0310622 + 18051c7 commit 2afd919

File tree

2 files changed

+90
-40
lines changed

2 files changed

+90
-40
lines changed

src/script/sign.cpp

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,43 +17,52 @@ using namespace std;
1717

1818
typedef vector<unsigned char> valtype;
1919

20-
bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
20+
TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn) {}
21+
22+
bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode) const
2123
{
2224
CKey key;
23-
if (!keystore.GetKey(address, key))
25+
if (!keystore->GetKey(address, key))
2426
return false;
2527

26-
vector<unsigned char> vchSig;
28+
uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
2729
if (!key.Sign(hash, vchSig))
2830
return false;
2931
vchSig.push_back((unsigned char)nHashType);
30-
scriptSigRet << vchSig;
32+
return true;
33+
}
3134

35+
static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
36+
{
37+
vector<unsigned char> vchSig;
38+
if (!creator.CreateSig(vchSig, address, scriptCode))
39+
return false;
40+
scriptSigRet << vchSig;
3241
return true;
3342
}
3443

35-
bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
44+
static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
3645
{
3746
int nSigned = 0;
3847
int nRequired = multisigdata.front()[0];
3948
for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
4049
{
4150
const valtype& pubkey = multisigdata[i];
4251
CKeyID keyID = CPubKey(pubkey).GetID();
43-
if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
52+
if (Sign1(keyID, creator, scriptCode, scriptSigRet))
4453
++nSigned;
4554
}
4655
return nSigned==nRequired;
4756
}
4857

4958
/**
50-
* Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
59+
* Sign scriptPubKey using signature made with creator.
5160
* Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
5261
* unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
5362
* Returns false if scriptPubKey could not be completely satisfied.
5463
*/
55-
bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType,
56-
CScript& scriptSigRet, txnouttype& whichTypeRet)
64+
static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,
65+
CScript& scriptSigRet, txnouttype& whichTypeRet)
5766
{
5867
scriptSigRet.clear();
5968

@@ -69,61 +78,62 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
6978
return false;
7079
case TX_PUBKEY:
7180
keyID = CPubKey(vSolutions[0]).GetID();
72-
return Sign1(keyID, keystore, hash, nHashType, scriptSigRet);
81+
return Sign1(keyID, creator, scriptPubKey, scriptSigRet);
7382
case TX_PUBKEYHASH:
7483
keyID = CKeyID(uint160(vSolutions[0]));
75-
if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
84+
if (!Sign1(keyID, creator, scriptPubKey, scriptSigRet))
7685
return false;
7786
else
7887
{
7988
CPubKey vch;
80-
keystore.GetPubKey(keyID, vch);
89+
creator.KeyStore().GetPubKey(keyID, vch);
8190
scriptSigRet << ToByteVector(vch);
8291
}
8392
return true;
8493
case TX_SCRIPTHASH:
85-
return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet);
94+
return creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptSigRet);
8695

8796
case TX_MULTISIG:
8897
scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
89-
return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet));
98+
return (SignN(vSolutions, creator, scriptPubKey, scriptSigRet));
9099
}
91100
return false;
92101
}
93102

94-
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
103+
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, CScript& scriptSig)
95104
{
96-
assert(nIn < txTo.vin.size());
97-
CTxIn& txin = txTo.vin[nIn];
98-
99-
// Leave out the signature from the hash, since a signature can't sign itself.
100-
// The checksig op will also drop the signatures from its hash.
101-
uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType);
102-
103105
txnouttype whichType;
104-
if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType))
106+
if (!SignStep(creator, fromPubKey, scriptSig, whichType))
105107
return false;
106108

107109
if (whichType == TX_SCRIPTHASH)
108110
{
109111
// Solver returns the subscript that need to be evaluated;
110112
// the final scriptSig is the signatures from that
111113
// and then the serialized subscript:
112-
CScript subscript = txin.scriptSig;
113-
114-
// Recompute txn hash using subscript in place of scriptPubKey:
115-
uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType);
114+
CScript subscript = scriptSig;
116115

117116
txnouttype subType;
118117
bool fSolved =
119-
Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH;
118+
SignStep(creator, subscript, scriptSig, subType) && subType != TX_SCRIPTHASH;
120119
// Append serialized subscript whether or not it is completely signed:
121-
txin.scriptSig << static_cast<valtype>(subscript);
120+
scriptSig << static_cast<valtype>(subscript);
122121
if (!fSolved) return false;
123122
}
124123

125124
// Test solution
126-
return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&txTo, nIn));
125+
return VerifyScript(scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
126+
}
127+
128+
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
129+
{
130+
assert(nIn < txTo.vin.size());
131+
CTxIn& txin = txTo.vin[nIn];
132+
133+
CTransaction txToConst(txTo);
134+
TransactionSignatureCreator creator(&keystore, &txToConst, nIn, nHashType);
135+
136+
return ProduceSignature(creator, fromPubKey, txin.scriptSig);
127137
}
128138

129139
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)
144154
return result;
145155
}
146156

147-
static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
157+
static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
148158
const vector<valtype>& vSolutions,
149159
const vector<valtype>& sigs1, const vector<valtype>& sigs2)
150160
{
@@ -174,7 +184,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction&
174184
if (sigs.count(pubkey))
175185
continue; // Already got a sig for this pubkey
176186

177-
if (TransactionSignatureChecker(&txTo, nIn).CheckSig(sig, pubkey, scriptPubKey))
187+
if (checker.CheckSig(sig, pubkey, scriptPubKey))
178188
{
179189
sigs[pubkey] = sig;
180190
break;
@@ -199,7 +209,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction&
199209
return result;
200210
}
201211

202-
static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
212+
static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
203213
const txnouttype txType, const vector<valtype>& vSolutions,
204214
vector<valtype>& sigs1, vector<valtype>& sigs2)
205215
{
@@ -233,19 +243,26 @@ static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction
233243
Solver(pubKey2, txType2, vSolutions2);
234244
sigs1.pop_back();
235245
sigs2.pop_back();
236-
CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2);
246+
CScript result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2);
237247
result << spk;
238248
return result;
239249
}
240250
case TX_MULTISIG:
241-
return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2);
251+
return CombineMultisig(scriptPubKey, checker, vSolutions, sigs1, sigs2);
242252
}
243253

244254
return CScript();
245255
}
246256

247257
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
248258
const CScript& scriptSig1, const CScript& scriptSig2)
259+
{
260+
TransactionSignatureChecker checker(&txTo, nIn);
261+
return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2);
262+
}
263+
264+
CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
265+
const CScript& scriptSig1, const CScript& scriptSig2)
249266
{
250267
txnouttype txType;
251268
vector<vector<unsigned char> > vSolutions;
@@ -256,5 +273,5 @@ CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo,
256273
vector<valtype> stack2;
257274
EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
258275

259-
return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
276+
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
260277
}

src/script/sign.h

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,52 @@
88

99
#include "script/interpreter.h"
1010

11+
class CKeyID;
1112
class CKeyStore;
1213
class CScript;
1314
class CTransaction;
1415

1516
struct CMutableTransaction;
1617

18+
/** Virtual base class for signature creators. */
19+
class BaseSignatureCreator {
20+
protected:
21+
const CKeyStore* keystore;
22+
23+
public:
24+
BaseSignatureCreator(const CKeyStore* keystoreIn) : keystore(keystoreIn) {}
25+
const CKeyStore& KeyStore() const { return *keystore; };
26+
virtual ~BaseSignatureCreator() {}
27+
virtual const BaseSignatureChecker& Checker() const =0;
28+
29+
/** Create a singular (non-script) signature. */
30+
virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const =0;
31+
};
32+
33+
/** A signature creator for transactions. */
34+
class TransactionSignatureCreator : public BaseSignatureCreator {
35+
const CTransaction* txTo;
36+
unsigned int nIn;
37+
int nHashType;
38+
const TransactionSignatureChecker checker;
39+
40+
public:
41+
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn=SIGHASH_ALL);
42+
const BaseSignatureChecker& Checker() const { return checker; }
43+
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
44+
};
45+
46+
/** Produce a script signature using a generic signature creator. */
47+
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig);
48+
49+
/** Produce a script signature for a transaction. */
1750
bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
1851
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
1952

20-
/**
21-
* Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
22-
* combine them intelligently and return the result.
23-
*/
53+
/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */
54+
CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const CScript& scriptSig1, const CScript& scriptSig2);
55+
56+
/** Combine two script signatures on transactions. */
2457
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
2558

2659
#endif // BITCOIN_SCRIPT_SIGN_H

0 commit comments

Comments
 (0)