text: // Copyright (c) 2009-2010 Satoshi Nakamoto
  // Copyright (c) 2009-2020 The Bitkincoin Core developers
  // Distributed under the MIT software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #ifndef BITCOIN_SCRIPT_SIGN_H
  #define BITCOIN_SCRIPT_SIGN_H
  
  #include <coins.h>
  #include <hash.h>
  #include <pubkey.h>
  #include <script/interpreter.h>
  #include <script/keyorigin.h>
  #include <span.h>
  #include <streams.h>
  
  class CKey;
  class CKeyID;
  class CScript;
  class CScriptID;
  class CTransaction;
  class SigningProvider;
  
  struct CMutableTransaction;
  
  /** Interface for signature creators. */
  class BaseSignatureCreator {
  public:
      virtual ~BaseSignatureCreator() {}
      virtual const BaseSignatureChecker& Checker() const =0;
  
      /** Create a singular (non-script) signature. */
      virtual bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0;
  };
  
  /** A signature creator for transactions. */
  class MutableTransactionSignatureCreator : public BaseSignatureCreator {
      const CMutableTransaction* txTo;
      unsigned int nIn;
      int nHashType;
      CAmount amount;
      const MutableTransactionSignatureChecker checker;
  
  public:
      MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn = SIGHASH_ALL);
      const BaseSignatureChecker& Checker() const override { return checker; }
      bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
  };
  
  /** A signature creator that just produces 71-byte empty signatures. */
  extern const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR;
  /** A signature creator that just produces 72-byte empty signatures. */
  extern const BaseSignatureCreator& DUMMY_MAXIMUM_SIGNATURE_CREATOR;
  
  typedef std::pair<CPubKey, std::vector<unsigned char>> SigPair;
  
  // This struct contains information from a transaction input and also contains signatures for that input.
  // The information contained here can be used to create a signature and is also filled by ProduceSignature
  // in order to construct final scriptSigs and scriptWitnesses.
  struct SignatureData {
      bool complete = false; ///< Stores whether the scriptSig and scriptWitness are complete
      bool witness = false; ///< Stores whether the input this SigData corresponds to is a witness input
      CScript scriptSig; ///< The scriptSig of an input. Contains complete signatures or the traditional partial signatures format
      CScript redeem_script; ///< The redeemScript (if any) for the input
      CScript witness_script; ///< The witnessScript (if any) for the input. witnessScripts are used in P2WSH outputs.
      CScriptWitness scriptWitness; ///< The scriptWitness of an input. Contains complete signatures or the traditional partial signatures format. scriptWitness is part of a transaction input per BIP 144.
      std::map<CKeyID, SigPair> signatures; ///< BIP 174 style partial signatures for the input. May contain all signatures necessary for producing a final scriptSig or scriptWitness.
      std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> misc_pubkeys;
      std::vector<CKeyID> missing_pubkeys; ///< KeyIDs of pubkeys which could not be found
      std::vector<CKeyID> missing_sigs; ///< KeyIDs of pubkeys for signatures which could not be found
      uint160 missing_redeem_script; ///< ScriptID of the missing redeemScript (if any)
      uint256 missing_witness_script; ///< SHA256 of the missing witnessScript (if any)
  
      SignatureData() {}
      explicit SignatureData(const CScript& script) : scriptSig(script) {}
      void MergeSignatureData(SignatureData sigdata);
  };
  
  // Takes a stream and multiple arguments and serializes them as if first serialized into a vector and then into the stream
  // The resulting output into the stream has the total serialized length of all of the objects followed by all objects concatenated with each other.
  template<typename Stream, typename... X>
  void SerializeToVector(Stream& s, const X&... args)
  {
      WriteCompactSize(s, GetSerializeSizeMany(s.GetVersion(), args...));
      SerializeMany(s, args...);
  }
  
  // Takes a stream and multiple arguments and unserializes them first as a vector then each object individually in the order provided in the arguments
  template<typename Stream, typename... X>
  void UnserializeFromVector(Stream& s, X&... args)
  {
      size_t expected_size = ReadCompactSize(s);
      size_t remaining_before = s.size();
      UnserializeMany(s, args...);
      size_t remaining_after = s.size();
      if (remaining_after + expected_size != remaining_before) {
          throw std::ios_base::failure("Size of value was not the stated size");
      }
  }
  
  // Deserialize HD keypaths into a map
  template<typename Stream>
  void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
  {
      // Make sure that the key is the size of pubkey + 1
      if (key.size() != CPubKey::SIZE + 1 && key.size() != CPubKey::COMPRESSED_SIZE + 1) {
          throw std::ios_base::failure("Size of key was not the expected size for the type BIP32 keypath");
      }
      // Read in the pubkey from key
      CPubKey pubkey(key.begin() + 1, key.end());
      if (!pubkey.IsFullyValid()) {
         throw std::ios_base::failure("Invalid pubkey");
      }
      if (hd_keypaths.count(pubkey) > 0) {
          throw std::ios_base::failure("Duplicate Key, pubkey derivation path already provided");
      }
  
      // Read in key path
      uint64_t value_len = ReadCompactSize(s);
      if (value_len % 4 || value_len == 0) {
          throw std::ios_base::failure("Invalid length for HD key path");
      }
  
      KeyOriginInfo keypath;
      s >> keypath.fingerprint;
      for (unsigned int i = 4; i < value_len; i += sizeof(uint32_t)) {
          uint32_t index;
          s >> index;
          keypath.path.push_back(index);
      }
  
      // Add to map
      hd_keypaths.emplace(pubkey, std::move(keypath));
  }
  
  // Serialize HD keypaths to a stream from a map
  template<typename Stream>
  void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, KeyOriginInfo>& hd_keypaths, uint8_t type)
  {
      for (auto keypath_pair : hd_keypaths) {
          if (!keypath_pair.first.IsValid()) {
              throw std::ios_base::failure("Invalid CPubKey being serialized");
          }
          SerializeToVector(s, type, MakeSpan(keypath_pair.first));
          WriteCompactSize(s, (keypath_pair.second.path.size() + 1) * sizeof(uint32_t));
          s << keypath_pair.second.fingerprint;
          for (const auto& path : keypath_pair.second.path) {
              s << path;
          }
      }
  }
  
  /** Produce a script signature using a generic signature creator. */
  bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata);
  
  /** Produce a script signature for a transaction. */
  bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType);
  bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
  
  /** Extract signature data from a transaction input, and insert it. */
  SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout);
  void UpdateInput(CTxIn& input, const SignatureData& data);
  
  /* Check whether we know how to sign for an output like this, assuming we
   * have all private keys. While this function does not need private keys, the passed
   * provider is used to look up public keys and redeemscripts by hash.
   * Solvability is unrelated to whether we consider this output to be ours. */
  bool IsSolvable(const SigningProvider& provider, const CScript& script);
  
  /** Check whether a scriptPubKey is known to be segwit. */
  bool IsSegWitOutput(const SigningProvider& provider, const CScript& script);
  
  /** Sign the CMutableTransaction */
  bool SignTransaction(CMutableTransaction& mtx, const SigningProvider* provider, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors);
  
  #endif // BITCOIN_SCRIPT_SIGN_H
  