/ src / rpc / signmessage.cpp
signmessage.cpp
  1  // Copyright (c) 2010 Satoshi Nakamoto
  2  // Copyright (c) 2009-2022 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 <key.h>
  7  #include <key_io.h>
  8  #include <rpc/protocol.h>
  9  #include <rpc/request.h>
 10  #include <rpc/server.h>
 11  #include <rpc/util.h>
 12  #include <univalue.h>
 13  #include <util/message.h>
 14  
 15  #include <string>
 16  
 17  static RPCHelpMan verifymessage()
 18  {
 19      return RPCHelpMan{"verifymessage",
 20          "Verify a signed message.",
 21          {
 22              {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the signature."},
 23              {"signature", RPCArg::Type::STR, RPCArg::Optional::NO, "The signature provided by the signer in base 64 encoding (see signmessage)."},
 24              {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message that was signed."},
 25          },
 26          RPCResult{
 27              RPCResult::Type::BOOL, "", "If the signature is verified or not."
 28          },
 29          RPCExamples{
 30              "\nUnlock the wallet for 30 seconds\n"
 31              + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
 32              "\nCreate the signature\n"
 33              + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
 34              "\nVerify the signature\n"
 35              + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
 36              "\nAs a JSON-RPC call\n"
 37              + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"")
 38          },
 39          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 40          {
 41              std::string strAddress = request.params[0].get_str();
 42              std::string strSign = request.params[1].get_str();
 43              std::string strMessage = request.params[2].get_str();
 44  
 45              switch (MessageVerify(strAddress, strSign, strMessage)) {
 46              case MessageVerificationResult::ERR_INVALID_ADDRESS:
 47                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
 48              case MessageVerificationResult::ERR_ADDRESS_NO_KEY:
 49                  throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
 50              case MessageVerificationResult::ERR_MALFORMED_SIGNATURE:
 51                  throw JSONRPCError(RPC_TYPE_ERROR, "Malformed base64 encoding");
 52              case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED:
 53              case MessageVerificationResult::ERR_NOT_SIGNED:
 54                  return false;
 55              case MessageVerificationResult::OK:
 56                  return true;
 57              }
 58  
 59              return false;
 60          },
 61      };
 62  }
 63  
 64  static RPCHelpMan signmessagewithprivkey()
 65  {
 66      return RPCHelpMan{"signmessagewithprivkey",
 67          "\nSign a message with the private key of an address\n",
 68          {
 69              {"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key to sign the message with."},
 70              {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
 71          },
 72          RPCResult{
 73              RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
 74          },
 75          RPCExamples{
 76              "\nCreate the signature\n"
 77              + HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
 78              "\nVerify the signature\n"
 79              + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
 80              "\nAs a JSON-RPC call\n"
 81              + HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
 82          },
 83          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 84          {
 85              std::string strPrivkey = request.params[0].get_str();
 86              std::string strMessage = request.params[1].get_str();
 87  
 88              CKey key = DecodeSecret(strPrivkey);
 89              if (!key.IsValid()) {
 90                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
 91              }
 92  
 93              std::string signature;
 94  
 95              if (!MessageSign(key, strMessage, signature)) {
 96                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
 97              }
 98  
 99              return signature;
100          },
101      };
102  }
103  
104  void RegisterSignMessageRPCCommands(CRPCTable& t)
105  {
106      static const CRPCCommand commands[]{
107          {"util", &verifymessage},
108          {"util", &signmessagewithprivkey},
109      };
110      for (const auto& c : commands) {
111          t.appendCommand(c.name, &c);
112      }
113  }