// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ #include "script/sign.h" #include "primitives/transaction.h" #include "key.h" #include "keystore.h" #include "script/standard.h" #include "uint256.h" #include "cc/CCinclude.h" #include "cc/eval.h" #include "key_io.h" #include using namespace std; typedef vector valtype; extern uint8_t ASSETCHAINS_TXPOW; extern char NSPV_wifstr[],NSPV_pubkeystr[]; extern int32_t KOMODO_NSPV; #ifndef KOMODO_NSPV_FULLNODE #define KOMODO_NSPV_FULLNODE (KOMODO_NSPV <= 0) #endif // !KOMODO_NSPV_FULLNODE #ifndef KOMODO_NSPV_SUPERLITE #define KOMODO_NSPV_SUPERLITE (KOMODO_NSPV > 0) #endif // !KOMODO_NSPV_SUPERLITE uint256 SIG_TXHASH; TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId, CKey *pprivKey, void *extraData) const { CKey key; uint256 hash; try { hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId); } catch (logic_error ex) { { fprintf(stderr,"logic error\n"); return false; } } SIG_TXHASH = hash; if ( KOMODO_NSPV_SUPERLITE ) key = DecodeSecret(NSPV_wifstr); else if (pprivKey) key = *pprivKey; else if (!keystore || !keystore->GetKey(address, key)) { fprintf(stderr,"keystore.%p error\n",keystore); return false; } //fprintf(stderr,"privkey (%s) for %s\n",NSPV_wifstr,EncodeDestination(key.GetPubKey().GetID()).c_str()); if (scriptCode.IsPayToCryptoCondition()) { CC *cc = (CC *)extraData; // assume either 1of1 or 1of2. if the condition created by the if (!cc || cc_signTreeSecp256k1Msg32(cc, key.begin(), hash.begin()) == 0) { fprintf(stderr,"CC tree error\n"); return false; } vchSig = CCSigVec(cc); if ( KOMODO_NSPV_SUPERLITE ) memset((uint8_t *)key.begin(),0,32); return true; } else { if ( ASSETCHAINS_TXPOW == 0 ) { if (!key.Sign(hash, vchSig)) { fprintf(stderr,"key.Sign error\n"); return false; } else { //fprintf(stderr,"signed success %s\n",(char *)HexStr(vchSig).c_str()); } } else { if (!key.Sign(hash, vchSig, rand())) return false; } } vchSig.push_back((unsigned char)nHashType); if ( KOMODO_NSPV_SUPERLITE ) memset((uint8_t *)key.begin(),0,32); return true; } static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, uint32_t consensusBranchId) { vector vchSig; if (!creator.CreateSig(vchSig, address, scriptCode, consensusBranchId)) { fprintf(stderr,"Sign1 creatsig error\n"); return false; } ret.push_back(vchSig); return true; } static bool SignN(const vector& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, uint32_t consensusBranchId) { 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, creator, scriptCode, ret, consensusBranchId)) ++nSigned; } return nSigned==nRequired; } CC *CCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2) { std::vector pks; pks.push_back(CCNewSecp256k1(pk1)); pks.push_back(CCNewSecp256k1(pk2)); CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode)); CC *Sig = CCNewThreshold(1, pks); return CCNewThreshold(2, {condCC, Sig}); } CC *CCcond1(uint8_t evalcode,CPubKey pk) { std::vector pks; pks.push_back(CCNewSecp256k1(pk)); CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode)); CC *Sig = CCNewThreshold(1, pks); return CCNewThreshold(2, {condCC, Sig}); } std::vector &GetCryptoConditions() { static bool initialized = false; static std::vector vCC = std::vector(); CCcontract_info C; if (!initialized) { // this should initialize any desired auto-signed crypto-conditions } return vCC; } bool GetCCByUnspendableAddress(struct CCcontract_info *cp, char *addrstr) { std::vector &vCC = GetCryptoConditions(); bool found = false; for (int i = 0; i < vCC.size(); i++) { if (strcmp(addrstr, vCC[i].unspendableCCaddr) == 0) { found = true; *cp = vCC[i]; break; } } return found; } bool CCinitLite(struct CCcontract_info *cp, uint8_t evalcode) { std::vector &vCC = GetCryptoConditions(); bool found = false; for (int i = 0; i < vCC.size(); i++) { if (vCC[i].evalcode == evalcode) { found = true; *cp = vCC[i]; break; } } return found; } bool _Getscriptaddress(char *destaddr, const CScript &scriptPubKey) { CTxDestination address; txnouttype whichType; std::vector> vvch = std::vector>(); if (Solver(scriptPubKey, whichType, vvch) && vvch[0].size() == 20) { address = CKeyID(uint160(vvch[0])); strcpy(destaddr,(char *)CBitcoinAddress(address).ToString().c_str()); return(true); } fprintf(stderr,"Solver for scriptPubKey failed\n%s\n", scriptPubKey.ToString().c_str()); return(false); } CScript _CCPubKey(const CC *cond) { unsigned char buf[1000]; size_t len = cc_conditionBinary(cond, buf); return CScript() << std::vector(buf, buf+len) << OP_CHECKCRYPTOCONDITION; } static bool SignStepCC(const BaseSignatureCreator& creator, const CScript& scriptPubKey, vector &vSolutions, vector& ret, uint32_t consensusBranchId) { CScript subScript; vector vPK; vector vParams = vector(); COptCCParams p; // get information to sign with CCcontract_info C; scriptPubKey.IsPayToCryptoCondition(&subScript, vParams); if (vParams.empty()) { // get the keyID address of the cc and if it is an unspendable cc address, use its pubkey // we have nothing else char addr[64]; if (_Getscriptaddress(addr, subScript) && GetCCByUnspendableAddress(&C, addr)) { vPK.push_back(CPubKey(ParseHex(C.CChexstr))); p = COptCCParams(p.VERSION, C.evalcode, 1, 1, vPK, vParams); } } else { p = COptCCParams(vParams[0]); } if (p.IsValid() && p.vKeys.size() >= p.n) { bool is1of2 = (p.m == 1 && p.n == 2); CKey privKey; // must be a valid cc eval code if (CCinitLite(&C, p.evalCode)) { // pay to cc address is a valid tx if (!is1of2) { bool havePriv = creator.KeyStore().GetKey(p.vKeys[0].GetID(), privKey); // if we don't have the private key, it must be the unspendable address if (!havePriv && (p.vKeys[0] == CPubKey(ParseHex(C.CChexstr)))) { privKey = CKey(); std::vector vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv)); privKey.Set(vch.begin(), vch.end(), false); } CC *cc = CCcond1(p.evalCode, p.vKeys[0]); if (cc) { vector vch; if (creator.CreateSig(vch, p.vKeys[0].GetID(), _CCPubKey(cc), consensusBranchId, &privKey, (void *)cc)) { ret.push_back(vch); } else { fprintf(stderr,"vin has 1of1 CC signing error with address.(%s)\n", p.vKeys[0].GetID().ToString().c_str()); } cc_free(cc); return ret.size() != 0; } } else { // first of priv key in our key store or contract address is what we sign with for (auto pk : p.vKeys) { if (creator.IsKeystoreValid() && creator.KeyStore().GetKey(pk.GetID(), privKey) && privKey.IsValid()) break; if (pk == CPubKey(ParseHex(C.CChexstr))) { privKey = CKey(); std::vector vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv)); privKey.Set(vch.begin(), vch.end(), false); break; } } if (!privKey.IsValid()) return false; CC *cc = CCcond1of2(p.evalCode, p.vKeys[0], p.vKeys[1]); if (cc) { vector vch; if (creator.CreateSig(vch, p.vKeys[0].GetID(), _CCPubKey(cc), consensusBranchId, &privKey, (void *)cc)) { ret.push_back(vch); } else { fprintf(stderr,"vin has 1of2 CC signing error with addresses.(%s)\n(%s)\n", p.vKeys[0].GetID().ToString().c_str(), p.vKeys[1].GetID().ToString().c_str()); } cc_free(cc); return ret.size() != 0; } } } } return false; } /** * Sign scriptPubKey using signature made with creator. * 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. */ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey, std::vector& ret, txnouttype& whichTypeRet, uint32_t consensusBranchId) { CScript scriptRet; uint160 h160; ret.clear(); vector vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) { // if this is a CLTV script, solve for the destination after CLTV if (scriptPubKey.IsCheckLockTimeVerify()) { uint8_t pushOp = scriptPubKey[0]; uint32_t scriptStart = pushOp + 3; // check post CLTV script CScript postfix = CScript(scriptPubKey.size() > scriptStart ? scriptPubKey.begin() + scriptStart : scriptPubKey.end(), scriptPubKey.end()); // check again with only postfix subscript if (!Solver(postfix, whichTypeRet, vSolutions)) return false; } else 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, creator, scriptPubKey, ret, consensusBranchId); case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (!Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId)) { fprintf(stderr,"sign1 error\n"); return false; } else { if ( KOMODO_NSPV_FULLNODE ) { CPubKey vch; creator.KeyStore().GetPubKey(keyID, vch); ret.push_back(ToByteVector(vch)); } else ret.push_back(ParseHex(NSPV_pubkeystr)); } return true; case TX_SCRIPTHASH: if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) { ret.push_back(std::vector(scriptRet.begin(), scriptRet.end())); return true; } return false; case TX_CRYPTOCONDITION: return SignStepCC(creator, scriptPubKey, vSolutions, ret, consensusBranchId); case TX_MULTISIG: ret.push_back(valtype()); // workaround CHECKMULTISIG bug return (SignN(vSolutions, creator, scriptPubKey, ret, consensusBranchId)); default: return false; } } static CScript PushAll(const vector& values) { CScript result; BOOST_FOREACH(const valtype& v, values) { if (v.size() == 0) { result << OP_0; } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) { result << CScript::EncodeOP_N(v[0]); } else { result << v; } } return result; } bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata, uint32_t consensusBranchId) { CScript script = fromPubKey; bool solved = true; std::vector result; txnouttype whichType; solved = SignStep(creator, script, result, whichType, consensusBranchId); CScript subscript; if (solved && whichType == TX_SCRIPTHASH) { // Solver returns the subscript that needs to be evaluated; // the final scriptSig is the signatures from that // and then the serialized subscript: script = subscript = CScript(result[0].begin(), result[0].end()); solved = solved && SignStep(creator, script, result, whichType, consensusBranchId) && whichType != TX_SCRIPTHASH; result.push_back(std::vector(subscript.begin(), subscript.end())); } sigdata.scriptSig = PushAll(result); // Test solution return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker(), consensusBranchId); } SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn) { SignatureData data; assert(tx.vin.size() > nIn); data.scriptSig = tx.vin[nIn].scriptSig; return data; } void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data) { assert(tx.vin.size() > nIn); tx.vin[nIn].scriptSig = data.scriptSig; } bool SignSignature( const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType, uint32_t consensusBranchId) { assert(nIn < txTo.vin.size()); CTransaction txToConst(txTo); TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType); SignatureData sigdata; bool ret = ProduceSignature(creator, fromPubKey, sigdata, consensusBranchId); UpdateTransaction(txTo, nIn, sigdata); return ret; } bool SignSignature( const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType, uint32_t consensusBranchId) { 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, txout.nValue, nHashType, consensusBranchId); } static vector CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const vector& vSolutions, const vector& sigs1, const vector& sigs2, uint32_t consensusBranchId) { // Combine all the signatures we've got: set 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 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 (checker.CheckSig(sig, pubkey, scriptPubKey, consensusBranchId)) { sigs[pubkey] = sig; break; } } } // Now build a merged CScript: unsigned int nSigsHave = 0; std::vector result; result.push_back(valtype()); // pop-one-too-many workaround for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) { if (sigs.count(vSolutions[i+1])) { result.push_back(sigs[vSolutions[i+1]]); ++nSigsHave; } } // Fill any missing with OP_0: for (unsigned int i = nSigsHave; i < nSigsRequired; i++) result.push_back(valtype()); return result; } namespace { struct Stacks { std::vector script; Stacks() {} explicit Stacks(const std::vector& scriptSigStack_) : script(scriptSigStack_) {} explicit Stacks(const SignatureData& data, uint32_t consensusBranchId) { EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), consensusBranchId); } SignatureData Output() const { SignatureData result; result.scriptSig = PushAll(script); return result; } }; } static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const txnouttype txType, const vector& vSolutions, Stacks sigs1, Stacks sigs2, uint32_t consensusBranchId) { switch (txType) { case TX_NONSTANDARD: case TX_NULL_DATA: // Don't know anything about this, assume bigger one is correct: if (sigs1.script.size() >= sigs2.script.size()) return sigs1; return sigs2; case TX_PUBKEY: case TX_PUBKEYHASH: case TX_CRYPTOCONDITION: // Signatures are bigger than placeholders or empty scripts: if (sigs1.script.empty() || sigs1.script[0].empty()) return sigs2; return sigs1; case TX_SCRIPTHASH: if (sigs1.script.empty() || sigs1.script.back().empty()) return sigs2; else if (sigs2.script.empty() || sigs2.script.back().empty()) return sigs1; else { // Recur to combine: valtype spk = sigs1.script.back(); CScript pubKey2(spk.begin(), spk.end()); txnouttype txType2; vector > vSolutions2; Solver(pubKey2, txType2, vSolutions2); sigs1.script.pop_back(); sigs2.script.pop_back(); Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, consensusBranchId); result.script.push_back(spk); return result; } case TX_MULTISIG: return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, consensusBranchId)); default: return Stacks(); } } SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2, uint32_t consensusBranchId) { txnouttype txType; vector > vSolutions; Solver(scriptPubKey, txType, vSolutions); return CombineSignatures( scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1, consensusBranchId), Stacks(scriptSig2, consensusBranchId), consensusBranchId).Output(); } namespace { /** Dummy signature checker which accepts all signatures. */ class DummySignatureChecker : public BaseSignatureChecker { public: DummySignatureChecker() {} bool CheckSig( const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const { return true; } }; const DummySignatureChecker dummyChecker; } const BaseSignatureChecker& DummySignatureCreator::Checker() const { return dummyChecker; } bool DummySignatureCreator::CreateSig( std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId, CKey *key, void *extraData) const { // Create a dummy signature that is a valid DER-encoding vchSig.assign(72, '\000'); vchSig[0] = 0x30; vchSig[1] = 69; vchSig[2] = 0x02; vchSig[3] = 33; vchSig[4] = 0x01; vchSig[4 + 33] = 0x02; vchSig[5 + 33] = 32; vchSig[6 + 33] = 0x01; vchSig[6 + 33 + 32] = SIGHASH_ALL; return true; }