signmessage.cpp raw

   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  }
 113