|
|
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
|
|
// Copyright (c) 2009-2013 The Bitcoin developers
|
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
#include "script.h"
|
|
|
|
|
|
|
|
#include "core.h"
|
|
|
|
#include "hash.h"
|
|
|
|
#include "key.h"
|
|
|
|
#include "keystore.h"
|
|
|
|
#include "crypto/sha1.h"
|
|
|
|
#include "crypto/sha2.h"
|
|
|
|
#include "crypto/ripemd160.h"
|
|
|
|
#include "sync.h"
|
|
|
|
#include "uint256.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
#include <boost/foreach.hpp>
|
|
|
|
#include <boost/tuple/tuple.hpp>
|
|
|
|
#include <boost/tuple/tuple_comparison.hpp>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace boost;
|
|
|
|
|
|
|
|
typedef vector<unsigned char> valtype;
|
|
|
|
static const valtype vchFalse(0);
|
|
|
|
static const valtype vchZero(0);
|
|
|
|
static const valtype vchTrue(1, 1);
|
|
|
|
static const CScriptNum bnZero(0);
|
|
|
|
static const CScriptNum bnOne(1);
|
|
|
|
static const CScriptNum bnFalse(0);
|
|
|
|
static const CScriptNum bnTrue(1);
|
|
|
|
|
|
|
|
bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags);
|
|
|
|
|
|
|
|
bool CastToBool(const valtype& vch)
|
|
|
|
{
|
|
|
|
for (unsigned int i = 0; i < vch.size(); i++)
|
|
|
|
{
|
|
|
|
if (vch[i] != 0)
|
|
|
|
{
|
|
|
|
// Can be negative zero
|
|
|
|
if (i == vch.size()-1 && vch[i] == 0x80)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Script is a stack machine (like Forth) that evaluates a predicate
|
|
|
|
// returning a bool indicating valid or not. There are no loops.
|
|
|
|
//
|
|
|
|
#define stacktop(i) (stack.at(stack.size()+(i)))
|
|
|
|
#define altstacktop(i) (altstack.at(altstack.size()+(i)))
|
|
|
|
static inline void popstack(vector<valtype>& stack)
|
|
|
|
{
|
|
|
|
if (stack.empty())
|
|
|
|
throw runtime_error("popstack() : stack empty");
|
|
|
|
stack.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const char* GetTxnOutputType(txnouttype t)
|
|
|
|
{
|
|
|
|
switch (t)
|
|
|
|
{
|
|
|
|
case TX_NONSTANDARD: return "nonstandard";
|
|
|
|
case TX_PUBKEY: return "pubkey";
|
|
|
|
case TX_PUBKEYHASH: return "pubkeyhash";
|
|
|
|
case TX_SCRIPTHASH: return "scripthash";
|
|
|
|
case TX_MULTISIG: return "multisig";
|
|
|
|
case TX_NULL_DATA: return "nulldata";
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const char* GetOpName(opcodetype opcode)
|
|
|
|
{
|
|
|
|
switch (opcode)
|
|
|
|
{
|
|
|
|
// push value
|
|
|
|
case OP_0 : return "0";
|
|
|
|
case OP_PUSHDATA1 : return "OP_PUSHDATA1";
|
|
|
|
case OP_PUSHDATA2 : return "OP_PUSHDATA2";
|
|
|
|
case OP_PUSHDATA4 : return "OP_PUSHDATA4";
|
|
|
|
case OP_1NEGATE : return "-1";
|
|
|
|
case OP_RESERVED : return "OP_RESERVED";
|
|
|
|
case OP_1 : return "1";
|
|
|
|
case OP_2 : return "2";
|
|
|
|
case OP_3 : return "3";
|
|
|
|
case OP_4 : return "4";
|
|
|
|
case OP_5 : return "5";
|
|
|
|
case OP_6 : return "6";
|
|
|
|
case OP_7 : return "7";
|
|
|
|
case OP_8 : return "8";
|
|
|
|
case OP_9 : return "9";
|
|
|
|
case OP_10 : return "10";
|
|
|
|
case OP_11 : return "11";
|
|
|
|
case OP_12 : return "12";
|
|
|
|
case OP_13 : return "13";
|
|
|
|
case OP_14 : return "14";
|
|
|
|
case OP_15 : return "15";
|
|
|
|
case OP_16 : return "16";
|
|
|
|
|
|
|
|
// control
|
|
|
|
case OP_NOP : return "OP_NOP";
|
|
|
|
case OP_VER : return "OP_VER";
|
|
|
|
case OP_IF : return "OP_IF";
|
|
|
|
case OP_NOTIF : return "OP_NOTIF";
|
|
|
|
case OP_VERIF : return "OP_VERIF";
|
|
|
|
case OP_VERNOTIF : return "OP_VERNOTIF";
|
|
|
|
case OP_ELSE : return "OP_ELSE";
|
|
|
|
case OP_ENDIF : return "OP_ENDIF";
|
|
|
|
case OP_VERIFY : return "OP_VERIFY";
|
|
|
|
case OP_RETURN : return "OP_RETURN";
|
|
|
|
|
|
|
|
// stack ops
|
|
|
|
case OP_TOALTSTACK : return "OP_TOALTSTACK";
|
|
|
|
case OP_FROMALTSTACK : return "OP_FROMALTSTACK";
|
|
|
|
case OP_2DROP : return "OP_2DROP";
|
|
|
|
case OP_2DUP : return "OP_2DUP";
|
|
|
|
case OP_3DUP : return "OP_3DUP";
|
|
|
|
case OP_2OVER : return "OP_2OVER";
|
|
|
|
case OP_2ROT : return "OP_2ROT";
|
|
|
|
case OP_2SWAP : return "OP_2SWAP";
|
|
|
|
case OP_IFDUP : return "OP_IFDUP";
|
|
|
|
case OP_DEPTH : return "OP_DEPTH";
|
|
|
|
case OP_DROP : return "OP_DROP";
|
|
|
|
case OP_DUP : return "OP_DUP";
|
|
|
|
case OP_NIP : return "OP_NIP";
|
|
|
|
case OP_OVER : return "OP_OVER";
|
|
|
|
case OP_PICK : return "OP_PICK";
|
|
|
|
case OP_ROLL : return "OP_ROLL";
|
|
|
|
case OP_ROT : return "OP_ROT";
|
|
|
|
case OP_SWAP : return "OP_SWAP";
|
|
|
|
case OP_TUCK : return "OP_TUCK";
|
|
|
|
|
|
|
|
// splice ops
|
|
|
|
case OP_CAT : return "OP_CAT";
|
|
|
|
case OP_SUBSTR : return "OP_SUBSTR";
|
|
|
|
case OP_LEFT : return "OP_LEFT";
|
|
|
|
case OP_RIGHT : return "OP_RIGHT";
|
|
|
|
case OP_SIZE : return "OP_SIZE";
|
|
|
|
|
|
|
|
// bit logic
|
|
|
|
case OP_INVERT : return "OP_INVERT";
|
|
|
|
case OP_AND : return "OP_AND";
|
|
|
|
case OP_OR : return "OP_OR";
|
|
|
|
case OP_XOR : return "OP_XOR";
|
|
|
|
case OP_EQUAL : return "OP_EQUAL";
|
|
|
|
case OP_EQUALVERIFY : return "OP_EQUALVERIFY";
|
|
|
|
case OP_RESERVED1 : return "OP_RESERVED1";
|
|
|
|
case OP_RESERVED2 : return "OP_RESERVED2";
|
|
|
|
|
|
|
|
// numeric
|
|
|
|
case OP_1ADD : return "OP_1ADD";
|
|
|
|
case OP_1SUB : return "OP_1SUB";
|
|
|
|
case OP_2MUL : return "OP_2MUL";
|
|
|
|
case OP_2DIV : return "OP_2DIV";
|
|
|
|
case OP_NEGATE : return "OP_NEGATE";
|
|
|
|
case OP_ABS : return "OP_ABS";
|
|
|
|
case OP_NOT : return "OP_NOT";
|
|
|
|
case OP_0NOTEQUAL : return "OP_0NOTEQUAL";
|
|
|
|
case OP_ADD : return "OP_ADD";
|
|
|
|
case OP_SUB : return "OP_SUB";
|
|
|
|
case OP_MUL : return "OP_MUL";
|
|
|
|
case OP_DIV : return "OP_DIV";
|
|
|
|
case OP_MOD : return "OP_MOD";
|
|
|
|
case OP_LSHIFT : return "OP_LSHIFT";
|
|
|
|
case OP_RSHIFT : return "OP_RSHIFT";
|
|
|
|
case OP_BOOLAND : return "OP_BOOLAND";
|
|
|
|
case OP_BOOLOR : return "OP_BOOLOR";
|
|
|
|
case OP_NUMEQUAL : return "OP_NUMEQUAL";
|
|
|
|
case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY";
|
|
|
|
case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL";
|
|
|
|
case OP_LESSTHAN : return "OP_LESSTHAN";
|
|
|
|
case OP_GREATERTHAN : return "OP_GREATERTHAN";
|
|
|
|
case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL";
|
|
|
|
case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL";
|
|
|
|
case OP_MIN : return "OP_MIN";
|
|
|
|
case OP_MAX : return "OP_MAX";
|
|
|
|
case OP_WITHIN : return "OP_WITHIN";
|
|
|
|
|
|
|
|
// crypto
|
|
|
|
case OP_RIPEMD160 : return "OP_RIPEMD160";
|
|
|
|
case OP_SHA1 : return "OP_SHA1";
|
|
|
|
case OP_SHA256 : return "OP_SHA256";
|
|
|
|
case OP_HASH160 : return "OP_HASH160";
|
|
|
|
case OP_HASH256 : return "OP_HASH256";
|
|
|
|
case OP_CODESEPARATOR : return "OP_CODESEPARATOR";
|
|
|
|
case OP_CHECKSIG : return "OP_CHECKSIG";
|
|
|
|
case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY";
|
|
|
|
case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
|
|
|
|
case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
|
|
|
|
|
|
|
|
// expanson
|
|
|
|
case OP_NOP1 : return "OP_NOP1";
|
|
|
|
case OP_NOP2 : return "OP_NOP2";
|
|
|
|
case OP_NOP3 : return "OP_NOP3";
|
|
|
|
case OP_NOP4 : return "OP_NOP4";
|
|
|
|
case OP_NOP5 : return "OP_NOP5";
|
|
|
|
case OP_NOP6 : return "OP_NOP6";
|
|
|
|
case OP_NOP7 : return "OP_NOP7";
|
|
|
|
case OP_NOP8 : return "OP_NOP8";
|
|
|
|
case OP_NOP9 : return "OP_NOP9";
|
|
|
|
case OP_NOP10 : return "OP_NOP10";
|
|
|
|
|
|
|
|
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
|
|
|
|
|
|
|
|
// Note:
|
|
|
|
// The template matching params OP_SMALLDATA/etc are defined in opcodetype enum
|
|
|
|
// as kind of implementation hack, they are *NOT* real opcodes. If found in real
|
|
|
|
// Script, just let the default: case deal with them.
|
|
|
|
|
|
|
|
default:
|
|
|
|
return "OP_UNKNOWN";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Only create signatures with even S, and verification mode to check.
To fix a minor malleability found by Sergio Lerner (reported here:
https://bitcointalk.org/index.php?topic=8392.msg1245898#msg1245898)
The problem is that if (R,S) is a valid ECDSA signature for a given
message and public key, (R,-S) is also valid. Modulo N (the order
of the secp256k1 curve), this means that both (R,S) and (R,N-S) are
valid. Given that N is odd, S and N-S have a different lowest bit.
We solve the problem by forcing signatures to have an even S value,
excluding one of the alternatives.
This commit just changes the signing code to always produce even S
values, and adds a verification mode to check it. This code is not
enabled anywhere yet. Existing tests in key_tests.cpp verify that
the produced signatures are still valid.
12 years ago
|
|
|
bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) {
|
|
|
|
if (!(flags & SCRIPT_VERIFY_STRICTENC))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (vchPubKey.size() < 33)
|
|
|
|
return error("Non-canonical public key: too short");
|
|
|
|
if (vchPubKey[0] == 0x04) {
|
|
|
|
if (vchPubKey.size() != 65)
|
|
|
|
return error("Non-canonical public key: invalid length for uncompressed key");
|
|
|
|
} else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) {
|
|
|
|
if (vchPubKey.size() != 33)
|
|
|
|
return error("Non-canonical public key: invalid length for compressed key");
|
|
|
|
} else {
|
|
|
|
return error("Non-canonical public key: compressed nor uncompressed");
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Only create signatures with even S, and verification mode to check.
To fix a minor malleability found by Sergio Lerner (reported here:
https://bitcointalk.org/index.php?topic=8392.msg1245898#msg1245898)
The problem is that if (R,S) is a valid ECDSA signature for a given
message and public key, (R,-S) is also valid. Modulo N (the order
of the secp256k1 curve), this means that both (R,S) and (R,N-S) are
valid. Given that N is odd, S and N-S have a different lowest bit.
We solve the problem by forcing signatures to have an even S value,
excluding one of the alternatives.
This commit just changes the signing code to always produce even S
values, and adds a verification mode to check it. This code is not
enabled anywhere yet. Existing tests in key_tests.cpp verify that
the produced signatures are still valid.
12 years ago
|
|
|
bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) {
|
|
|
|
if (!(flags & SCRIPT_VERIFY_STRICTENC))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
|
|
|
|
// A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
|
|
|
|
// Where R and S are not negative (their first byte has its highest bit not set), and not
|
|
|
|
// excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
|
|
|
|
// in which case a single 0 byte is necessary and even required).
|
|
|
|
if (vchSig.size() < 9)
|
|
|
|
return error("Non-canonical signature: too short");
|
|
|
|
if (vchSig.size() > 73)
|
|
|
|
return error("Non-canonical signature: too long");
|
|
|
|
unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY));
|
|
|
|
if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
|
|
|
|
return error("Non-canonical signature: unknown hashtype byte");
|
|
|
|
if (vchSig[0] != 0x30)
|
|
|
|
return error("Non-canonical signature: wrong type");
|
|
|
|
if (vchSig[1] != vchSig.size()-3)
|
|
|
|
return error("Non-canonical signature: wrong length marker");
|
|
|
|
unsigned int nLenR = vchSig[3];
|
|
|
|
if (5 + nLenR >= vchSig.size())
|
|
|
|
return error("Non-canonical signature: S length misplaced");
|
|
|
|
unsigned int nLenS = vchSig[5+nLenR];
|
|
|
|
if ((unsigned long)(nLenR+nLenS+7) != vchSig.size())
|
|
|
|
return error("Non-canonical signature: R+S length mismatch");
|
|
|
|
|
|
|
|
const unsigned char *R = &vchSig[4];
|
|
|
|
if (R[-2] != 0x02)
|
|
|
|
return error("Non-canonical signature: R value type mismatch");
|
|
|
|
if (nLenR == 0)
|
|
|
|
return error("Non-canonical signature: R length is zero");
|
|
|
|
if (R[0] & 0x80)
|
|
|
|
return error("Non-canonical signature: R value negative");
|
|
|
|
if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80))
|
|
|
|
return error("Non-canonical signature: R value excessively padded");
|
|
|
|
|
|
|
|
const unsigned char *S = &vchSig[6+nLenR];
|
|
|
|
if (S[-2] != 0x02)
|
|
|
|
return error("Non-canonical signature: S value type mismatch");
|
|
|
|
if (nLenS == 0)
|
|
|
|
return error("Non-canonical signature: S length is zero");
|
|
|
|
if (S[0] & 0x80)
|
|
|
|
return error("Non-canonical signature: S value negative");
|
|
|
|
if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80))
|
|
|
|
return error("Non-canonical signature: S value excessively padded");
|
|
|
|
|
|
|
|
if (flags & SCRIPT_VERIFY_LOW_S) {
|
|
|
|
// If the S value is above the order of the curve divided by two, its
|
|
|
|
// complement modulo the order could have been used instead, which is
|
|
|
|
// one byte shorter when encoded correctly.
|
|
|
|
if (!CKey::CheckSignatureElement(S, nLenS, true))
|
|
|
|
return error("Non-canonical signature: S value is unnecessarily high");
|
Only create signatures with even S, and verification mode to check.
To fix a minor malleability found by Sergio Lerner (reported here:
https://bitcointalk.org/index.php?topic=8392.msg1245898#msg1245898)
The problem is that if (R,S) is a valid ECDSA signature for a given
message and public key, (R,-S) is also valid. Modulo N (the order
of the secp256k1 curve), this means that both (R,S) and (R,N-S) are
valid. Given that N is odd, S and N-S have a different lowest bit.
We solve the problem by forcing signatures to have an even S value,
excluding one of the alternatives.
This commit just changes the signing code to always produce even S
values, and adds a verification mode to check it. This code is not
enabled anywhere yet. Existing tests in key_tests.cpp verify that
the produced signatures are still valid.
12 years ago
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType)
|
|
|
|
{
|
|
|
|
CScript::const_iterator pc = script.begin();
|
|
|
|
CScript::const_iterator pend = script.end();
|
|
|
|
CScript::const_iterator pbegincodehash = script.begin();
|
|
|
|
opcodetype opcode;
|
|
|
|
valtype vchPushValue;
|
|
|
|
vector<bool> vfExec;
|
|
|
|
vector<valtype> altstack;
|
|
|
|
if (script.size() > 10000)
|
|
|
|
return false;
|
|
|
|
int nOpCount = 0;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
while (pc < pend)
|
|
|
|
{
|
|
|
|
bool fExec = !count(vfExec.begin(), vfExec.end(), false);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Read instruction
|
|
|
|
//
|
|
|
|
if (!script.GetOp(pc, opcode, vchPushValue))
|
|
|
|
return false;
|
|
|
|
if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Note how OP_RESERVED does not count towards the opcode limit.
|
|
|
|
if (opcode > OP_16 && ++nOpCount > 201)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (opcode == OP_CAT ||
|
|
|
|
opcode == OP_SUBSTR ||
|
|
|
|
opcode == OP_LEFT ||
|
|
|
|
opcode == OP_RIGHT ||
|
|
|
|
opcode == OP_INVERT ||
|
|
|
|
opcode == OP_AND ||
|
|
|
|
opcode == OP_OR ||
|
|
|
|
opcode == OP_XOR ||
|
|
|
|
opcode == OP_2MUL ||
|
|
|
|
opcode == OP_2DIV ||
|
|
|
|
opcode == OP_MUL ||
|
|
|
|
opcode == OP_DIV ||
|
|
|
|
opcode == OP_MOD ||
|
|
|
|
opcode == OP_LSHIFT ||
|
|
|
|
opcode == OP_RSHIFT)
|
|
|
|
return false; // Disabled opcodes.
|
|
|
|
|
|
|
|
if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4)
|
|
|
|
stack.push_back(vchPushValue);
|
|
|
|
else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
|
|
|
|
switch (opcode)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Push value
|
|
|
|
//
|
|
|
|
case OP_1NEGATE:
|
|
|
|
case OP_1:
|
|
|
|
case OP_2:
|
|
|
|
case OP_3:
|
|
|
|
case OP_4:
|
|
|
|
case OP_5:
|
|
|
|
case OP_6:
|
|
|
|
case OP_7:
|
|
|
|
case OP_8:
|
|
|
|
case OP_9:
|
|
|
|
case OP_10:
|
|
|
|
case OP_11:
|
|
|
|
case OP_12:
|
|
|
|
case OP_13:
|
|
|
|
case OP_14:
|
|
|
|
case OP_15:
|
|
|
|
case OP_16:
|
|
|
|
{
|
|
|
|
// ( -- value)
|
|
|
|
CScriptNum bn((int)opcode - (int)(OP_1 - 1));
|
|
|
|
stack.push_back(bn.getvch());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Control
|
|
|
|
//
|
|
|
|
case OP_NOP:
|
|
|
|
case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5:
|
|
|
|
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_IF:
|
|
|
|
case OP_NOTIF:
|
|
|
|
{
|
|
|
|
// <expression> if [statements] [else [statements]] endif
|
|
|
|
bool fValue = false;
|
|
|
|
if (fExec)
|
|
|
|
{
|
|
|
|
if (stack.size() < 1)
|
|
|
|
return false;
|
|
|
|
valtype& vch = stacktop(-1);
|
|
|
|
fValue = CastToBool(vch);
|
|
|
|
if (opcode == OP_NOTIF)
|
|
|
|
fValue = !fValue;
|
|
|
|
popstack(stack);
|
|
|
|
}
|
|
|
|
vfExec.push_back(fValue);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_ELSE:
|
|
|
|
{
|
|
|
|
if (vfExec.empty())
|
|
|
|
return false;
|
|
|
|
vfExec.back() = !vfExec.back();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_ENDIF:
|
|
|
|
{
|
|
|
|
if (vfExec.empty())
|
|
|
|
return false;
|
|
|
|
vfExec.pop_back();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_VERIFY:
|
|
|
|
{
|
|
|
|
// (true -- ) or
|
|
|
|
// (false -- false) and return
|
|
|
|
if (stack.size() < 1)
|
|
|
|
return false;
|
|
|
|
bool fValue = CastToBool(stacktop(-1));
|
|
|
|
if (fValue)
|
|
|
|
popstack(stack);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_RETURN:
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Stack ops
|
|
|
|
//
|
|
|
|
case OP_TOALTSTACK:
|
|
|
|
{
|
|
|
|
if (stack.size() < 1)
|
|
|
|
return false;
|
|
|
|
altstack.push_back(stacktop(-1));
|
|
|
|
popstack(stack);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_FROMALTSTACK:
|
|
|
|
{
|
|
|
|
if (altstack.size() < 1)
|
|
|
|
return false;
|
|
|
|
stack.push_back(altstacktop(-1));
|
|
|
|
popstack(altstack);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_2DROP:
|
|
|
|
{
|
|
|
|
// (x1 x2 -- )
|
|
|
|
if (stack.size() < 2)
|
|
|
|
return false;
|
|
|
|
popstack(stack);
|
|
|
|
popstack(stack);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_2DUP:
|
|
|
|
{
|
|
|
|
// (x1 x2 -- x1 x2 x1 x2)
|
|
|
|
if (stack.size() < 2)
|
|
|
|
return false;
|
|
|
|
valtype vch1 = stacktop(-2);
|
|
|
|
valtype vch2 = stacktop(-1);
|
|
|
|
stack.push_back(vch1);
|
|
|
|
stack.push_back(vch2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_3DUP:
|
|
|
|
{
|
|
|
|
// (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
|
|
|
|
if (stack.size() < 3)
|
|
|
|
return false;
|
|
|
|
valtype vch1 = stacktop(-3);
|
|
|
|
valtype vch2 = stacktop(-2);
|
|
|
|
valtype vch3 = stacktop(-1);
|
|
|
|
stack.push_back(vch1);
|
|
|
|
stack.push_back(vch2);
|
|
|
|
stack.push_back(vch3);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_2OVER:
|
|
|
|
{
|
|
|
|
// (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
|
|
|
|
if (stack.size() < 4)
|
|
|
|
return false;
|
|
|
|
valtype vch1 = stacktop(-4);
|
|
|
|
valtype vch2 = stacktop(-3);
|
|
|
|
stack.push_back(vch1);
|
|
|
|
stack.push_back(vch2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_2ROT:
|
|
|
|
{
|
|
|
|
// (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
|
|
|
|
if (stack.size() < 6)
|
|
|
|
return false;
|
|
|
|
valtype vch1 = stacktop(-6);
|
|
|
|
valtype vch2 = stacktop(-5);
|
|
|
|
stack.erase(stack.end()-6, stack.end()-4);
|
|
|
|
stack.push_back(vch1);
|
|
|
|
stack.push_back(vch2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_2SWAP:
|
|
|
|
{
|
|
|
|
// (x1 x2 x3 x4 -- x3 x4 x1 x2)
|
|
|
|
if (stack.size() < 4)
|
|
|
|
return false;
|
|
|
|
swap(stacktop(-4), stacktop(-2));
|
|
|
|
swap(stacktop(-3), stacktop(-1));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_IFDUP:
|
|
|
|
{
|
|
|
|
// (x - 0 | x x)
|
|
|
|
if (stack.size() < 1)
|
|
|
|
return false;
|
|
|
|
valtype vch = stacktop(-1);
|
|
|
|
if (CastToBool(vch))
|
|
|
|
stack.push_back(vch);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_DEPTH:
|
|
|
|
{
|
|
|
|
// -- stacksize
|
|
|
|
CScriptNum bn(stack.size());
|
|
|
|
stack.push_back(bn.getvch());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_DROP:
|
|
|
|
{
|
|
|
|
// (x -- )
|
|
|
|
if (stack.size() < 1)
|
|
|
|
return false;
|
|
|
|
popstack(stack);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_DUP:
|
|
|
|
{
|
|
|
|
// (x -- x x)
|
|
|
|
if (stack.size() < 1)
|
|
|
|
return false;
|
|
|
|
valtype vch = stacktop(-1);
|
|
|
|
stack.push_back(vch);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_NIP:
|
|
|
|
{
|
|
|
|
// (x1 x2 -- x2)
|
|
|
|
if (stack.size() < 2)
|
|
|
|
return false;
|
|
|
|
stack.erase(stack.end() - 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_OVER:
|
|
|
|
{
|
|
|
|
// (x1 x2 -- x1 x2 x1)
|
|
|
|
if (stack.size() < 2)
|
|
|
|
return false;
|
|
|
|
valtype vch = stacktop(-2);
|
|
|
|
stack.push_back(vch);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_PICK:
|
|
|
|
case OP_ROLL:
|
|
|
|
{
|
|
|
|
// (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
|
|
|
|
// (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
|
|
|
|
if (stack.size() < 2)
|
|
|
|
return false;
|
|
|
|
int n = CScriptNum(stacktop(-1)).getint();
|
|
|
|
popstack(stack);
|
|
|
|
if (n < 0 || n >= (int)stack.size())
|
|
|
|
return false;
|
|
|
|
valtype vch = stacktop(-n-1);
|
|
|
|
if (opcode == OP_ROLL)
|
|
|
|
stack.erase(stack.end()-n-1);
|
|
|
|
stack.push_back(vch);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_ROT:
|
|
|
|
{
|
|
|
|
// (x1 x2 x3 -- x2 x3 x1)
|
|
|
|
// x2 x1 x3 after first swap
|
|
|
|
// x2 x3 x1 after second swap
|
|
|
|
if (stack.size() < 3)
|
|
|
|
return false;
|
|
|
|
swap(stacktop(-3), stacktop(-2));
|
|
|
|
swap(stacktop(-2), stacktop(-1));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_SWAP:
|
|
|
|
{
|
|
|
|
// (x1 x2 -- x2 x1)
|
|
|
|
if (stack.size() < 2)
|
|
|
|
return false;
|
|
|
|
swap(stacktop(-2), stacktop(-1));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_TUCK:
|
|
|
|
{
|
|
|
|
// (x1 x2 -- x2 x1 x2)
|
|
|
|
if (stack.size() < 2)
|
|
|
|
return false;
|
|
|
|
valtype vch = stacktop(-1);
|
|
|
|
stack.insert(stack.end()-2, vch);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case OP_SIZE:
|
|
|
|
{
|
|
|
|
// (in -- in size)
|
|
|
|
if (stack.size() < 1)
|
|
|
|
return false;
|
|
|
|
CScriptNum bn(stacktop(-1).size());
|
|
|
|
stack.push_back(bn.getvch());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Bitwise logic
|
|
|
|
//
|
|
|
|
case OP_EQUAL:
|
|
|
|
case OP_EQUALVERIFY:
|
|
|
|
//case OP_NOTEQUAL: // use OP_NUMNOTEQUAL
|
|
|
|
{
|
|
|
|
// (x1 x2 - bool)
|
|
|
|
if (stack.size() < 2)
|
|
|
|
return false;
|
|
|
|
valtype& vch1 = stacktop(-2);
|
|
|
|
valtype& vch2 = stacktop(-1);
|
|
|
|
bool fEqual = (vch1 == vch2);
|
|
|
|
// OP_NOTEQUAL is disabled because it would be too easy to say
|
|
|
|
// something like n != 1 and have some wiseguy pass in 1 with extra
|
|
|
|
// zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001)
|
|
|
|
//if (opcode == OP_NOTEQUAL)
|
|
|
|
// fEqual = !fEqual;
|
|
|
|
popstack(stack);
|
|
|
|
popstack(stack);
|
|
|
|
stack.push_back(fEqual ? vchTrue : vchFalse);
|
|
|
|
if (opcode == OP_EQUALVERIFY)
|
|
|
|
{
|
|
|
|
if (fEqual)
|
|
|
|
popstack(stack);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Numeric
|
|
|
|
//
|
|
|
|
case OP_1ADD:
|
|
|
|
case OP_1SUB:
|
|
|
|
case OP_NEGATE:
|
|
|
|
case OP_ABS:
|
|
|
|
case OP_NOT:
|
|
|
|
case OP_0NOTEQUAL:
|
|
|
|
{
|
|
|
|
// (in -- out)
|
|
|
|
if (stack.size() < 1)
|
|
|
|
return false;
|
|
|
|
CScriptNum bn(stacktop(-1));
|
|
|
|
switch (opcode)
|
|
|
|
{
|
|
|
|
case OP_1ADD: bn += bnOne; break;
|
|
|
|
case OP_1SUB: bn -= bnOne; break;
|
|
|
|
case OP_NEGATE: bn = -bn; break;
|
|
|
|
case OP_ABS: if (bn < bnZero) bn = -bn; break;
|
|
|
|
case OP_NOT: bn = (bn == bnZero); break;
|
|
|
|
case OP_0NOTEQUAL: bn = (bn != bnZero); break;
|
|
|
|
default: assert(!"invalid opcode"); break;
|
|
|
|
}
|
|
|
|
popstack(stack);
|
|
|
|
stack.push_back(bn.getvch());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_ADD:
|
|
|
|
case OP_SUB:
|
|
|
|
case OP_BOOLAND:
|
|
|
|
case OP_BOOLOR:
|
|
|
|
case OP_NUMEQUAL:
|
|
|
|
case OP_NUMEQUALVERIFY:
|
|
|
|
case OP_NUMNOTEQUAL:
|
|
|
|
case OP_LESSTHAN:
|
|
|
|
case OP_GREATERTHAN:
|
|
|
|
case OP_LESSTHANOREQUAL:
|
|
|
|
case OP_GREATERTHANOREQUAL:
|
|
|
|
case OP_MIN:
|
|
|
|
case OP_MAX:
|
|
|
|
{
|
|
|
|
// (x1 x2 -- out)
|
|
|
|
if (stack.size() < 2)
|
|
|
|
return false;
|
|
|
|
CScriptNum bn1(stacktop(-2));
|
|
|
|
CScriptNum bn2(stacktop(-1));
|
|
|
|
CScriptNum bn(0);
|
|
|
|
switch (opcode)
|
|
|
|
{
|
|
|
|
case OP_ADD:
|
|
|
|
bn = bn1 + bn2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_SUB:
|
|
|
|
bn = bn1 - bn2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break;
|
|
|
|
case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break;
|
|
|
|
case OP_NUMEQUAL: bn = (bn1 == bn2); break;
|
|
|
|
case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break;
|
|
|
|
case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break;
|
|
|
|
case OP_LESSTHAN: bn = (bn1 < bn2); break;
|
|
|
|
case OP_GREATERTHAN: bn = (bn1 > bn2); break;
|
|
|
|
case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break;
|
|
|
|
case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break;
|
|
|
|
case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break;
|
|
|
|
case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break;
|
|
|
|
default: assert(!"invalid opcode"); break;
|
|
|
|
}
|
|
|
|
popstack(stack);
|
|
|
|
popstack(stack);
|
|
|
|
stack.push_back(bn.getvch());
|
|
|
|
|
|
|
|
if (opcode == OP_NUMEQUALVERIFY)
|
|
|
|
{
|
|
|
|
if (CastToBool(stacktop(-1)))
|
|
|
|
popstack(stack);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_WITHIN:
|
|
|
|
{
|
|
|
|
// (x min max -- out)
|
|
|
|
if (stack.size() < 3)
|
|
|
|
return false;
|
|
|
|
CScriptNum bn1(stacktop(-3));
|
|
|
|
CScriptNum bn2(stacktop(-2));
|
|
|
|
CScriptNum bn3(stacktop(-1));
|
|
|
|
bool fValue = (bn2 <= bn1 && bn1 < bn3);
|
|
|
|
popstack(stack);
|
|
|
|
popstack(stack);
|
|
|
|
popstack(stack);
|
|
|
|
stack.push_back(fValue ? vchTrue : vchFalse);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Crypto
|
|
|
|
//
|
|
|
|
case OP_RIPEMD160:
|
|
|
|
case OP_SHA1:
|
|
|
|
case OP_SHA256:
|
|
|
|
case OP_HASH160:
|
|
|
|
case OP_HASH256:
|
|
|
|
{
|
|
|
|
// (in -- hash)
|
|
|
|
if (stack.size() < 1)
|
|
|
|
return false;
|
|
|
|
valtype& vch = stacktop(-1);
|
|
|
|
valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32);
|
|
|
|
if (opcode == OP_RIPEMD160)
|
|
|
|
CRIPEMD160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);
|
|
|
|
else if (opcode == OP_SHA1)
|
|
|
|
CSHA1().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);
|
|
|
|
else if (opcode == OP_SHA256)
|
|
|
|
CSHA256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);
|
|
|
|
else if (opcode == OP_HASH160)
|
|
|
|
CHash160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);
|
|
|
|
else if (opcode == OP_HASH256)
|
|
|
|
CHash256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);
|
|
|
|
popstack(stack);
|
|
|
|
stack.push_back(vchHash);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_CODESEPARATOR:
|
|
|
|
{
|
|
|
|
// Hash starts after the code separator
|
|
|
|
pbegincodehash = pc;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_CHECKSIG:
|
|
|
|
case OP_CHECKSIGVERIFY:
|
|
|
|
{
|
|
|
|
// (sig pubkey -- bool)
|
|
|
|
if (stack.size() < 2)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
valtype& vchSig = stacktop(-2);
|
|
|
|
valtype& vchPubKey = stacktop(-1);
|
|
|
|
|
|
|
|
// Subset of script starting at the most recent codeseparator
|
|
|
|
CScript scriptCode(pbegincodehash, pend);
|
|
|
|
|
|
|
|
// Drop the signature, since there's no way for a signature to sign itself
|
|
|
|
scriptCode.FindAndDelete(CScript(vchSig));
|
|
|
|
|
Only create signatures with even S, and verification mode to check.
To fix a minor malleability found by Sergio Lerner (reported here:
https://bitcointalk.org/index.php?topic=8392.msg1245898#msg1245898)
The problem is that if (R,S) is a valid ECDSA signature for a given
message and public key, (R,-S) is also valid. Modulo N (the order
of the secp256k1 curve), this means that both (R,S) and (R,N-S) are
valid. Given that N is odd, S and N-S have a different lowest bit.
We solve the problem by forcing signatures to have an even S value,
excluding one of the alternatives.
This commit just changes the signing code to always produce even S
values, and adds a verification mode to check it. This code is not
enabled anywhere yet. Existing tests in key_tests.cpp verify that
the produced signatures are still valid.
12 years ago
|
|
|
bool fSuccess = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) &&
|
|
|
|
CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags);
|
|
|
|
|
|
|
|
popstack(stack);
|
|
|
|
popstack(stack);
|
|
|
|
stack.push_back(fSuccess ? vchTrue : vchFalse);
|
|
|
|
if (opcode == OP_CHECKSIGVERIFY)
|
|
|
|
{
|
|
|
|
if (fSuccess)
|
|
|
|
popstack(stack);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_CHECKMULTISIG:
|
|
|
|
case OP_CHECKMULTISIGVERIFY:
|
|
|
|
{
|
|
|
|
// ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool)
|
|
|
|
|
|
|
|
int i = 1;
|
|
|
|
if ((int)stack.size() < i)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int nKeysCount = CScriptNum(stacktop(-i)).getint();
|
|
|
|
if (nKeysCount < 0 || nKeysCount > 20)
|
|
|
|
return false;
|
|
|
|
nOpCount += nKeysCount;
|
|
|
|
if (nOpCount > 201)
|
|
|
|
return false;
|
|
|
|
int ikey = ++i;
|
|
|
|
i += nKeysCount;
|
|
|
|
if ((int)stack.size() < i)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int nSigsCount = CScriptNum(stacktop(-i)).getint();
|
|
|
|
if (nSigsCount < 0 || nSigsCount > nKeysCount)
|
|
|
|
return false;
|
|
|
|
int isig = ++i;
|
|
|
|
i += nSigsCount;
|
|
|
|
if ((int)stack.size() < i)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Subset of script starting at the most recent codeseparator
|
|
|
|
CScript scriptCode(pbegincodehash, pend);
|
|
|
|
|
|
|
|
// Drop the signatures, since there's no way for a signature to sign itself
|
|
|
|
for (int k = 0; k < nSigsCount; k++)
|
|
|
|
{
|
|
|
|
valtype& vchSig = stacktop(-isig-k);
|
|
|
|
scriptCode.FindAndDelete(CScript(vchSig));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool fSuccess = true;
|
|
|
|
while (fSuccess && nSigsCount > 0)
|
|
|
|
{
|
|
|
|
valtype& vchSig = stacktop(-isig);
|
|
|
|
valtype& vchPubKey = stacktop(-ikey);
|
|
|
|
|
|
|
|
// Check signature
|
Only create signatures with even S, and verification mode to check.
To fix a minor malleability found by Sergio Lerner (reported here:
https://bitcointalk.org/index.php?topic=8392.msg1245898#msg1245898)
The problem is that if (R,S) is a valid ECDSA signature for a given
message and public key, (R,-S) is also valid. Modulo N (the order
of the secp256k1 curve), this means that both (R,S) and (R,N-S) are
valid. Given that N is odd, S and N-S have a different lowest bit.
We solve the problem by forcing signatures to have an even S value,
excluding one of the alternatives.
This commit just changes the signing code to always produce even S
values, and adds a verification mode to check it. This code is not
enabled anywhere yet. Existing tests in key_tests.cpp verify that
the produced signatures are still valid.
12 years ago
|
|
|
bool fOk = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) &&
|
|
|
|
CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags);
|
|
|
|
|
|
|
|
if (fOk) {
|
|
|
|
isig++;
|
|
|
|
nSigsCount--;
|
|
|
|
}
|
|
|
|
ikey++;
|
|
|
|
nKeysCount--;
|
|
|
|
|
|
|
|
// If there are more signatures left than keys left,
|
|
|
|
// then too many signatures have failed
|
|
|
|
if (nSigsCount > nKeysCount)
|
|
|
|
fSuccess = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clean up stack of actual arguments
|
|
|
|
while (i-- > 1)
|
|
|
|
popstack(stack);
|
|
|
|
|
|
|
|
// A bug causes CHECKMULTISIG to consume one extra argument
|
|
|
|
// whose contents were not checked in any way.
|
|
|
|
//
|
|
|
|
// Unfortunately this is a potential source of mutability,
|
|
|
|
// so optionally verify it is exactly equal to zero prior
|
|
|
|
// to removing it from the stack.
|
|
|
|
if (stack.size() < 1)
|
|
|
|
return false;
|
|
|
|
if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size())
|
|
|
|
return error("CHECKMULTISIG dummy argument not null");
|
|
|
|
popstack(stack);
|
|
|
|
|
|
|
|
stack.push_back(fSuccess ? vchTrue : vchFalse);
|
|
|
|
|
|
|
|
if (opcode == OP_CHECKMULTISIGVERIFY)
|
|
|
|
{
|
|
|
|
if (fSuccess)
|
|
|
|
popstack(stack);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Size limits
|
|
|
|
if (stack.size() + altstack.size() > 1000)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!vfExec.empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
/** Wrapper that serializes like CTransaction, but with the modifications
|
|
|
|
* required for the signature hash done in-place
|
|
|
|
*/
|
|
|
|
class CTransactionSignatureSerializer {
|
|
|
|
private:
|
|
|
|
const CTransaction &txTo; // reference to the spending transaction (the one being serialized)
|
|
|
|
const CScript &scriptCode; // output script being consumed
|
|
|
|
const unsigned int nIn; // input index of txTo being signed
|
|
|
|
const bool fAnyoneCanPay; // whether the hashtype has the SIGHASH_ANYONECANPAY flag set
|
|
|
|
const bool fHashSingle; // whether the hashtype is SIGHASH_SINGLE
|
|
|
|
const bool fHashNone; // whether the hashtype is SIGHASH_NONE
|
|
|
|
|
|
|
|
public:
|
|
|
|
CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :
|
|
|
|
txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn),
|
|
|
|
fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)),
|
|
|
|
fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE),
|
|
|
|
fHashNone((nHashTypeIn & 0x1f) == SIGHASH_NONE) {}
|
|
|
|
|
|
|
|
/** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */
|
|
|
|
template<typename S>
|
|
|
|
void SerializeScriptCode(S &s, int nType, int nVersion) const {
|
|
|
|
CScript::const_iterator it = scriptCode.begin();
|
|
|
|
CScript::const_iterator itBegin = it;
|
|
|
|
opcodetype opcode;
|
|
|
|
unsigned int nCodeSeparators = 0;
|
|
|
|
while (scriptCode.GetOp(it, opcode)) {
|
|
|
|
if (opcode == OP_CODESEPARATOR)
|
|
|
|
nCodeSeparators++;
|
|
|
|
}
|
|
|
|
::WriteCompactSize(s, scriptCode.size() - nCodeSeparators);
|
|
|
|
it = itBegin;
|
|
|
|
while (scriptCode.GetOp(it, opcode)) {
|
|
|
|
if (opcode == OP_CODESEPARATOR) {
|
|
|
|
s.write((char*)&itBegin[0], it-itBegin-1);
|
|
|
|
itBegin = it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s.write((char*)&itBegin[0], it-itBegin);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Serialize an input of txTo */
|
|
|
|
template<typename S>
|
|
|
|
void SerializeInput(S &s, unsigned int nInput, int nType, int nVersion) const {
|
|
|
|
// In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized
|
|
|
|
if (fAnyoneCanPay)
|
|
|
|
nInput = nIn;
|
|
|
|
// Serialize the prevout
|
|
|
|
::Serialize(s, txTo.vin[nInput].prevout, nType, nVersion);
|
|
|
|
// Serialize the script
|
|
|
|
if (nInput != nIn)
|
|
|
|
// Blank out other inputs' signatures
|
|
|
|
::Serialize(s, CScript(), nType, nVersion);
|
|
|
|
else
|
|
|
|
SerializeScriptCode(s, nType, nVersion);
|
|
|
|
// Serialize the nSequence
|
|
|
|
if (nInput != nIn && (fHashSingle || fHashNone))
|
|
|
|
// let the others update at will
|
|
|
|
::Serialize(s, (int)0, nType, nVersion);
|
|
|
|
else
|
|
|
|
::Serialize(s, txTo.vin[nInput].nSequence, nType, nVersion);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Serialize an output of txTo */
|
|
|
|
template<typename S>
|
|
|
|
void SerializeOutput(S &s, unsigned int nOutput, int nType, int nVersion) const {
|
|
|
|
if (fHashSingle && nOutput != nIn)
|
|
|
|
// Do not lock-in the txout payee at other indices as txin
|
|
|
|
::Serialize(s, CTxOut(), nType, nVersion);
|
|
|
|
else
|
|
|
|
::Serialize(s, txTo.vout[nOutput], nType, nVersion);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Serialize txTo */
|
|
|
|
template<typename S>
|
|
|
|
void Serialize(S &s, int nType, int nVersion) const {
|
|
|
|
// Serialize nVersion
|
|
|
|
::Serialize(s, txTo.nVersion, nType, nVersion);
|
|
|
|
// Serialize vin
|
|
|
|
unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size();
|
|
|
|
::WriteCompactSize(s, nInputs);
|
|
|
|
for (unsigned int nInput = 0; nInput < nInputs; nInput++)
|
|
|
|
SerializeInput(s, nInput, nType, nVersion);
|
|
|
|
// Serialize vout
|
|
|
|
unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? nIn+1 : txTo.vout.size());
|
|
|
|
::WriteCompactSize(s, nOutputs);
|
|
|
|
for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++)
|
|
|
|
SerializeOutput(s, nOutput, nType, nVersion);
|
|
|
|
// Serialie nLockTime
|
|
|
|
::Serialize(s, txTo.nLockTime, nType, nVersion);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // anon namespace
|
|
|
|
|
|
|
|
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
|
|
|
|
{
|
|
|
|
if (nIn >= txTo.vin.size()) {
|
|
|
|
LogPrintf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for invalid use of SIGHASH_SINGLE
|
|
|
|
if ((nHashType & 0x1f) == SIGHASH_SINGLE) {
|
|
|
|
if (nIn >= txTo.vout.size()) {
|
|
|
|
LogPrintf("ERROR: SignatureHash() : nOut=%d out of range\n", nIn);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wrapper to serialize only the necessary parts of the transaction being signed
|
|
|
|
CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType);
|
|
|
|
|
|
|
|
// Serialize and hash
|
|
|
|
CHashWriter ss(SER_GETHASH, 0);
|
|
|
|
ss << txTmp << nHashType;
|
|
|
|
return ss.GetHash();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Valid signature cache, to avoid doing expensive ECDSA signature checking
|
|
|
|
// twice for every transaction (once when accepted into memory pool, and
|
|
|
|
// again when accepted into the block chain)
|
|
|
|
|
|
|
|
class CSignatureCache
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
// sigdata_type is (signature hash, signature, public key):
|
|
|
|
typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type;
|
|
|
|
std::set< sigdata_type> setValid;
|
|
|
|
boost::shared_mutex cs_sigcache;
|
|
|
|
|
|
|
|
public:
|
|
|
|
bool
|
|
|
|
Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
|
|
|
|
{
|
|
|
|
boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
|
|
|
|
|
|
|
|
sigdata_type k(hash, vchSig, pubKey);
|
|
|
|
std::set<sigdata_type>::iterator mi = setValid.find(k);
|
|
|
|
if (mi != setValid.end())
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
|
|
|
|
{
|
|
|
|
// DoS prevention: limit cache size to less than 10MB
|
|
|
|
// (~200 bytes per cache entry times 50,000 entries)
|
|
|
|
// Since there are a maximum of 20,000 signature operations per block
|
|
|
|
// 50,000 is a reasonable default.
|
|
|
|
int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
|
|
|
|
if (nMaxCacheSize <= 0) return;
|
|
|
|
|
|
|
|
boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
|
|
|
|
|
|
|
|
while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize)
|
|
|
|
{
|
|
|
|
// Evict a random entry. Random because that helps
|
|
|
|
// foil would-be DoS attackers who might try to pre-generate
|
|
|
|
// and re-use a set of valid signatures just-slightly-greater
|
|
|
|
// than our cache size.
|
|
|
|
uint256 randomHash = GetRandHash();
|
|
|
|
std::vector<unsigned char> unused;
|
|
|
|
std::set<sigdata_type>::iterator it =
|
|
|
|
setValid.lower_bound(sigdata_type(randomHash, unused, unused));
|
|
|
|
if (it == setValid.end())
|
|
|
|
it = setValid.begin();
|
|
|
|
setValid.erase(*it);
|
|
|
|
}
|
|
|
|
|
|
|
|
sigdata_type k(hash, vchSig, pubKey);
|
|
|
|
setValid.insert(k);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode,
|
|
|
|
const CTransaction& txTo, unsigned int nIn, int nHashType, int flags)
|
|
|
|
{
|
|
|
|
static CSignatureCache signatureCache;
|
|
|
|
|
|
|
|
CPubKey pubkey(vchPubKey);
|
|
|
|
if (!pubkey.IsValid())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Hash type is one byte tacked on to the end of the signature
|
|
|
|
if (vchSig.empty())
|
|
|
|
return false;
|
|
|
|
if (nHashType == 0)
|
|
|
|
nHashType = vchSig.back();
|
|
|
|
else if (nHashType != vchSig.back())
|
|
|
|
return false;
|
|
|
|
vchSig.pop_back();
|
|
|
|
|
|
|
|
uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType);
|
|
|
|
|
|
|
|
if (signatureCache.Get(sighash, vchSig, pubkey))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!pubkey.Verify(sighash, vchSig))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!(flags & SCRIPT_VERIFY_NOCACHE))
|
|
|
|
signatureCache.Set(sighash, vchSig, pubkey);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
|
|
|
|
//
|
|
|
|
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
|
|
|
|
{
|
|
|
|
// Templates
|
|
|
|
static multimap<txnouttype, CScript> mTemplates;
|
|
|
|
if (mTemplates.empty())
|
|
|
|
{
|
|
|
|
// Standard tx, sender provides pubkey, receiver adds signature
|
|
|
|
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
|
|
|
|
|
|
|
|
// Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
|
|
|
|
mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
|
|
|
|
|
|
|
|
// Sender provides N pubkeys, receivers provides M signatures
|
|
|
|
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
|
|
|
|
|
|
|
|
// Empty, provably prunable, data-carrying output
|
|
|
|
if (GetBoolArg("-datacarrier", true))
|
|
|
|
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
|
|
|
|
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shortcut for pay-to-script-hash, which are more constrained than the other types:
|
|
|
|
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
|
|
|
|
if (scriptPubKey.IsPayToScriptHash())
|
|
|
|
{
|
|
|
|
typeRet = TX_SCRIPTHASH;
|
|
|
|
vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
|
|
|
|
vSolutionsRet.push_back(hashBytes);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Scan templates
|
|
|
|
const CScript& script1 = scriptPubKey;
|
|
|
|
BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
|
|
|
|
{
|
|
|
|
const CScript& script2 = tplate.second;
|
|
|
|
vSolutionsRet.clear();
|
|
|
|
|
|
|
|
opcodetype opcode1, opcode2;
|
|
|
|
vector<unsigned char> vch1, vch2;
|
|
|
|
|
|
|
|
// Compare
|
|
|
|
CScript::const_iterator pc1 = script1.begin();
|
|
|
|
CScript::const_iterator pc2 = script2.begin();
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
if (pc1 == script1.end() && pc2 == script2.end())
|
|
|
|
{
|
|
|
|
// Found a match
|
|
|
|
typeRet = tplate.first;
|
|
|
|
if (typeRet == TX_MULTISIG)
|
|
|
|
{
|
|
|
|
// Additional checks for TX_MULTISIG:
|
|
|
|
unsigned char m = vSolutionsRet.front()[0];
|
|
|
|
unsigned char n = vSolutionsRet.back()[0];
|
|
|
|
if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!script1.GetOp(pc1, opcode1, vch1))
|
|
|
|
break;
|
|
|
|
if (!script2.GetOp(pc2, opcode2, vch2))
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Template matching opcodes:
|
|
|
|
if (opcode2 == OP_PUBKEYS)
|
|
|
|
{
|
|
|
|
while (vch1.size() >= 33 && vch1.size() <= 65)
|
|
|
|
{
|
|
|
|
vSolutionsRet.push_back(vch1);
|
|
|
|
if (!script1.GetOp(pc1, opcode1, vch1))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!script2.GetOp(pc2, opcode2, vch2))
|
|
|
|
break;
|
|
|
|
// Normal situation is to fall through
|
|
|
|
// to other if/else statements
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opcode2 == OP_PUBKEY)
|
|
|
|
{
|
|
|
|
if (vch1.size() < 33 || vch1.size() > 65)
|
|
|
|
break;
|
|
|
|
vSolutionsRet.push_back(vch1);
|
|
|
|
}
|
|
|
|
else if (opcode2 == OP_PUBKEYHASH)
|
|
|
|
{
|
|
|
|
if (vch1.size() != sizeof(uint160))
|
|
|
|
break;
|
|
|
|
vSolutionsRet.push_back(vch1);
|
|
|
|
}
|
|
|
|
else if (opcode2 == OP_SMALLINTEGER)
|
|
|
|
{ // Single-byte small integer pushed onto vSolutions
|
|
|
|
if (opcode1 == OP_0 ||
|
|
|
|
(opcode1 >= OP_1 && opcode1 <= OP_16))
|
|
|
|
{
|
|
|
|
char n = (char)CScript::DecodeOP_N(opcode1);
|
|
|
|
vSolutionsRet.push_back(valtype(1, n));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (opcode2 == OP_SMALLDATA)
|
|
|
|
{
|
|
|
|
// small pushdata, <= MAX_OP_RETURN_RELAY bytes
|
|
|
|
if (vch1.size() > MAX_OP_RETURN_RELAY)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (opcode1 != opcode2 || vch1 != vch2)
|
|
|
|
{
|
|
|
|
// Others must match exactly
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vSolutionsRet.clear();
|
|
|
|
typeRet = TX_NONSTANDARD;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
|
|
|
|
{
|
|
|
|
CKey key;
|
|
|
|
if (!keystore.GetKey(address, key))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
vector<unsigned char> vchSig;
|
|
|
|
if (!key.Sign(hash, vchSig))
|
|
|
|
return false;
|
|
|
|
vchSig.push_back((unsigned char)nHashType);
|
|
|
|
scriptSigRet << vchSig;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
|
|
|
|
{
|
|
|
|
int nSigned = 0;
|
|
|
|
int nRequired = multisigdata.front()[0];
|
|
|
|
for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
|
|
|
|
{
|
|
|
|
const valtype& pubkey = multisigdata[i];
|
|
|
|
CKeyID keyID = CPubKey(pubkey).GetID();
|
|
|
|
if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
|
|
|
++nSigned;
|
|
|
|
}
|
|
|
|
return nSigned==nRequired;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
|
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
scriptSigRet.clear();
|
|
|
|
|
|
|
|
vector<valtype> vSolutions;
|
|
|
|
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
CKeyID keyID;
|
|
|
|
switch (whichTypeRet)
|
|
|
|
{
|
|
|
|
case TX_NONSTANDARD:
|
|
|
|
case TX_NULL_DATA:
|
|
|
|
return false;
|
|
|
|
case TX_PUBKEY:
|
|
|
|
keyID = CPubKey(vSolutions[0]).GetID();
|
|
|
|
return Sign1(keyID, keystore, hash, nHashType, scriptSigRet);
|
|
|
|
case TX_PUBKEYHASH:
|
|
|
|
keyID = CKeyID(uint160(vSolutions[0]));
|
|
|
|
if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CPubKey vch;
|
|
|
|
keystore.GetPubKey(keyID, vch);
|
|
|
|
scriptSigRet << vch;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
case TX_SCRIPTHASH:
|
|
|
|
return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet);
|
|
|
|
|
|
|
|
case TX_MULTISIG:
|
|
|
|
scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
|
|
|
|
return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet));
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions)
|
|
|
|
{
|
|
|
|
switch (t)
|
|
|
|
{
|
|
|
|
case TX_NONSTANDARD:
|
|
|
|
case TX_NULL_DATA:
|
|
|
|
return -1;
|
|
|
|
case TX_PUBKEY:
|
|
|
|
return 1;
|
|
|
|
case TX_PUBKEYHASH:
|
|
|
|
return 2;
|
|
|
|
case TX_MULTISIG:
|
|
|
|
if (vSolutions.size() < 1 || vSolutions[0].size() < 1)
|
|
|
|
return -1;
|
|
|
|
return vSolutions[0][0] + 1;
|
|
|
|
case TX_SCRIPTHASH:
|
|
|
|
return 1; // doesn't include args needed by the script
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
|
|
|
{
|
|
|
|
vector<valtype> vSolutions;
|
|
|
|
if (!Solver(scriptPubKey, whichType, vSolutions))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (whichType == TX_MULTISIG)
|
|
|
|
{
|
|
|
|
unsigned char m = vSolutions.front()[0];
|
|
|
|
unsigned char n = vSolutions.back()[0];
|
|
|
|
// Support up to x-of-3 multisig txns as standard
|
|
|
|
if (n < 1 || n > 3)
|
|
|
|
return false;
|
|
|
|
if (m < 1 || m > n)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return whichType != TX_NONSTANDARD;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
|
|
|
|
{
|
|
|
|
unsigned int nResult = 0;
|
|
|
|
BOOST_FOREACH(const valtype& pubkey, pubkeys)
|
|
|
|
{
|
|
|
|
CKeyID keyID = CPubKey(pubkey).GetID();
|
|
|
|
if (keystore.HaveKey(keyID))
|
|
|
|
++nResult;
|
|
|
|
}
|
|
|
|
return nResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class CKeyStoreIsMineVisitor : public boost::static_visitor<bool>
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
const CKeyStore *keystore;
|
|
|
|
public:
|
|
|
|
CKeyStoreIsMineVisitor(const CKeyStore *keystoreIn) : keystore(keystoreIn) { }
|
|
|
|
bool operator()(const CNoDestination &dest) const { return false; }
|
|
|
|
bool operator()(const CKeyID &keyID) const { return keystore->HaveKey(keyID); }
|
|
|
|
bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); }
|
|
|
|
};
|
|
|
|
|
|
|
|
isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
|
|
|
|
{
|
|
|
|
CScript script;
|
|
|
|
script.SetDestination(dest);
|
|
|
|
return IsMine(keystore, script);
|
|
|
|
}
|
|
|
|
|
|
|
|
isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
|
|
|
{
|
|
|
|
vector<valtype> vSolutions;
|
|
|
|
txnouttype whichType;
|
|
|
|
if (!Solver(scriptPubKey, whichType, vSolutions)) {
|
|
|
|
if (keystore.HaveWatchOnly(scriptPubKey))
|
|
|
|
return ISMINE_WATCH_ONLY;
|
|
|
|
return ISMINE_NO;
|
|
|
|
}
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
|
|
|
|
CKeyID keyID;
|
|
|
|
switch (whichType)
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
{
|
|
|
|
case TX_NONSTANDARD:
|
|
|
|
case TX_NULL_DATA:
|
|
|
|
break;
|
|
|
|
case TX_PUBKEY:
|
|
|
|
keyID = CPubKey(vSolutions[0]).GetID();
|
|
|
|
if (keystore.HaveKey(keyID))
|
|
|
|
return ISMINE_SPENDABLE;
|
|
|
|
break;
|
|
|
|
case TX_PUBKEYHASH:
|
|
|
|
keyID = CKeyID(uint160(vSolutions[0]));
|
|
|
|
if (keystore.HaveKey(keyID))
|
|
|
|
return ISMINE_SPENDABLE;
|
|
|
|
break;
|
|
|
|
case TX_SCRIPTHASH:
|
|
|
|
{
|
|
|
|
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
|
|
|
|
CScript subscript;
|
|
|
|
if (keystore.GetCScript(scriptID, subscript)) {
|
|
|
|
isminetype ret = IsMine(keystore, subscript);
|
|
|
|
if (ret == ISMINE_SPENDABLE)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
break;
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
}
|
|
|
|
case TX_MULTISIG:
|
|
|
|
{
|
|
|
|
// Only consider transactions "mine" if we own ALL the
|
|
|
|
// keys involved. multi-signature transactions that are
|
|
|
|
// partially owned (somebody else has a key that can spend
|
|
|
|
// them) enable spend-out-from-under-you attacks, especially
|
|
|
|
// in shared-wallet situations.
|
|
|
|
vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
|
|
|
|
if (HaveKeys(keys, keystore) == keys.size())
|
|
|
|
return ISMINE_SPENDABLE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keystore.HaveWatchOnly(scriptPubKey))
|
|
|
|
return ISMINE_WATCH_ONLY;
|
|
|
|
return ISMINE_NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
|
|
|
{
|
|
|
|
vector<valtype> vSolutions;
|
|
|
|
txnouttype whichType;
|
|
|
|
if (!Solver(scriptPubKey, whichType, vSolutions))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (whichType == TX_PUBKEY)
|
|
|
|
{
|
|
|
|
addressRet = CPubKey(vSolutions[0]).GetID();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (whichType == TX_PUBKEYHASH)
|
|
|
|
{
|
|
|
|
addressRet = CKeyID(uint160(vSolutions[0]));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (whichType == TX_SCRIPTHASH)
|
|
|
|
{
|
|
|
|
addressRet = CScriptID(uint160(vSolutions[0]));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// Multisig txns have more than one address...
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet)
|
|
|
|
{
|
|
|
|
addressRet.clear();
|
|
|
|
typeRet = TX_NONSTANDARD;
|
|
|
|
vector<valtype> vSolutions;
|
|
|
|
if (!Solver(scriptPubKey, typeRet, vSolutions))
|
|
|
|
return false;
|
|
|
|
if (typeRet == TX_NULL_DATA){
|
|
|
|
// This is data, not addresses
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeRet == TX_MULTISIG)
|
|
|
|
{
|
|
|
|
nRequiredRet = vSolutions.front()[0];
|
|
|
|
for (unsigned int i = 1; i < vSolutions.size()-1; i++)
|
|
|
|
{
|
|
|
|
CTxDestination address = CPubKey(vSolutions[i]).GetID();
|
|
|
|
addressRet.push_back(address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nRequiredRet = 1;
|
|
|
|
CTxDestination address;
|
|
|
|
if (!ExtractDestination(scriptPubKey, address))
|
|
|
|
return false;
|
|
|
|
addressRet.push_back(address);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
class CAffectedKeysVisitor : public boost::static_visitor<void> {
|
|
|
|
private:
|
|
|
|
const CKeyStore &keystore;
|
|
|
|
std::vector<CKeyID> &vKeys;
|
|
|
|
|
|
|
|
public:
|
|
|
|
CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
|
|
|
|
|
|
|
|
void Process(const CScript &script) {
|
|
|
|
txnouttype type;
|
|
|
|
std::vector<CTxDestination> vDest;
|
|
|
|
int nRequired;
|
|
|
|
if (ExtractDestinations(script, type, vDest, nRequired)) {
|
|
|
|
BOOST_FOREACH(const CTxDestination &dest, vDest)
|
|
|
|
boost::apply_visitor(*this, dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const CKeyID &keyId) {
|
|
|
|
if (keystore.HaveKey(keyId))
|
|
|
|
vKeys.push_back(keyId);
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const CScriptID &scriptId) {
|
|
|
|
CScript script;
|
|
|
|
if (keystore.GetCScript(scriptId, script))
|
|
|
|
Process(script);
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const CNoDestination &none) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys) {
|
|
|
|
CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
|
|
|
unsigned int flags, int nHashType)
|
|
|
|
{
|
|
|
|
vector<vector<unsigned char> > stack, stackCopy;
|
|
|
|
if (!EvalScript(stack, scriptSig, txTo, nIn, flags, nHashType))
|
|
|
|
return false;
|
|
|
|
if (flags & SCRIPT_VERIFY_P2SH)
|
|
|
|
stackCopy = stack;
|
|
|
|
if (!EvalScript(stack, scriptPubKey, txTo, nIn, flags, nHashType))
|
|
|
|
return false;
|
|
|
|
if (stack.empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (CastToBool(stack.back()) == false)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Additional validation for spend-to-script-hash transactions:
|
|
|
|
if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash())
|
|
|
|
{
|
|
|
|
if (!scriptSig.IsPushOnly()) // scriptSig must be literals-only
|
|
|
|
return false; // or validation fails
|
|
|
|
|
|
|
|
// stackCopy cannot be empty here, because if it was the
|
|
|
|
// P2SH HASH <> EQUAL scriptPubKey would be evaluated with
|
|
|
|
// an empty stack and the EvalScript above would return false.
|
|
|
|
assert(!stackCopy.empty());
|
|
|
|
|
|
|
|
const valtype& pubKeySerialized = stackCopy.back();
|
|
|
|
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
|
|
|
|
popstack(stackCopy);
|
|
|
|
|
|
|
|
if (!EvalScript(stackCopy, pubKey2, txTo, nIn, flags, nHashType))
|
|
|
|
return false;
|
|
|
|
if (stackCopy.empty())
|
|
|
|
return false;
|
|
|
|
return CastToBool(stackCopy.back());
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
|
|
|
// 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))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (whichType == TX_SCRIPTHASH)
|
|
|
|
{
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
txnouttype subType;
|
|
|
|
bool fSolved =
|
|
|
|
Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH;
|
|
|
|
// Append serialized subscript whether or not it is completely signed:
|
|
|
|
txin.scriptSig << static_cast<valtype>(subscript);
|
|
|
|
if (!fSolved) return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test solution
|
|
|
|
return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
|
|
|
{
|
|
|
|
assert(nIn < txTo.vin.size());
|
|
|
|
CTxIn& txin = txTo.vin[nIn];
|
|
|
|
assert(txin.prevout.n < txFrom.vout.size());
|
|
|
|
const CTxOut& txout = txFrom.vout[txin.prevout.n];
|
|
|
|
|
|
|
|
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
|
|
|
|
}
|
|
|
|
|
|
|
|
static CScript PushAll(const vector<valtype>& values)
|
|
|
|
{
|
|
|
|
CScript result;
|
|
|
|
BOOST_FOREACH(const valtype& v, values)
|
|
|
|
result << v;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn,
|
|
|
|
const vector<valtype>& vSolutions,
|
|
|
|
vector<valtype>& sigs1, vector<valtype>& sigs2)
|
|
|
|
{
|
|
|
|
// Combine all the signatures we've got:
|
|
|
|
set<valtype> allsigs;
|
|
|
|
BOOST_FOREACH(const valtype& v, sigs1)
|
|
|
|
{
|
|
|
|
if (!v.empty())
|
|
|
|
allsigs.insert(v);
|
|
|
|
}
|
|
|
|
BOOST_FOREACH(const valtype& v, sigs2)
|
|
|
|
{
|
|
|
|
if (!v.empty())
|
|
|
|
allsigs.insert(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build a map of pubkey -> signature by matching sigs to pubkeys:
|
|
|
|
assert(vSolutions.size() > 1);
|
|
|
|
unsigned int nSigsRequired = vSolutions.front()[0];
|
|
|
|
unsigned int nPubKeys = vSolutions.size()-2;
|
|
|
|
map<valtype, valtype> sigs;
|
|
|
|
BOOST_FOREACH(const valtype& sig, allsigs)
|
|
|
|
{
|
|
|
|
for (unsigned int i = 0; i < nPubKeys; i++)
|
|
|
|
{
|
|
|
|
const valtype& pubkey = vSolutions[i+1];
|
|
|
|
if (sigs.count(pubkey))
|
|
|
|
continue; // Already got a sig for this pubkey
|
|
|
|
|
|
|
|
if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0, 0))
|
|
|
|
{
|
|
|
|
sigs[pubkey] = sig;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Now build a merged CScript:
|
|
|
|
unsigned int nSigsHave = 0;
|
|
|
|
CScript result; result << OP_0; // pop-one-too-many workaround
|
|
|
|
for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
|
|
|
|
{
|
|
|
|
if (sigs.count(vSolutions[i+1]))
|
|
|
|
{
|
|
|
|
result << sigs[vSolutions[i+1]];
|
|
|
|
++nSigsHave;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Fill any missing with OP_0:
|
|
|
|
for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
|
|
|
|
result << OP_0;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
|
|
|
const txnouttype txType, const vector<valtype>& vSolutions,
|
|
|
|
vector<valtype>& sigs1, vector<valtype>& sigs2)
|
|
|
|
{
|
|
|
|
switch (txType)
|
|
|
|
{
|
|
|
|
case TX_NONSTANDARD:
|
|
|
|
case TX_NULL_DATA:
|
|
|
|
// Don't know anything about this, assume bigger one is correct:
|
|
|
|
if (sigs1.size() >= sigs2.size())
|
|
|
|
return PushAll(sigs1);
|
|
|
|
return PushAll(sigs2);
|
|
|
|
case TX_PUBKEY:
|
|
|
|
case TX_PUBKEYHASH:
|
|
|
|
// Signatures are bigger than placeholders or empty scripts:
|
|
|
|
if (sigs1.empty() || sigs1[0].empty())
|
|
|
|
return PushAll(sigs2);
|
|
|
|
return PushAll(sigs1);
|
|
|
|
case TX_SCRIPTHASH:
|
|
|
|
if (sigs1.empty() || sigs1.back().empty())
|
|
|
|
return PushAll(sigs2);
|
|
|
|
else if (sigs2.empty() || sigs2.back().empty())
|
|
|
|
return PushAll(sigs1);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Recur to combine:
|
|
|
|
valtype spk = sigs1.back();
|
|
|
|
CScript pubKey2(spk.begin(), spk.end());
|
|
|
|
|
|
|
|
txnouttype txType2;
|
|
|
|
vector<vector<unsigned char> > vSolutions2;
|
|
|
|
Solver(pubKey2, txType2, vSolutions2);
|
|
|
|
sigs1.pop_back();
|
|
|
|
sigs2.pop_back();
|
|
|
|
CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2);
|
|
|
|
result << spk;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
case TX_MULTISIG:
|
|
|
|
return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2);
|
|
|
|
}
|
|
|
|
|
|
|
|
return CScript();
|
|
|
|
}
|
|
|
|
|
|
|
|
CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
|
|
|
const CScript& scriptSig1, const CScript& scriptSig2)
|
|
|
|
{
|
|
|
|
txnouttype txType;
|
|
|
|
vector<vector<unsigned char> > vSolutions;
|
|
|
|
Solver(scriptPubKey, txType, vSolutions);
|
|
|
|
|
|
|
|
vector<valtype> stack1;
|
|
|
|
EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
|
|
|
|
vector<valtype> stack2;
|
|
|
|
EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
|
|
|
|
|
|
|
|
return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int CScript::GetSigOpCount(bool fAccurate) const
|
|
|
|
{
|
|
|
|
unsigned int n = 0;
|
|
|
|
const_iterator pc = begin();
|
|
|
|
opcodetype lastOpcode = OP_INVALIDOPCODE;
|
|
|
|
while (pc < end())
|
|
|
|
{
|
|
|
|
opcodetype opcode;
|
|
|
|
if (!GetOp(pc, opcode))
|
|
|
|
break;
|
|
|
|
if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
|
|
|
|
n++;
|
|
|
|
else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
|
|
|
|
{
|
|
|
|
if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
|
|
|
|
n += DecodeOP_N(lastOpcode);
|
|
|
|
else
|
|
|
|
n += 20;
|
|
|
|
}
|
|
|
|
lastOpcode = opcode;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
|
|
|
|
{
|
|
|
|
if (!IsPayToScriptHash())
|
|
|
|
return GetSigOpCount(true);
|
|
|
|
|
|
|
|
// This is a pay-to-script-hash scriptPubKey;
|
|
|
|
// get the last item that the scriptSig
|
|
|
|
// pushes onto the stack:
|
|
|
|
const_iterator pc = scriptSig.begin();
|
|
|
|
vector<unsigned char> data;
|
|
|
|
while (pc < scriptSig.end())
|
|
|
|
{
|
|
|
|
opcodetype opcode;
|
|
|
|
if (!scriptSig.GetOp(pc, opcode, data))
|
|
|
|
return 0;
|
|
|
|
if (opcode > OP_16)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ... and return its opcount:
|
|
|
|
CScript subscript(data.begin(), data.end());
|
|
|
|
return subscript.GetSigOpCount(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CScript::IsPayToScriptHash() const
|
|
|
|
{
|
|
|
|
// Extra-fast test for pay-to-script-hash CScripts:
|
|
|
|
return (this->size() == 23 &&
|
|
|
|
this->at(0) == OP_HASH160 &&
|
|
|
|
this->at(1) == 0x14 &&
|
|
|
|
this->at(22) == OP_EQUAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CScript::IsPushOnly() const
|
|
|
|
{
|
|
|
|
const_iterator pc = begin();
|
|
|
|
while (pc < end())
|
|
|
|
{
|
|
|
|
opcodetype opcode;
|
|
|
|
if (!GetOp(pc, opcode))
|
|
|
|
return false;
|
|
|
|
// Note that IsPushOnly() *does* consider OP_RESERVED to be a
|
|
|
|
// push-type opcode, however execution of OP_RESERVED fails, so
|
|
|
|
// it's not relevant to P2SH as the scriptSig would fail prior to
|
|
|
|
// the P2SH special validation code being executed.
|
|
|
|
if (opcode > OP_16)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CScript::HasCanonicalPushes() const
|
|
|
|
{
|
|
|
|
const_iterator pc = begin();
|
|
|
|
while (pc < end())
|
|
|
|
{
|
|
|
|
opcodetype opcode;
|
|
|
|
std::vector<unsigned char> data;
|
|
|
|
if (!GetOp(pc, opcode, data))
|
|
|
|
return false;
|
|
|
|
if (opcode > OP_16)
|
|
|
|
continue;
|
|
|
|
if (opcode < OP_PUSHDATA1 && opcode > OP_0 && (data.size() == 1 && data[0] <= 16))
|
|
|
|
// Could have used an OP_n code, rather than a 1-byte push.
|
|
|
|
return false;
|
|
|
|
if (opcode == OP_PUSHDATA1 && data.size() < OP_PUSHDATA1)
|
|
|
|
// Could have used a normal n-byte push, rather than OP_PUSHDATA1.
|
|
|
|
return false;
|
|
|
|
if (opcode == OP_PUSHDATA2 && data.size() <= 0xFF)
|
|
|
|
// Could have used an OP_PUSHDATA1.
|
|
|
|
return false;
|
|
|
|
if (opcode == OP_PUSHDATA4 && data.size() <= 0xFFFF)
|
|
|
|
// Could have used an OP_PUSHDATA2.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
class CScriptVisitor : public boost::static_visitor<bool>
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
CScript *script;
|
|
|
|
public:
|
|
|
|
CScriptVisitor(CScript *scriptin) { script = scriptin; }
|
|
|
|
|
|
|
|
bool operator()(const CNoDestination &dest) const {
|
|
|
|
script->clear();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(const CKeyID &keyID) const {
|
|
|
|
script->clear();
|
|
|
|
*script << OP_DUP << OP_HASH160 << keyID << OP_EQUALVERIFY << OP_CHECKSIG;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(const CScriptID &scriptID) const {
|
|
|
|
script->clear();
|
|
|
|
*script << OP_HASH160 << scriptID << OP_EQUAL;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void CScript::SetDestination(const CTxDestination& dest)
|
|
|
|
{
|
|
|
|
boost::apply_visitor(CScriptVisitor(this), dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CScript::SetMultisig(int nRequired, const std::vector<CPubKey>& keys)
|
|
|
|
{
|
|
|
|
this->clear();
|
|
|
|
|
|
|
|
*this << EncodeOP_N(nRequired);
|
|
|
|
BOOST_FOREACH(const CPubKey& key, keys)
|
|
|
|
*this << key;
|
|
|
|
*this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CScriptCompressor::IsToKeyID(CKeyID &hash) const
|
|
|
|
{
|
|
|
|
if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160
|
|
|
|
&& script[2] == 20 && script[23] == OP_EQUALVERIFY
|
|
|
|
&& script[24] == OP_CHECKSIG) {
|
|
|
|
memcpy(&hash, &script[3], 20);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CScriptCompressor::IsToScriptID(CScriptID &hash) const
|
|
|
|
{
|
|
|
|
if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20
|
|
|
|
&& script[22] == OP_EQUAL) {
|
|
|
|
memcpy(&hash, &script[2], 20);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const
|
|
|
|
{
|
|
|
|
if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG
|
|
|
|
&& (script[1] == 0x02 || script[1] == 0x03)) {
|
|
|
|
pubkey.Set(&script[1], &script[34]);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG
|
|
|
|
&& script[1] == 0x04) {
|
|
|
|
pubkey.Set(&script[1], &script[66]);
|
|
|
|
return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const
|
|
|
|
{
|
|
|
|
CKeyID keyID;
|
|
|
|
if (IsToKeyID(keyID)) {
|
|
|
|
out.resize(21);
|
|
|
|
out[0] = 0x00;
|
|
|
|
memcpy(&out[1], &keyID, 20);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
CScriptID scriptID;
|
|
|
|
if (IsToScriptID(scriptID)) {
|
|
|
|
out.resize(21);
|
|
|
|
out[0] = 0x01;
|
|
|
|
memcpy(&out[1], &scriptID, 20);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
CPubKey pubkey;
|
|
|
|
if (IsToPubKey(pubkey)) {
|
|
|
|
out.resize(33);
|
|
|
|
memcpy(&out[1], &pubkey[1], 32);
|
|
|
|
if (pubkey[0] == 0x02 || pubkey[0] == 0x03) {
|
|
|
|
out[0] = pubkey[0];
|
|
|
|
return true;
|
|
|
|
} else if (pubkey[0] == 0x04) {
|
|
|
|
out[0] = 0x04 | (pubkey[64] & 0x01);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const
|
|
|
|
{
|
|
|
|
if (nSize == 0 || nSize == 1)
|
|
|
|
return 20;
|
|
|
|
if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5)
|
|
|
|
return 32;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigned char> &in)
|
|
|
|
{
|
|
|
|
switch(nSize) {
|
|
|
|
case 0x00:
|
|
|
|
script.resize(25);
|
|
|
|
script[0] = OP_DUP;
|
|
|
|
script[1] = OP_HASH160;
|
|
|
|
script[2] = 20;
|
|
|
|
memcpy(&script[3], &in[0], 20);
|
|
|
|
script[23] = OP_EQUALVERIFY;
|
|
|
|
script[24] = OP_CHECKSIG;
|
|
|
|
return true;
|
|
|
|
case 0x01:
|
|
|
|
script.resize(23);
|
|
|
|
script[0] = OP_HASH160;
|
|
|
|
script[1] = 20;
|
|
|
|
memcpy(&script[2], &in[0], 20);
|
|
|
|
script[22] = OP_EQUAL;
|
|
|
|
return true;
|
|
|
|
case 0x02:
|
|
|
|
case 0x03:
|
|
|
|
script.resize(35);
|
|
|
|
script[0] = 33;
|
|
|
|
script[1] = nSize;
|
|
|
|
memcpy(&script[2], &in[0], 32);
|
|
|
|
script[34] = OP_CHECKSIG;
|
|
|
|
return true;
|
|
|
|
case 0x04:
|
|
|
|
case 0x05:
|
|
|
|
unsigned char vch[33] = {};
|
|
|
|
vch[0] = nSize - 2;
|
|
|
|
memcpy(&vch[1], &in[0], 32);
|
|
|
|
CPubKey pubkey(&vch[0], &vch[33]);
|
|
|
|
if (!pubkey.Decompress())
|
|
|
|
return false;
|
|
|
|
assert(pubkey.size() == 65);
|
|
|
|
script.resize(67);
|
|
|
|
script[0] = 65;
|
|
|
|
memcpy(&script[1], pubkey.begin(), 65);
|
|
|
|
script[66] = OP_CHECKSIG;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|