aboutsummaryrefslogtreecommitdiff
path: root/src/common/signmessage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/signmessage.cpp')
-rw-r--r--src/common/signmessage.cpp93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/common/signmessage.cpp b/src/common/signmessage.cpp
new file mode 100644
index 0000000000..1612751e44
--- /dev/null
+++ b/src/common/signmessage.cpp
@@ -0,0 +1,93 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <common/signmessage.h>
+#include <hash.h>
+#include <key.h>
+#include <key_io.h>
+#include <pubkey.h>
+#include <uint256.h>
+#include <util/strencodings.h>
+
+#include <cassert>
+#include <optional>
+#include <string>
+#include <variant>
+#include <vector>
+
+/**
+ * Text used to signify that a signed message follows and to prevent
+ * inadvertently signing a transaction.
+ */
+const std::string MESSAGE_MAGIC = "Bitcoin Signed Message:\n";
+
+MessageVerificationResult MessageVerify(
+ const std::string& address,
+ const std::string& signature,
+ const std::string& message)
+{
+ CTxDestination destination = DecodeDestination(address);
+ if (!IsValidDestination(destination)) {
+ return MessageVerificationResult::ERR_INVALID_ADDRESS;
+ }
+
+ if (std::get_if<PKHash>(&destination) == nullptr) {
+ return MessageVerificationResult::ERR_ADDRESS_NO_KEY;
+ }
+
+ auto signature_bytes = DecodeBase64(signature);
+ if (!signature_bytes) {
+ return MessageVerificationResult::ERR_MALFORMED_SIGNATURE;
+ }
+
+ CPubKey pubkey;
+ if (!pubkey.RecoverCompact(MessageHash(message), *signature_bytes)) {
+ return MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED;
+ }
+
+ if (!(PKHash(pubkey) == *std::get_if<PKHash>(&destination))) {
+ return MessageVerificationResult::ERR_NOT_SIGNED;
+ }
+
+ return MessageVerificationResult::OK;
+}
+
+bool MessageSign(
+ const CKey& privkey,
+ const std::string& message,
+ std::string& signature)
+{
+ std::vector<unsigned char> signature_bytes;
+
+ if (!privkey.SignCompact(MessageHash(message), signature_bytes)) {
+ return false;
+ }
+
+ signature = EncodeBase64(signature_bytes);
+
+ return true;
+}
+
+uint256 MessageHash(const std::string& message)
+{
+ HashWriter hasher{};
+ hasher << MESSAGE_MAGIC << message;
+
+ return hasher.GetHash();
+}
+
+std::string SigningResultString(const SigningResult res)
+{
+ switch (res) {
+ case SigningResult::OK:
+ return "No error";
+ case SigningResult::PRIVATE_KEY_NOT_AVAILABLE:
+ return "Private key not available";
+ case SigningResult::SIGNING_FAILED:
+ return "Sign failed";
+ // no default case, so the compiler can warn about missing cases
+ }
+ assert(false);
+}