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