signmessage.cpp raw
1 // Copyright (c) 2009-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 <core_io.h>
8 #include <hash.h>
9 #include <key.h>
10 #include <key_io.h>
11 #include <outputtype.h>
12 #include <pubkey.h>
13 #include <script/interpreter.h>
14 #include <streams.h>
15 #include <uint256.h>
16 #include <util/strencodings.h>
17
18 #include <cassert>
19 #include <optional>
20 #include <string>
21 #include <variant>
22 #include <vector>
23
24 /**
25 * Text used to signify that a signed message follows and to prevent
26 * inadvertently signing a transaction.
27 */
28 const std::string MESSAGE_MAGIC = "Bitcoin Signed Message:\n";
29
30 /**
31 * BIP-322 tagged hash
32 */
33 static const HashWriter HASHER_BIP322{TaggedHash("BIP0322-signed-message")};
34
35 static constexpr unsigned int BIP322_REQUIRED_FLAGS =
36 SCRIPT_VERIFY_CONST_SCRIPTCODE // disallows OP_CODESEPARATOR and FindAndDelete
37 | SCRIPT_VERIFY_LOW_S
38 | SCRIPT_VERIFY_STRICTENC
39 | SCRIPT_VERIFY_NULLFAIL
40 | SCRIPT_VERIFY_MINIMALDATA
41 | SCRIPT_VERIFY_CLEANSTACK
42 | SCRIPT_VERIFY_P2SH
43 | SCRIPT_VERIFY_WITNESS
44 | SCRIPT_VERIFY_TAPROOT
45 | SCRIPT_VERIFY_MINIMALIF;
46
47 static constexpr unsigned int BIP322_INCONCLUSIVE_FLAGS =
48 SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS
49 | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS
50 | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE
51 | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION
52 | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM;
53
54 MessageVerificationResult MessageVerifyBIP322(
55 CTxDestination& destination,
56 std::vector<unsigned char>& signature,
57 const std::string& message,
58 MessageVerificationResult legacyError)
59 {
60 auto txs = BIP322Txs::Create(destination, message, legacyError, signature);
61 if (!txs) return legacyError;
62
63 const CTransaction& to_sign = txs->m_to_sign;
64 const CTransaction& to_spend = txs->m_to_spend;
65
66 const CScript scriptSig = to_sign.vin[0].scriptSig;
67 const CScriptWitness& witness = to_sign.vin[0].scriptWitness;
68
69 PrecomputedTransactionData txdata;
70 txdata.Init(to_sign, {to_spend.vout[0]});
71 TransactionSignatureChecker sigcheck(&to_sign, /* nInIn= */ 0, /* amountIn= */ to_spend.vout[0].nValue, txdata, MissingDataBehavior::ASSERT_FAIL);
72 sigcheck.m_require_sighash_all = true;
73
74 if (!VerifyScript(scriptSig, to_spend.vout[0].scriptPubKey, &witness, BIP322_REQUIRED_FLAGS, sigcheck)) {
75 return MessageVerificationResult::ERR_INVALID;
76 }
77
78 // inconclusive checks
79
80 if (to_sign.version != 0 && to_sign.version != 2) {
81 return MessageVerificationResult::INCONCLUSIVE;
82 }
83
84 if (!VerifyScript(scriptSig, to_spend.vout[0].scriptPubKey, &witness, BIP322_INCONCLUSIVE_FLAGS, sigcheck)) {
85 return MessageVerificationResult::INCONCLUSIVE;
86 }
87
88 return MessageVerificationResult::OK;
89 }
90
91 MessageVerificationResult MessageVerify(
92 const std::string& address,
93 const std::string& signature,
94 const std::string& message)
95 {
96 auto signature_bytes = DecodeBase64(signature);
97 if ((!signature_bytes) || signature_bytes->empty()) {
98 return MessageVerificationResult::ERR_MALFORMED_SIGNATURE;
99 }
100
101 CTxDestination destination = DecodeDestination(address);
102 if (!IsValidDestination(destination)) {
103 return MessageVerificationResult::ERR_INVALID_ADDRESS;
104 }
105
106 OutputType signed_for_outputtype;
107 if (std::holds_alternative<PKHash>(destination)) {
108 signed_for_outputtype = OutputType::LEGACY;
109 } else if (std::holds_alternative<ScriptHash>(destination)) {
110 signed_for_outputtype = OutputType::P2SH_SEGWIT;
111 } else if (std::holds_alternative<WitnessV0KeyHash>(destination)) {
112 signed_for_outputtype = OutputType::BECH32;
113 } else {
114 return MessageVerifyBIP322(destination, *signature_bytes, message, MessageVerificationResult::ERR_ADDRESS_NO_KEY);
115 }
116
117 uint8_t sigtype{(*signature_bytes)[0]};
118 if (sigtype < 27 || sigtype > 42) {
119 return MessageVerifyBIP322(destination, *signature_bytes, message, MessageVerificationResult::ERR_MALFORMED_SIGNATURE);
120 }
121 sigtype = (sigtype - 27) >> 2;
122 if (sigtype == 3) {
123 (*signature_bytes)[0] -= 8;
124 signed_for_outputtype = OutputType::BECH32;
125 } else if (sigtype == 2) {
126 (*signature_bytes)[0] -= 4;
127 signed_for_outputtype = OutputType::P2SH_SEGWIT;
128 }
129
130 CPubKey pubkey;
131 if (!pubkey.RecoverCompact(MessageHash(message, MessageSignatureFormat::LEGACY), *signature_bytes)) {
132 return MessageVerifyBIP322(destination, *signature_bytes, message, MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED);
133 }
134
135 CTxDestination recovered_dest = GetDestinationForKey(pubkey, signed_for_outputtype);
136
137 if (!(recovered_dest == destination)) {
138 return MessageVerifyBIP322(destination, *signature_bytes, message, MessageVerificationResult::ERR_NOT_SIGNED);
139 }
140
141 return MessageVerificationResult::OK;
142 }
143
144 bool MessageSign(
145 const CKey& privkey,
146 const std::string& message,
147 std::string& signature)
148 {
149 std::vector<unsigned char> signature_bytes;
150
151 if (!privkey.SignCompact(MessageHash(message, MessageSignatureFormat::LEGACY), signature_bytes)) {
152 return false;
153 }
154
155 signature = EncodeBase64(signature_bytes);
156
157 return true;
158 }
159
160 uint256 MessageHash(const std::string& message, MessageSignatureFormat format)
161 {
162 switch (format) {
163 case MessageSignatureFormat::LEGACY:
164 {
165 HashWriter hasher{};
166 hasher << MESSAGE_MAGIC << message;
167
168 return hasher.GetHash();
169 }
170
171 case MessageSignatureFormat::SIMPLE:
172 case MessageSignatureFormat::FULL:
173 {
174 HashWriter hasher{HASHER_BIP322};
175 if (!message.empty()) {
176 hasher.write(AsBytes(Span{message.data(), message.size() * sizeof(char)}));
177 }
178 return hasher.GetSHA256();
179 }
180 }
181 assert(false);
182 }
183
184 std::string SigningResultString(const SigningResult res)
185 {
186 switch (res) {
187 case SigningResult::OK:
188 return "No error";
189 case SigningResult::PRIVATE_KEY_NOT_AVAILABLE:
190 return "Private key not available";
191 case SigningResult::SIGNING_FAILED:
192 return "Sign failed";
193 // no default case, so the compiler can warn about missing cases
194 }
195 assert(false);
196 }
197
198 std::optional<BIP322Txs> BIP322Txs::Create(const CTxDestination& destination, const std::string& message, MessageVerificationResult& result, std::optional<const std::vector<unsigned char>> signature)
199 {
200 // attempt to get script pub key for destination
201 CScript message_challenge = GetScriptForDestination(destination);
202 if (message_challenge.size() == 0) {
203 // NoDestination; failure
204 // (use legacy result)
205 return std::nullopt;
206 }
207
208 // prepare message hash
209 uint256 message_hash = MessageHash(message, MessageSignatureFormat::SIMPLE);
210 std::vector<unsigned char> message_hash_vec(message_hash.begin(), message_hash.end());
211
212 // generate to_spend transaction
213 CMutableTransaction to_spend;
214 to_spend.version = 0;
215 to_spend.nLockTime = 0;
216 to_spend.vin.emplace_back(COutPoint(Txid::FromUint256(uint256::ZERO), 0xFFFFFFFF), (CScript() << OP_0 << message_hash_vec), 0);
217 to_spend.vout.emplace_back(0, message_challenge);
218
219 CMutableTransaction to_sign;
220 if (signature.has_value() && DecodeTx(to_sign, signature.value(), /* try_no_witness= */ true, /* try_witness= */ true)) {
221 // validate decoded transaction
222 // multiple inputs (proof of funds) are not supported as we do not have UTXO set access
223 if (to_sign.vin.size() > 1) {
224 result = MessageVerificationResult::ERR_POF;
225 return std::nullopt;
226 }
227 if ((to_sign.vin.size() == 0 || to_sign.vin[0].prevout.hash != to_spend.GetHash()) ||
228 (to_sign.vin[0].prevout.n != 0) ||
229 (to_sign.vout.size() != 1) ||
230 (to_sign.vout[0].nValue != 0) ||
231 (to_sign.vout[0].scriptPubKey != (CScript() << OP_RETURN))) {
232 result = MessageVerificationResult::ERR_INVALID;
233 return std::nullopt;
234 }
235 } else {
236 // signature is missing, or a witness stack only
237 to_sign.version = 0;
238 to_sign.nLockTime = 0;
239 to_sign.vin.emplace_back(COutPoint(to_spend.GetHash(), 0), CScript(), 0);
240 if (signature.has_value()) {
241 try {
242 DataStream ds(signature.value());
243 ds >> to_sign.vin[0].scriptWitness.stack;
244 if (!ds.empty()) {
245 result = MessageVerificationResult::ERR_INVALID;
246 return std::nullopt;
247 }
248 } catch (...) {
249 // not a script witness either; fall back to legacy error
250 // (use legacy result)
251 return std::nullopt;
252 }
253 }
254 to_sign.vout.emplace_back(0, CScript() << OP_RETURN);
255 }
256
257 return BIP322Txs{to_spend, to_sign};
258 }
259