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