lbrycrd/src/script/sign.cpp

261 lines
8.7 KiB
C++
Raw Normal View History

2014-08-27 17:22:33 +02:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
2014-08-27 17:22:33 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "script/sign.h"
#include "core/transaction.h"
2014-08-27 17:22:33 +02:00
#include "key.h"
#include "keystore.h"
#include "script/standard.h"
#include "uint256.h"
#include <boost/foreach.hpp>
using namespace std;
typedef vector<unsigned char> valtype;
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 << ToByteVector(vch);
2014-08-27 17:22:33 +02:00
}
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;
}
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
2014-09-10 16:16:09 +02:00
return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(txTo, nIn));
2014-08-27 17:22:33 +02:00
}
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 (SignatureChecker(txTo, nIn).CheckSig(sig, pubkey, scriptPubKey))
2014-08-27 17:22:33 +02:00
{
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;
2014-09-10 16:16:09 +02:00
EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
2014-08-27 17:22:33 +02:00
vector<valtype> stack2;
2014-09-10 16:16:09 +02:00
EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
2014-08-27 17:22:33 +02:00
return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
}