Branch data Line data Source code
1 : : // Copyright (c) 2009-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 <common/signmessage.h>
7 : : #include <hash.h>
8 : : #include <key.h>
9 : : #include <key_io.h>
10 : : #include <pubkey.h>
11 : : #include <uint256.h>
12 : : #include <util/strencodings.h>
13 : :
14 : : #include <cassert>
15 : : #include <optional>
16 : : #include <string>
17 : : #include <variant>
18 : : #include <vector>
19 : :
20 : : /**
21 : : * Text used to signify that a signed message follows and to prevent
22 : : * inadvertently signing a transaction.
23 : : */
24 : : const std::string MESSAGE_MAGIC = "Bitcoin Signed Message:\n";
25 : :
26 : 1371 : MessageVerificationResult MessageVerify(
27 : : const std::string& address,
28 : : const std::string& signature,
29 : : const std::string& message)
30 : : {
31 : 1371 : CTxDestination destination = DecodeDestination(address);
32 [ + - + + ]: 1371 : if (!IsValidDestination(destination)) {
33 : : return MessageVerificationResult::ERR_INVALID_ADDRESS;
34 : : }
35 : :
36 [ + + ]: 2040 : if (std::get_if<PKHash>(&destination) == nullptr) {
37 : : return MessageVerificationResult::ERR_ADDRESS_NO_KEY;
38 : : }
39 : :
40 [ + - ]: 669 : auto signature_bytes = DecodeBase64(signature);
41 [ + + ]: 669 : if (!signature_bytes) {
42 : : return MessageVerificationResult::ERR_MALFORMED_SIGNATURE;
43 : : }
44 : :
45 [ + - ]: 668 : CPubKey pubkey;
46 [ + - + - : 668 : if (!pubkey.RecoverCompact(MessageHash(message), *signature_bytes)) {
+ + ]
47 : : return MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED;
48 : : }
49 : :
50 [ + - + - : 1304 : if (!(PKHash(pubkey) == *std::get_if<PKHash>(&destination))) {
+ + ]
51 : 28 : return MessageVerificationResult::ERR_NOT_SIGNED;
52 : : }
53 : :
54 : : return MessageVerificationResult::OK;
55 : 2040 : }
56 : :
57 : 4734 : bool MessageSign(
58 : : const CKey& privkey,
59 : : const std::string& message,
60 : : std::string& signature)
61 : : {
62 : 4734 : std::vector<unsigned char> signature_bytes;
63 : :
64 [ + - + - : 4734 : if (!privkey.SignCompact(MessageHash(message), signature_bytes)) {
+ + ]
65 : : return false;
66 : : }
67 : :
68 [ + - ]: 4672 : signature = EncodeBase64(signature_bytes);
69 : :
70 : 4672 : return true;
71 : 4734 : }
72 : :
73 : 6087 : uint256 MessageHash(const std::string& message)
74 : : {
75 : 6087 : HashWriter hasher{};
76 : 6087 : hasher << MESSAGE_MAGIC << message;
77 : :
78 : 6087 : return hasher.GetHash();
79 : : }
80 : :
81 : 685 : std::string SigningResultString(const SigningResult res)
82 : : {
83 [ + + + - ]: 685 : switch (res) {
84 : 639 : case SigningResult::OK:
85 : 639 : return "No error";
86 : 22 : case SigningResult::PRIVATE_KEY_NOT_AVAILABLE:
87 : 22 : return "Private key not available";
88 : 24 : case SigningResult::SIGNING_FAILED:
89 : 24 : return "Sign failed";
90 : : // no default case, so the compiler can warn about missing cases
91 : : }
92 : 0 : assert(false);
93 : : }
|