signmessage.cpp raw

   1  // Copyright (c) 2010 Satoshi Nakamoto
   2  // Copyright (c) 2009-2022 The Limenka 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 RPCHelpMan verifymessage()
  18  {
  19      return RPCHelpMan{"verifymessage",
  20          "Verify a signed message.",
  21          {
  22              {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The limenka 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 = self.Arg<std::string>("address");
  42              std::string strSign = self.Arg<std::string>("signature");
  43              std::string strMessage = self.Arg<std::string>("message");
  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_POF:
  53              case MessageVerificationResult::INCONCLUSIVE:
  54                  throw JSONRPCError(RPC_TYPE_ERROR, "This signature is not yet supported");
  55              case MessageVerificationResult::ERR_INVALID:
  56              case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED:
  57              case MessageVerificationResult::ERR_NOT_SIGNED:
  58                  return false;
  59              case MessageVerificationResult::OK:
  60                  return true;
  61              }
  62  
  63              return false;
  64          },
  65      };
  66  }
  67  
  68  static RPCHelpMan signmessagewithprivkey()
  69  {
  70      return RPCHelpMan{"signmessagewithprivkey",
  71          "\nSign a message with the private key of an address\n",
  72          {
  73              {"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key to sign the message with."},
  74              {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
  75          },
  76          RPCResult{
  77              RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
  78          },
  79          RPCExamples{
  80              "\nCreate the signature\n"
  81              + HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
  82              "\nVerify the signature\n"
  83              + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
  84              "\nAs a JSON-RPC call\n"
  85              + HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
  86          },
  87          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
  88          {
  89              std::string strPrivkey = request.params[0].get_str();
  90              std::string strMessage = request.params[1].get_str();
  91  
  92              CKey key = DecodeSecret(strPrivkey);
  93              if (!key.IsValid()) {
  94                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
  95              }
  96  
  97              std::string signature;
  98  
  99              if (!MessageSign(key, strMessage, signature)) {
 100                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
 101              }
 102  
 103              return signature;
 104          },
 105      };
 106  }
 107  
 108  void RegisterSignMessageRPCCommands(CRPCTable& t)
 109  {
 110      static const CRPCCommand commands[]{
 111          {"util", &verifymessage},
 112          {"util", &signmessagewithprivkey},
 113      };
 114      for (const auto& c : commands) {
 115          t.appendCommand(c.name, &c);
 116      }
 117  }
 118