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