signmessage.cpp raw

   1  // Copyright (c) 2009-2010 Satoshi Nakamoto
   2  // Copyright (c) 2009-present The Bitcoin Core developers
   3  // Distributed under the MIT software license, see the accompanying
   4  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   5  
   6  #include <common/signmessage.h>
   7  #include <hash.h>
   8  #include <key.h>
   9  #include <key_io.h>
  10  #include <pubkey.h>
  11  #include <uint256.h>
  12  #include <util/strencodings.h>
  13  
  14  #include <cassert>
  15  #include <optional>
  16  #include <string>
  17  #include <variant>
  18  #include <vector>
  19  
  20  /**
  21   * Text used to signify that a signed message follows and to prevent
  22   * inadvertently signing a transaction.
  23   */
  24  const std::string MESSAGE_MAGIC = "Bitcoin Signed Message:\n";
  25  
  26  MessageVerificationResult MessageVerify(
  27      const std::string& address,
  28      const std::string& signature,
  29      const std::string& message)
  30  {
  31      CTxDestination destination = DecodeDestination(address);
  32      if (!IsValidDestination(destination)) {
  33          return MessageVerificationResult::ERR_INVALID_ADDRESS;
  34      }
  35  
  36      if (std::get_if<PKHash>(&destination) == nullptr) {
  37          return MessageVerificationResult::ERR_ADDRESS_NO_KEY;
  38      }
  39  
  40      auto signature_bytes = DecodeBase64(signature);
  41      if (!signature_bytes) {
  42          return MessageVerificationResult::ERR_MALFORMED_SIGNATURE;
  43      }
  44  
  45      CPubKey pubkey;
  46      if (!pubkey.RecoverCompact(MessageHash(message), *signature_bytes)) {
  47          return MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED;
  48      }
  49  
  50      if (!(PKHash(pubkey) == *std::get_if<PKHash>(&destination))) {
  51          return MessageVerificationResult::ERR_NOT_SIGNED;
  52      }
  53  
  54      return MessageVerificationResult::OK;
  55  }
  56  
  57  bool MessageSign(
  58      const CKey& privkey,
  59      const std::string& message,
  60      std::string& signature)
  61  {
  62      std::vector<unsigned char> signature_bytes;
  63  
  64      if (!privkey.SignCompact(MessageHash(message), signature_bytes)) {
  65          return false;
  66      }
  67  
  68      signature = EncodeBase64(signature_bytes);
  69  
  70      return true;
  71  }
  72  
  73  uint256 MessageHash(const std::string& message)
  74  {
  75      HashWriter hasher{};
  76      hasher << MESSAGE_MAGIC << message;
  77  
  78      return hasher.GetHash();
  79  }
  80  
  81  std::string SigningResultString(const SigningResult res)
  82  {
  83      switch (res) {
  84          case SigningResult::OK:
  85              return "No error";
  86          case SigningResult::PRIVATE_KEY_NOT_AVAILABLE:
  87              return "Private key not available";
  88          case SigningResult::SIGNING_FAILED:
  89              return "Sign failed";
  90      } // no default case, so the compiler can warn about missing cases
  91      assert(false);
  92  }
  93