Changeset View
Changeset View
Standalone View
Standalone View
src/script/sign.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <script/sign.h> | #include <script/sign.h> | ||||
#include <key.h> | #include <key.h> | ||||
#include <policy/policy.h> | #include <policy/policy.h> | ||||
#include <primitives/transaction.h> | #include <primitives/transaction.h> | ||||
#include <script/standard.h> | #include <script/standard.h> | ||||
#include <uint256.h> | #include <uint256.h> | ||||
typedef std::vector<uint8_t> valtype; | typedef std::vector<uint8_t> valtype; | ||||
TransactionSignatureCreator::TransactionSignatureCreator( | TransactionSignatureCreator::TransactionSignatureCreator( | ||||
const SigningProvider *provider, const CTransaction *txToIn, | const CTransaction *txToIn, unsigned int nInIn, const Amount amountIn, | ||||
unsigned int nInIn, const Amount amountIn, SigHashType sigHashTypeIn) | SigHashType sigHashTypeIn) | ||||
: BaseSignatureCreator(provider), txTo(txToIn), nIn(nInIn), | : txTo(txToIn), nIn(nInIn), amount(amountIn), sigHashType(sigHashTypeIn), | ||||
amount(amountIn), sigHashType(sigHashTypeIn), | |||||
checker(txTo, nIn, amountIn) {} | checker(txTo, nIn, amountIn) {} | ||||
bool TransactionSignatureCreator::CreateSig(std::vector<uint8_t> &vchSig, | bool TransactionSignatureCreator::CreateSig(const SigningProvider &provider, | ||||
std::vector<uint8_t> &vchSig, | |||||
const CKeyID &address, | const CKeyID &address, | ||||
const CScript &scriptCode) const { | const CScript &scriptCode) const { | ||||
CKey key; | CKey key; | ||||
if (!m_provider->GetKey(address, key)) { | if (!provider.GetKey(address, key)) { | ||||
return false; | return false; | ||||
} | } | ||||
uint256 hash = SignatureHash(scriptCode, *txTo, nIn, sigHashType, amount); | uint256 hash = SignatureHash(scriptCode, *txTo, nIn, sigHashType, amount); | ||||
if (!key.SignECDSA(hash, vchSig)) { | if (!key.SignECDSA(hash, vchSig)) { | ||||
return false; | return false; | ||||
} | } | ||||
vchSig.push_back(uint8_t(sigHashType.getRawSigHashType())); | vchSig.push_back(uint8_t(sigHashType.getRawSigHashType())); | ||||
return true; | return true; | ||||
} | } | ||||
static bool Sign1(const CKeyID &address, const BaseSignatureCreator &creator, | static bool Sign1(const SigningProvider &provider, const CKeyID &address, | ||||
const BaseSignatureCreator &creator, | |||||
const CScript &scriptCode, std::vector<valtype> &ret) { | const CScript &scriptCode, std::vector<valtype> &ret) { | ||||
std::vector<uint8_t> vchSig; | std::vector<uint8_t> vchSig; | ||||
if (!creator.CreateSig(vchSig, address, scriptCode)) { | if (!creator.CreateSig(provider, vchSig, address, scriptCode)) { | ||||
return false; | return false; | ||||
} | } | ||||
ret.push_back(vchSig); | ret.push_back(vchSig); | ||||
return true; | return true; | ||||
} | } | ||||
static bool SignN(const std::vector<valtype> &multisigdata, | static bool SignN(const SigningProvider &provider, | ||||
const std::vector<valtype> &multisigdata, | |||||
const BaseSignatureCreator &creator, | const BaseSignatureCreator &creator, | ||||
const CScript &scriptCode, std::vector<valtype> &ret) { | const CScript &scriptCode, std::vector<valtype> &ret) { | ||||
int nSigned = 0; | int nSigned = 0; | ||||
int nRequired = multisigdata.front()[0]; | int nRequired = multisigdata.front()[0]; | ||||
for (size_t i = 1; i < multisigdata.size() - 1 && nSigned < nRequired; | for (size_t i = 1; i < multisigdata.size() - 1 && nSigned < nRequired; | ||||
i++) { | i++) { | ||||
const valtype &pubkey = multisigdata[i]; | const valtype &pubkey = multisigdata[i]; | ||||
CKeyID keyID = CPubKey(pubkey).GetID(); | CKeyID keyID = CPubKey(pubkey).GetID(); | ||||
if (Sign1(keyID, creator, scriptCode, ret)) { | if (Sign1(provider, keyID, creator, scriptCode, ret)) { | ||||
++nSigned; | ++nSigned; | ||||
} | } | ||||
} | } | ||||
return nSigned == nRequired; | return nSigned == nRequired; | ||||
} | } | ||||
/** | /** | ||||
* Sign scriptPubKey using signature made with creator. | * Sign scriptPubKey using signature made with creator. | ||||
* Signatures are returned in scriptSigRet (or returns false if scriptPubKey | * Signatures are returned in scriptSigRet (or returns false if scriptPubKey | ||||
* can't be signed), unless whichTypeRet is TX_SCRIPTHASH, in which case | * can't be signed), unless whichTypeRet is TX_SCRIPTHASH, in which case | ||||
* scriptSigRet is the redemption script. | * scriptSigRet is the redemption script. | ||||
* Returns false if scriptPubKey could not be completely satisfied. | * Returns false if scriptPubKey could not be completely satisfied. | ||||
*/ | */ | ||||
static bool SignStep(const BaseSignatureCreator &creator, | static bool SignStep(const SigningProvider &provider, | ||||
const BaseSignatureCreator &creator, | |||||
const CScript &scriptPubKey, std::vector<valtype> &ret, | const CScript &scriptPubKey, std::vector<valtype> &ret, | ||||
txnouttype &whichTypeRet) { | txnouttype &whichTypeRet) { | ||||
CScript scriptRet; | CScript scriptRet; | ||||
uint160 h160; | uint160 h160; | ||||
ret.clear(); | ret.clear(); | ||||
std::vector<valtype> vSolutions; | std::vector<valtype> vSolutions; | ||||
if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) { | if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) { | ||||
return false; | return false; | ||||
} | } | ||||
CKeyID keyID; | CKeyID keyID; | ||||
switch (whichTypeRet) { | switch (whichTypeRet) { | ||||
case TX_NONSTANDARD: | case TX_NONSTANDARD: | ||||
case TX_NULL_DATA: | case TX_NULL_DATA: | ||||
return false; | return false; | ||||
case TX_PUBKEY: | case TX_PUBKEY: | ||||
keyID = CPubKey(vSolutions[0]).GetID(); | keyID = CPubKey(vSolutions[0]).GetID(); | ||||
return Sign1(keyID, creator, scriptPubKey, ret); | return Sign1(provider, keyID, creator, scriptPubKey, ret); | ||||
case TX_PUBKEYHASH: { | case TX_PUBKEYHASH: { | ||||
keyID = CKeyID(uint160(vSolutions[0])); | keyID = CKeyID(uint160(vSolutions[0])); | ||||
if (!Sign1(keyID, creator, scriptPubKey, ret)) { | if (!Sign1(provider, keyID, creator, scriptPubKey, ret)) { | ||||
return false; | return false; | ||||
} | } | ||||
CPubKey vch; | CPubKey vch; | ||||
creator.Provider().GetPubKey(keyID, vch); | provider.GetPubKey(keyID, vch); | ||||
ret.push_back(ToByteVector(vch)); | ret.push_back(ToByteVector(vch)); | ||||
return true; | return true; | ||||
} | } | ||||
case TX_SCRIPTHASH: | case TX_SCRIPTHASH: | ||||
if (creator.Provider().GetCScript(uint160(vSolutions[0]), | if (provider.GetCScript(uint160(vSolutions[0]), scriptRet)) { | ||||
scriptRet)) { | |||||
ret.push_back( | ret.push_back( | ||||
std::vector<uint8_t>(scriptRet.begin(), scriptRet.end())); | std::vector<uint8_t>(scriptRet.begin(), scriptRet.end())); | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
case TX_MULTISIG: | case TX_MULTISIG: | ||||
// workaround CHECKMULTISIG bug | // workaround CHECKMULTISIG bug | ||||
ret.push_back(valtype()); | ret.push_back(valtype()); | ||||
return (SignN(vSolutions, creator, scriptPubKey, ret)); | return (SignN(provider, vSolutions, creator, scriptPubKey, ret)); | ||||
default: | default: | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
static CScript PushAll(const std::vector<valtype> &values) { | static CScript PushAll(const std::vector<valtype> &values) { | ||||
CScript result; | CScript result; | ||||
for (const valtype &v : values) { | for (const valtype &v : values) { | ||||
if (v.size() == 0) { | if (v.size() == 0) { | ||||
result << OP_0; | result << OP_0; | ||||
} else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) { | } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) { | ||||
result << CScript::EncodeOP_N(v[0]); | result << CScript::EncodeOP_N(v[0]); | ||||
} else { | } else { | ||||
result << v; | result << v; | ||||
} | } | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
bool ProduceSignature(const BaseSignatureCreator &creator, | bool ProduceSignature(const SigningProvider &provider, | ||||
const BaseSignatureCreator &creator, | |||||
const CScript &fromPubKey, SignatureData &sigdata) { | const CScript &fromPubKey, SignatureData &sigdata) { | ||||
std::vector<valtype> result; | std::vector<valtype> result; | ||||
txnouttype whichType; | txnouttype whichType; | ||||
bool solved = SignStep(creator, fromPubKey, result, whichType); | bool solved = SignStep(provider, creator, fromPubKey, result, whichType); | ||||
CScript subscript; | CScript subscript; | ||||
if (solved && whichType == TX_SCRIPTHASH) { | if (solved && whichType == TX_SCRIPTHASH) { | ||||
// Solver returns the subscript that needs to be evaluated; the final | // Solver returns the subscript that needs to be evaluated; the final | ||||
// scriptSig is the signatures from that and then the serialized | // scriptSig is the signatures from that and then the serialized | ||||
// subscript: | // subscript: | ||||
subscript = CScript(result[0].begin(), result[0].end()); | subscript = CScript(result[0].begin(), result[0].end()); | ||||
solved = solved && SignStep(creator, subscript, result, whichType) && | solved = solved && | ||||
SignStep(provider, creator, subscript, result, whichType) && | |||||
whichType != TX_SCRIPTHASH; | whichType != TX_SCRIPTHASH; | ||||
result.push_back( | result.push_back( | ||||
std::vector<uint8_t>(subscript.begin(), subscript.end())); | std::vector<uint8_t>(subscript.begin(), subscript.end())); | ||||
} | } | ||||
sigdata.scriptSig = PushAll(result); | sigdata.scriptSig = PushAll(result); | ||||
// Test solution | // Test solution | ||||
Show All 21 Lines | |||||
} | } | ||||
bool SignSignature(const SigningProvider &provider, const CScript &fromPubKey, | bool SignSignature(const SigningProvider &provider, const CScript &fromPubKey, | ||||
CMutableTransaction &txTo, unsigned int nIn, | CMutableTransaction &txTo, unsigned int nIn, | ||||
const Amount amount, SigHashType sigHashType) { | const Amount amount, SigHashType sigHashType) { | ||||
assert(nIn < txTo.vin.size()); | assert(nIn < txTo.vin.size()); | ||||
CTransaction txToConst(txTo); | CTransaction txToConst(txTo); | ||||
TransactionSignatureCreator creator(&provider, &txToConst, nIn, amount, | TransactionSignatureCreator creator(&txToConst, nIn, amount, sigHashType); | ||||
sigHashType); | |||||
SignatureData sigdata; | SignatureData sigdata; | ||||
bool ret = ProduceSignature(creator, fromPubKey, sigdata); | bool ret = ProduceSignature(provider, creator, fromPubKey, sigdata); | ||||
UpdateTransaction(txTo, nIn, sigdata); | UpdateTransaction(txTo, nIn, sigdata); | ||||
return ret; | return ret; | ||||
} | } | ||||
bool SignSignature(const SigningProvider &provider, const CTransaction &txFrom, | bool SignSignature(const SigningProvider &provider, const CTransaction &txFrom, | ||||
CMutableTransaction &txTo, unsigned int nIn, | CMutableTransaction &txTo, unsigned int nIn, | ||||
SigHashType sigHashType) { | SigHashType sigHashType) { | ||||
assert(nIn < txTo.vin.size()); | assert(nIn < txTo.vin.size()); | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | SignatureData CombineSignatures(const CScript &scriptPubKey, | ||||
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, | return CombineSignatures(scriptPubKey, checker, txType, vSolutions, | ||||
Stacks(scriptSig1), Stacks(scriptSig2)) | Stacks(scriptSig1), Stacks(scriptSig2)) | ||||
.Output(); | .Output(); | ||||
} | } | ||||
namespace { | namespace { | ||||
/** Dummy signature checker which accepts all signatures. */ | /** Dummy signature checker which accepts all signatures. */ | ||||
class DummySignatureChecker : public BaseSignatureChecker { | class DummySignatureChecker final : public BaseSignatureChecker { | ||||
public: | public: | ||||
DummySignatureChecker() {} | DummySignatureChecker() {} | ||||
bool CheckSig(const std::vector<uint8_t> &scriptSig, | bool CheckSig(const std::vector<uint8_t> &scriptSig, | ||||
const std::vector<uint8_t> &vchPubKey, | const std::vector<uint8_t> &vchPubKey, | ||||
const CScript &scriptCode, uint32_t flags) const override { | const CScript &scriptCode, uint32_t flags) const override { | ||||
return true; | return true; | ||||
} | } | ||||
}; | }; | ||||
const DummySignatureChecker dummyChecker; | const DummySignatureChecker DUMMY_CHECKER; | ||||
} // namespace | |||||
const BaseSignatureChecker &DummySignatureCreator::Checker() const { | class DummySignatureCreator final : public BaseSignatureCreator { | ||||
return dummyChecker; | public: | ||||
DummySignatureCreator() {} | |||||
const BaseSignatureChecker &Checker() const override { | |||||
return DUMMY_CHECKER; | |||||
} | } | ||||
bool CreateSig(const SigningProvider &provider, | |||||
bool DummySignatureCreator::CreateSig(std::vector<uint8_t> &vchSig, | std::vector<uint8_t> &vchSig, const CKeyID &keyid, | ||||
const CKeyID &keyid, | |||||
const CScript &scriptCode) const { | const CScript &scriptCode) const { | ||||
// Create a dummy signature that is a valid DER-encoding | // Create a dummy signature that is a valid DER-encoding | ||||
vchSig.assign(72, '\000'); | vchSig.assign(72, '\000'); | ||||
vchSig[0] = 0x30; | vchSig[0] = 0x30; | ||||
vchSig[1] = 69; | vchSig[1] = 69; | ||||
vchSig[2] = 0x02; | vchSig[2] = 0x02; | ||||
vchSig[3] = 33; | vchSig[3] = 33; | ||||
vchSig[4] = 0x01; | vchSig[4] = 0x01; | ||||
vchSig[4 + 33] = 0x02; | vchSig[4 + 33] = 0x02; | ||||
vchSig[5 + 33] = 32; | vchSig[5 + 33] = 32; | ||||
vchSig[6 + 33] = 0x01; | vchSig[6 + 33] = 0x01; | ||||
vchSig[6 + 33 + 32] = SIGHASH_ALL | SIGHASH_FORKID; | vchSig[6 + 33 + 32] = SIGHASH_ALL | SIGHASH_FORKID; | ||||
return true; | return true; | ||||
} | } | ||||
}; | |||||
} // namespace | |||||
const BaseSignatureCreator &DUMMY_SIGNATURE_CREATOR = DummySignatureCreator(); |