aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2015-12-27 19:49:08 +0100
committerPieter Wuille <pieter.wuille@gmail.com>2016-06-22 15:43:00 +0200
commit3dd410294d42f251e4808ef1dfcfcd64817edbac (patch)
treed6c5146772069c84ad8edbef9fce968b33d54924 /src/script
parent0ef1dd3e11dd573b6e443852ef0c72e34093ac68 (diff)
BIP143: Verification logic
Includes simplifications by Eric Lombrozo.
Diffstat (limited to 'src/script')
-rw-r--r--src/script/interpreter.cpp84
-rw-r--r--src/script/interpreter.h17
-rw-r--r--src/script/sign.cpp17
-rw-r--r--src/script/sign.h5
4 files changed, 95 insertions, 28 deletions
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index be649fca20..4deebd050d 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -229,7 +229,7 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
return true;
}
-bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
+bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
{
static const CScriptNum bnZero(0);
static const CScriptNum bnOne(1);
@@ -869,13 +869,15 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
CScript scriptCode(pbegincodehash, pend);
// Drop the signature, since there's no way for a signature to sign itself
- scriptCode.FindAndDelete(CScript(vchSig));
+ if (sigversion == SIGVERSION_BASE) {
+ scriptCode.FindAndDelete(CScript(vchSig));
+ }
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
//serror is set
return false;
}
- bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode);
+ bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
popstack(stack);
popstack(stack);
@@ -925,7 +927,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
for (int k = 0; k < nSigsCount; k++)
{
valtype& vchSig = stacktop(-isig-k);
- scriptCode.FindAndDelete(CScript(vchSig));
+ if (sigversion == SIGVERSION_BASE) {
+ scriptCode.FindAndDelete(CScript(vchSig));
+ }
}
bool fSuccess = true;
@@ -943,7 +947,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
}
// Check signature
- bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode);
+ bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
if (fOk) {
isig++;
@@ -1106,8 +1110,64 @@ public:
} // anon namespace
-uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
+uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion)
{
+ if (sigversion == SIGVERSION_WITNESS_V0) {
+ uint256 hashPrevouts;
+ uint256 hashSequence;
+ uint256 hashOutputs;
+
+ if (!(nHashType & SIGHASH_ANYONECANPAY)) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vin.size(); n++) {
+ ss << txTo.vin[n].prevout;
+ }
+ hashPrevouts = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ }
+
+ if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vin.size(); n++) {
+ ss << txTo.vin[n].nSequence;
+ }
+ hashSequence = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ }
+
+ if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vout.size(); n++) {
+ ss << txTo.vout[n];
+ }
+ hashOutputs = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
+ CHashWriter ss(SER_GETHASH, 0);
+ ss << txTo.vout[nIn];
+ hashOutputs = ss.GetHash();
+ }
+
+ CHashWriter ss(SER_GETHASH, 0);
+ // Version
+ ss << txTo.nVersion;
+ // Input prevouts/nSequence (none/all, depending on flags)
+ ss << hashPrevouts;
+ ss << hashSequence;
+ // The input being signed (replacing the scriptSig with scriptCode + amount)
+ // The prevout may already be contained in hashPrevout, and the nSequence
+ // may already be contain in hashSequence.
+ ss << txTo.vin[nIn].prevout;
+ ss << static_cast<const CScriptBase&>(scriptCode);
+ ss << amount;
+ ss << txTo.vin[nIn].nSequence;
+ // Outputs (none/one/all, depending on flags)
+ ss << hashOutputs;
+ // Locktime
+ ss << txTo.nLockTime;
+ // Sighash type
+ ss << nHashType;
+
+ return ss.GetHash();
+ }
+
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
if (nIn >= txTo.vin.size()) {
// nIn out of range
@@ -1136,7 +1196,7 @@ bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned cha
return pubkey.Verify(sighash, vchSig);
}
-bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
+bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
@@ -1149,7 +1209,7 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
int nHashType = vchSig.back();
vchSig.pop_back();
- uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
+ uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
if (!VerifySignature(vchSig, pubkey, sighash))
return false;
@@ -1280,7 +1340,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
}
- if (!EvalScript(stack, scriptPubKey, flags, checker, serror)) {
+ if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_WITNESS_V0, serror)) {
return false;
}
@@ -1307,12 +1367,12 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
}
vector<vector<unsigned char> > stack, stackCopy;
- if (!EvalScript(stack, scriptSig, flags, checker, serror))
+ if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror))
// serror is set
return false;
if (flags & SCRIPT_VERIFY_P2SH)
stackCopy = stack;
- if (!EvalScript(stack, scriptPubKey, flags, checker, serror))
+ if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_BASE, serror))
// serror is set
return false;
if (stack.empty())
@@ -1358,7 +1418,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
popstack(stack);
- if (!EvalScript(stack, pubKey2, flags, checker, serror))
+ if (!EvalScript(stack, pubKey2, flags, checker, SIGVERSION_BASE, serror))
// serror is set
return false;
if (stack.empty())
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 6f13e75d78..8643729425 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -98,12 +98,18 @@ enum
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
-uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
+enum SigVersion
+{
+ SIGVERSION_BASE = 0,
+ SIGVERSION_WITNESS_V0 = 1,
+};
+
+uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion);
class BaseSignatureChecker
{
public:
- virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
+ virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
return false;
}
@@ -126,13 +132,14 @@ class TransactionSignatureChecker : public BaseSignatureChecker
private:
const CTransaction* txTo;
unsigned int nIn;
+ const CAmount amount;
protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
- TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : txTo(txToIn), nIn(nInIn) {}
- bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
+ TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn) {}
+ bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const;
bool CheckLockTime(const CScriptNum& nLockTime) const;
bool CheckSequence(const CScriptNum& nSequence) const;
};
@@ -146,7 +153,7 @@ public:
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
};
-bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);
+bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = NULL);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = NULL);
#endif // BITCOIN_SCRIPT_INTERPRETER_H
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 62d874eed4..83bb0cfa29 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -18,8 +18,7 @@ using namespace std;
typedef std::vector<unsigned char> valtype;
-static const CAmount amountZero = 0;
-TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn, amountZero) {}
+TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode) const
{
@@ -27,7 +26,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
if (!keystore->GetKey(address, key))
return false;
- uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
+ uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, SIGVERSION_BASE);
if (!key.Sign(hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
@@ -186,7 +185,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
if (sigs.count(pubkey))
continue; // Already got a sig for this pubkey
- if (checker.CheckSig(sig, pubkey, scriptPubKey))
+ if (checker.CheckSig(sig, pubkey, scriptPubKey, SIGVERSION_BASE))
{
sigs[pubkey] = sig;
break;
@@ -256,10 +255,10 @@ static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatur
return CScript();
}
-CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CAmount& amount,
const CScript& scriptSig1, const CScript& scriptSig2)
{
- TransactionSignatureChecker checker(&txTo, nIn, amountZero);
+ TransactionSignatureChecker checker(&txTo, nIn, amount);
return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2);
}
@@ -271,9 +270,9 @@ CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecke
Solver(scriptPubKey, txType, vSolutions);
vector<valtype> stack1;
- EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
+ EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE);
vector<valtype> stack2;
- EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
+ EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE);
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
}
@@ -285,7 +284,7 @@ class DummySignatureChecker : public BaseSignatureChecker
public:
DummySignatureChecker() {}
- bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
+ bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
return true;
}
diff --git a/src/script/sign.h b/src/script/sign.h
index 47a9cde7f4..f54511f7a6 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -35,10 +35,11 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
const CTransaction* txTo;
unsigned int nIn;
int nHashType;
+ CAmount amount;
const TransactionSignatureChecker checker;
public:
- TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn=SIGHASH_ALL);
+ TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);
const BaseSignatureChecker& Checker() const { return checker; }
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
};
@@ -62,6 +63,6 @@ bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutab
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);
+CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CAmount& amount, const CScript& scriptSig1, const CScript& scriptSig2);
#endif // BITCOIN_SCRIPT_SIGN_H