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