Skip to content

Commit

Permalink
Add signature version 1 with updated sighash
Browse files Browse the repository at this point in the history
Includes simplifications by Eric Lombrozo.
  • Loading branch information
sipa committed Jan 11, 2016
1 parent 6c53939 commit 7414455
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 59 deletions.
2 changes: 1 addition & 1 deletion src/policy/policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
// IsStandardTx() will have already returned false
// and this method isn't called.
std::vector<std::vector<unsigned char> > stack;
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker()))
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), 0))
return false;

if (whichType == TX_SCRIPTHASH)
Expand Down
76 changes: 66 additions & 10 deletions src/script/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,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, int sigversion, ScriptError* serror)
{
static const CScriptNum bnZero(0);
static const CScriptNum bnOne(1);
Expand Down Expand Up @@ -835,7 +835,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
//serror is set
return false;
}
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode);
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);

popstack(stack);
popstack(stack);
Expand Down Expand Up @@ -903,7 +903,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++;
Expand Down Expand Up @@ -1066,8 +1066,64 @@ class CTransactionSignatureSerializer {

} // 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, int sigversion)
{
if (sigversion == 1) {
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
Expand Down Expand Up @@ -1096,7 +1152,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, int sigversion) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
Expand All @@ -1109,7 +1165,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;
Expand Down Expand Up @@ -1182,7 +1238,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
return set_success(serror);
}

if (!EvalScript(stack, scriptPubKey, flags, checker, serror)) {
if (!EvalScript(stack, scriptPubKey, flags, checker, 1, serror)) {
return false;
}
// Scripts inside witness implicitly require cleanstack behaviour
Expand All @@ -1208,12 +1264,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, 0, 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, 0, serror))
// serror is set
return false;
if (stack.empty())
Expand Down Expand Up @@ -1259,7 +1315,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, 0, serror))
// serror is set
return false;
if (stack.empty())
Expand Down
11 changes: 6 additions & 5 deletions src/script/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ 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);
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, int 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, int sigversion) const
{
return false;
}
Expand All @@ -112,13 +112,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, int sigversion) const;
bool CheckLockTime(const CScriptNum& nLockTime) const;
};

Expand All @@ -131,7 +132,7 @@ class MutableTransactionSignatureChecker : public TransactionSignatureChecker
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, int 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
Loading

0 comments on commit 7414455

Please sign in to comment.