Bitcoin Core 32.99.0
P2P Digital Currency
bip352_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2026-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <common/bip352.h>
6#include <chainparams.h>
7#include <coins.h>
8#include <span.h>
9#include <addresstype.h>
10#include <script/solver.h>
11#include <test/data/bip352_send_and_receive_vectors.json.h>
12
14
15#include <boost/test/unit_test.hpp>
16#include <test/util/json.h>
17#include <vector>
18#include <util/chaintype.h>
19#include <util/strencodings.h>
20#include <streams.h>
21
22namespace bip352 {
24
25CKey ParseHexToCKey(std::string_view hex) {
26 CKey output;
27 std::vector<unsigned char> hex_data = ParseHex(hex);
28 output.Set(hex_data.begin(), hex_data.end(), true);
29 return output;
30};
31
32BOOST_AUTO_TEST_CASE(bip352_send_and_receive_test_vectors)
33{
35 BOOST_REQUIRE(tests.read(json_tests::bip352_send_and_receive_vectors));
36
37 for (const auto& vec : tests.getValues()) {
38 // run sending tests
39 BOOST_TEST_MESSAGE(vec["comment"].get_str());
40
41 for (const auto& sender : vec["sending"].getValues()) {
42 const UniValue& given = sender["given"];
43 const UniValue& expected = sender["expected"];
44
45 std::vector<COutPoint> outpoints;
46 std::vector<CKey> keys;
47 std::vector<KeyPair> taproot_keys;
48 for (const auto& input : given["vin"].getValues()) {
49 COutPoint outpoint{Txid::FromHex(input["txid"].get_str()).value(), input["vout"].getInt<uint32_t>()};
50 outpoints.push_back(outpoint);
51 const auto& spk_bytes = ParseHex(input["prevout"]["scriptPubKey"]["hex"].get_str());
52 CScript spk = CScript(spk_bytes.begin(), spk_bytes.end());
53 const auto& script_sig_bytes = ParseHex(input["scriptSig"].get_str());
54 CScript script_sig = CScript(script_sig_bytes.begin(), script_sig_bytes.end());
55 CTxIn txin{outpoint, script_sig};
56 // read the field txWitness as a stream and write txWitness >> witness.stack;
57 const auto witness_str = ParseHex(input["txinwitness"].get_str());
58 if (!witness_str.empty()) {
59 SpanReader(witness_str) >> txin.scriptWitness.stack;
60 }
61
62 // check if this is a silent payments input by trying to extract the public key
63 const auto& pubkey = GetPubKeyFromInput(txin, spk);
64 if (pubkey.has_value()) {
65 std::vector<std::vector<unsigned char>> solutions;
66 TxoutType type = Solver(spk, solutions);
68 taproot_keys.emplace_back(ParseHexToCKey(input["private_key"].get_str()).ComputeKeyPair(nullptr));
69 } else {
70 keys.emplace_back(ParseHexToCKey(input["private_key"].get_str()));
71 }
72 }
73 }
74 if (taproot_keys.empty() && keys.empty()) {
75 BOOST_CHECK(expected["outputs"].getValues()[0].empty());
76 continue;
77 }
78 // silent payments logic
79 auto smallest_outpoint = std::min_element(outpoints.begin(), outpoints.end(), BIP352Comparator());
80 std::map<size_t, SilentPaymentsDestination> sp_dests;
81 const std::vector<UniValue>& silent_payments_addresses = given["recipients"].getValues();
82 size_t sp_index = 0;
83 for (size_t i = 0; i < silent_payments_addresses.size(); ++i) {
84 auto sp = DecodeSilentPaymentsAddress(silent_payments_addresses[i]["address"].get_str(), Params());
85 BOOST_REQUIRE(sp.has_value());
86 if (!silent_payments_addresses[i]["scan_pub_key"].isNull()) {
87 BOOST_CHECK_EQUAL(HexStr(sp->GetScanPubKey()), silent_payments_addresses[i]["scan_pub_key"].get_str());
88 BOOST_CHECK_EQUAL(HexStr(sp->GetSpendPubKey()), silent_payments_addresses[i]["spend_pub_key"].get_str());
89 }
90 size_t count = silent_payments_addresses[i]["count"].isNull() ? 1 : (size_t)silent_payments_addresses[i]["count"].getInt<int>();
91 for (size_t j = 0; j < count; ++j) {
92 sp_dests.emplace(sp_index++, *sp);
93 }
94 }
95 auto sp_tr_dests = GenerateSilentPaymentsTaprootDestinations(sp_dests, keys, taproot_keys, *smallest_outpoint);
96 // This means the inputs summed to zero, which realistically would only happen maliciously. In this case, just move on
97 if (!sp_tr_dests.has_value()) {
98 // Check that we actually expect zero outputs to be generated for this test
99 BOOST_CHECK(expected["outputs"].getValues()[0].empty());
100 continue;
101 }
102 bool match = false;
103 for (const auto& candidate_set : expected["outputs"].getValues()) {
104 BOOST_CHECK(sp_tr_dests->size() == candidate_set.size());
105 std::vector<WitnessV1Taproot> expected_spks;
106 for (const auto& output : candidate_set.getValues()) {
107 const WitnessV1Taproot tap{XOnlyPubKey(ParseHex(output.get_str()))};
108 expected_spks.push_back(tap);
109 }
110 match = std::all_of(sp_tr_dests->begin(), sp_tr_dests->end(), [&](const auto& entry) {
111 return std::find(expected_spks.begin(), expected_spks.end(), entry.second) != expected_spks.end();
112 });
113 if (match) break;
114 }
115 BOOST_CHECK(match);
116 }
117
118 // Test receiving
119 for (const auto& recipient : vec["receiving"].getValues()) {
120
121 const UniValue& given = recipient["given"];
122 const UniValue& expected = recipient["expected"];
123
124 std::vector<CTxIn> vin;
125 std::map<COutPoint, Coin> coins;
126 for (const auto& input : given["vin"].getValues()) {
127 COutPoint outpoint{Txid::FromHex(input["txid"].get_str()).value(), input["vout"].getInt<uint32_t>()};
128 const auto& spk_bytes = ParseHex(input["prevout"]["scriptPubKey"]["hex"].get_str());
129 CScript spk = CScript(spk_bytes.begin(), spk_bytes.end());
130 const auto& script_sig_bytes = ParseHex(input["scriptSig"].get_str());
131 CScript script_sig = CScript(script_sig_bytes.begin(), script_sig_bytes.end());
132 CTxIn txin{outpoint, script_sig};
133 // read the field txWitness as a stream and write txWitness >> witness.stack;
134 const auto witness_str = ParseHex(input["txinwitness"].get_str());
135 if (!witness_str.empty()) {
136 SpanReader(witness_str) >> txin.scriptWitness.stack;
137 }
138 vin.push_back(txin);
139 coins[outpoint] = Coin{CTxOut{{}, spk}, 0, false};
140 }
141 auto pub_tweak_data = GetSilentPaymentsPrevoutsSummary(vin, coins);
142 // If we don't get any tweak data from the transaction inputs, it is not a silent payment
143 // transaction, so we skip it.
144 if (!pub_tweak_data.has_value()) {
145 // Make sure this is expected and not just a failure of the GetSilentPaymentsPrevoutsSummary func
146 BOOST_CHECK(expected["outputs"].empty());
147 continue;
148 }
149 std::vector<XOnlyPubKey> output_pub_keys;
150 for (const auto& pubkey : given["outputs"].getValues()) {
151 output_pub_keys.emplace_back(ParseHex(pubkey.get_str()));
152 }
153
154 CKey scan_priv_key = ParseHexToCKey(given["key_material"]["scan_priv_key"].get_str());
155 CKey spend_priv_key = ParseHexToCKey(given["key_material"]["spend_priv_key"].get_str());
156 SilentPaymentsDestination sp_address{SilentPaymentsDestination::From(scan_priv_key.GetPubKey(), spend_priv_key.GetPubKey()).value()};
157 auto expected_address = DecodeSilentPaymentsAddress(expected["addresses"][0].get_str(), Params());
158 BOOST_REQUIRE(expected_address.has_value());
159 BOOST_CHECK(sp_address == *expected_address);
160
161 // The change label is registered automatically; only non-change labels need registering.
162 SilentPaymentsReceiver receiver{scan_priv_key, sp_address.GetSpendPubKey()};
163 auto given_labels{given["labels"].getValues()};
164 for (size_t i = 0; i < given_labels.size(); i++) {
165 const uint32_t m = given_labels[i].getInt<uint32_t>();
166 const SilentPaymentsDestination labeled_addr = (m == 0) ? receiver.GetChangeDestination() : receiver.GenerateLabeledAddress(m);
167 // expected["addresses"] contains the base silent payments address (at index 0)
168 // followed by the labeled addresses
169 auto sp = DecodeSilentPaymentsAddress(expected["addresses"][i+1].get_str(), Params());
170 BOOST_REQUIRE(sp.has_value());
171 BOOST_CHECK(labeled_addr == *sp);
172 }
173
174 // Scanning
175 const auto& found_outputs = receiver.Scan(*pub_tweak_data, output_pub_keys);
176 BOOST_REQUIRE(found_outputs.has_value());
177 // The transaction may be a silent payments transaction, but it does not contain any outputs for us,
178 // so we continue to the next transaction.
179 if (found_outputs->empty()) {
180 BOOST_CHECK(expected["outputs"].empty());
181 continue;
182 }
183 if (!expected["n_outputs"].isNull()) {
184 BOOST_CHECK_EQUAL(found_outputs->size(), (size_t)expected["n_outputs"].getInt<int>());
185 } else {
186 std::map<XOnlyPubKey, uint256> expected_outputs;
187 for (const auto& output : expected["outputs"].getValues()) {
188 expected_outputs.emplace(
189 XOnlyPubKey{ParseHex(output["pub_key"].get_str())},
190 uint256{ParseHex(output["priv_key_tweak"].get_str())});
191 }
192 BOOST_TEST_MESSAGE(found_outputs->size());
193 BOOST_REQUIRE_EQUAL(found_outputs->size(), expected_outputs.size());
194 for (const auto& output : *found_outputs) {
195 const auto expected_output = expected_outputs.find(output.output);
196 BOOST_REQUIRE(expected_output != expected_outputs.end());
197 BOOST_CHECK(output.tweak == expected_output->second);
198 }
199 }
200 }
201 }
202}
203
204BOOST_AUTO_TEST_CASE(bip352_preserves_requested_output_indexes)
205{
206 CKey sender_key = ParseHexToCKey("0000000000000000000000000000000000000000000000000000000000000001");
207 CKey scan_key = ParseHexToCKey("0000000000000000000000000000000000000000000000000000000000000002");
208 CKey spend_key = ParseHexToCKey("0000000000000000000000000000000000000000000000000000000000000003");
209 SilentPaymentsDestination sp_dest{SilentPaymentsDestination::From(scan_key.GetPubKey(), spend_key.GetPubKey()).value()};
210 std::map<size_t, SilentPaymentsDestination> sp_dests{{2, sp_dest}, {5, sp_dest}};
211 COutPoint smallest_outpoint{Txid::FromHex("0000000000000000000000000000000000000000000000000000000000000001").value(), 0};
212
213 auto generated = GenerateSilentPaymentsTaprootDestinations(sp_dests, {sender_key}, {}, smallest_outpoint);
214
215 BOOST_REQUIRE(generated.has_value());
216 BOOST_CHECK_EQUAL(generated->size(), sp_dests.size());
217 BOOST_CHECK_EQUAL(generated->count(0), 0);
218 BOOST_CHECK_EQUAL(generated->count(1), 0);
219 BOOST_CHECK_EQUAL(generated->count(2), 1);
220 BOOST_CHECK_EQUAL(generated->count(5), 1);
221}
222
223BOOST_AUTO_TEST_CASE(bip352_skips_transactions_spending_unknown_segwit_versions)
224{
225 CKey key = ParseHexToCKey("0000000000000000000000000000000000000000000000000000000000000001");
226 CPubKey pubkey = key.GetPubKey();
227 COutPoint eligible_outpoint{Txid::FromHex("0000000000000000000000000000000000000000000000000000000000000001").value(), 0};
228 COutPoint unknown_segwit_outpoint{Txid::FromHex("0000000000000000000000000000000000000000000000000000000000000002").value(), 0};
229
230 CTxIn eligible_input{eligible_outpoint};
231 eligible_input.scriptWitness.stack.emplace_back(64, 0);
232 eligible_input.scriptWitness.stack.emplace_back(pubkey.begin(), pubkey.end());
233
234 std::map<COutPoint, Coin> coins;
235 coins[eligible_outpoint] = Coin{CTxOut{{}, GetScriptForDestination(WitnessV0KeyHash{pubkey})}, 0, false};
236 coins[unknown_segwit_outpoint] = Coin{CTxOut{{}, GetScriptForDestination(WitnessUnknown{2, std::vector<unsigned char>(32, 1)})}, 0, false};
237
238 BOOST_REQUIRE(GetSilentPaymentsPrevoutsSummary({eligible_input}, coins).has_value());
239 BOOST_CHECK(!GetSilentPaymentsPrevoutsSummary({eligible_input, CTxIn{unknown_segwit_outpoint}}, coins).has_value());
240}
241
242BOOST_AUTO_TEST_CASE(bip352_scan_skips_invalid_taproot_outputs)
243{
244 CKey sender_key = ParseHexToCKey("0000000000000000000000000000000000000000000000000000000000000001");
245 CKey scan_key = ParseHexToCKey("0000000000000000000000000000000000000000000000000000000000000002");
246 CKey spend_key = ParseHexToCKey("0000000000000000000000000000000000000000000000000000000000000003");
247 const COutPoint outpoint{Txid::FromHex("0000000000000000000000000000000000000000000000000000000000000001").value(), 0};
248
249 std::map<size_t, SilentPaymentsDestination> sp_dests;
250 sp_dests.emplace(0, SilentPaymentsDestination::From(scan_key.GetPubKey(), spend_key.GetPubKey()).value());
251 const auto sp_tr_dests = GenerateSilentPaymentsTaprootDestinations(sp_dests, {sender_key}, {}, outpoint);
252 BOOST_REQUIRE(sp_tr_dests.has_value());
253 const XOnlyPubKey expected_output{sp_tr_dests->begin()->second};
254
255 CTxIn txin{outpoint};
256 const CPubKey sender_pubkey{sender_key.GetPubKey()};
257 txin.scriptWitness.stack.emplace_back();
258 txin.scriptWitness.stack.emplace_back(sender_pubkey.begin(), sender_pubkey.end());
259
260 std::map<COutPoint, Coin> coins;
261 coins[outpoint] = Coin{CTxOut{{}, GetScriptForDestination(WitnessV0KeyHash{sender_pubkey})}, 0, false};
262 const auto prevouts_summary = GetSilentPaymentsPrevoutsSummary({txin}, coins);
263 BOOST_REQUIRE(prevouts_summary.has_value());
264
265 std::vector<XOnlyPubKey> output_pub_keys;
266 output_pub_keys.emplace_back(ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
267 output_pub_keys.push_back(expected_output);
268
269 SilentPaymentsReceiver receiver{scan_key, spend_key.GetPubKey()};
270 const auto found_outputs = receiver.Scan(*prevouts_summary, output_pub_keys);
271 BOOST_REQUIRE(found_outputs.has_value());
272 BOOST_REQUIRE_EQUAL(found_outputs->size(), 1);
273 BOOST_CHECK(found_outputs->front().output == expected_output);
274}
275
276BOOST_AUTO_TEST_CASE(bip352_label_serialize_roundtrip)
277{
278 CKey scan_key = ParseHexToCKey("0000000000000000000000000000000000000000000000000000000000000002");
279 CPubKey spend_pubkey = ParseHexToCKey("0000000000000000000000000000000000000000000000000000000000000003").GetPubKey();
280 SilentPaymentsReceiver receiver{scan_key, spend_pubkey};
281
282 BOOST_REQUIRE_EQUAL(receiver.GetLabels().size(), 1);
283 const SilentPaymentsLabel& label = receiver.GetLabels().begin()->first;
284
285 DataStream stream;
286 label.Serialize(stream);
287 auto roundtripped = SilentPaymentsLabel::Unserialize(stream);
288 BOOST_REQUIRE(roundtripped.has_value());
289 BOOST_CHECK(*roundtripped == label);
290 BOOST_CHECK(stream.empty());
291}
292
293BOOST_AUTO_TEST_CASE(bip352_decode_address)
294{
295 struct ValidVector {
296 ChainType chain;
297 std::string address;
298 std::string scan_pubkey;
299 std::string spend_pubkey;
300 std::string extension_data;
301 uint8_t version;
302 };
303 const ValidVector valid_vectors[]{
305 "sp1qq22l5s6l9460ww6t4tkzsy2a7zejurcmzz35pt0ffrzk5erlaykdcqugecjjnjqf7ggq39vl6wexjlm00n66z94v675n7wcux6d2krr68gdjvfn2",
306 "0295fa435f2d74f73b4baaec28115df0b32e0f1b10a340ade948c56a647fe92cdc",
307 "0388ce2529c809f21008959fd3b2697f6f7cf5a116acd7a93f3b1c369aab0c7a3a",
308 "", 0},
310 "sp1pq22l5s6l9460ww6t4tkzsy2a7zejurcmzz35pt0ffrzk5erlaykdcqugecjjnjqf7ggq39vl6wexjlm00n66z94v675n7wcux6d2krr68t02m0h0s8cwhy",
311 "0295fa435f2d74f73b4baaec28115df0b32e0f1b10a340ade948c56a647fe92cdc",
312 "0388ce2529c809f21008959fd3b2697f6f7cf5a116acd7a93f3b1c369aab0c7a3a",
313 "deadbeef", 1},
315 "tsp1qqthpye3hdcnydp9temp7yduy6uw5h2nw8u9fz677ccrna280qwj3uq60zeqs3zfpj3age62h4ljq2lyawwdecmk8a545yysk4x3tu3skjqm2thu6",
316 "02ee1266376e264684abcec3e23784d71d4baa6e3f0a916bdec6073ea8ef03a51e",
317 "034f1641088921947a8ce957afe4057c9d739b9c6ec7ed2b421216a9a2be461690",
318 "", 0},
320 "tsp1qqvrl2accqtatgtkllv5fdsfapq6vqnrr0uf2whhmjyas4teg7ljfqqlpec0ze90m97t3stv92p5ekzkcwzmpx0x8p7ljj9xqcjjpvnfurc00tjn9",
321 "0307f5771802fab42edffb2896c13d0834c04c637f12a75efb913b0aaf28f7e490",
322 "03e1ce1e2c95fb2f97182d8550699b0ad870b6133cc70fbf2914c0c4a4164d3c1e",
323 "", 0},
325 "sprt1qq04xgllnqqfdlxjkr355rmsahfn9t8l6sd0k20t4uka4c73nvvpnwqu4kvg0nm62d5jtmqp54lkc7tul0dzt25ejtn4f80505z3u0h5jag59rdg4",
326 "03ea647ff30012df9a561c6941ee1dba66559ffa835f653d75e5bb5c7a33630337",
327 "0395b310f9ef4a6d24bd8034afed8f2f9f7b44b553325cea93be8fa0a3c7de92ea",
328 "", 0},
329 };
330
331 for (const auto& vec : valid_vectors) {
332 SelectParams(vec.chain);
333
334 auto sp = DecodeSilentPaymentsAddress(vec.address, Params());
335 BOOST_REQUIRE_MESSAGE(sp.has_value(), vec.address);
336 BOOST_CHECK_EQUAL(sp->GetVersion(), vec.version);
337 BOOST_CHECK_EQUAL(HexStr(sp->GetScanPubKey()), vec.scan_pubkey);
338 BOOST_CHECK_EQUAL(HexStr(sp->GetSpendPubKey()), vec.spend_pubkey);
339 BOOST_CHECK_EQUAL(HexStr(sp->GetExtensionData()), vec.extension_data);
340
341 // Bech32(m) is case-insensitive as a whole; an all-uppercase address must decode identically.
342 std::string flipped = ToUpper(vec.address);
343 auto sp_flipped = DecodeSilentPaymentsAddress(flipped, Params());
344 BOOST_REQUIRE_MESSAGE(sp_flipped.has_value(), flipped);
345 BOOST_CHECK(*sp_flipped == *sp);
346 }
347
348 // `chain` is the one chain (if any) whose HRP matches the address, where `expected_error`
349 // applies; on every other chain the HRP check itself is expected to fail first.
350 // `chain_independent` addresses fail bech32m checksum verification before the HRP is even
351 // compared, so `expected_error` applies on every chain instead.
352 struct InvalidVector {
353 std::string address;
354 std::string expected_error;
355 std::optional<ChainType> chain = std::nullopt;
356 bool chain_independent = false;
357 };
358 const InvalidVector invalid_vectors[]{
359 {"spx1qq22l5s6l9460ww6t4tkzsy2a7zejurcmzz35pt0ffrzk5erlaykdcqugecjjnjqf7ggq39vl6wexjlm00n66z94v675n7wcux6d2krr68g37pn04",
360 "Invalid or unsupported prefix for Silent Payments address (expected sp, got spx)."}, // wrong HRP; never matches any chain
361 {"sp1qq22l5s6l9460ww6t4tkzsy2a7zejurcmzz35pt0ffrzk5erlaykdcqugecjjnjqf7ggq39vl6wexjlm00n66z94v675n7wcux6d2krr68gcwu9kg",
362 "Silent Payments address must use Bech32m checksum", std::nullopt, /*chain_independent=*/true}, // bad checksum
363 {"sp1qqgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq2qugecjjnjqf7ggq39vl6wexjlm00n66z94v675n7wcux6d2krr68g25havg",
364 "Invalid Silent payments address", ChainType::MAIN}, // invalid scan pubkey
365 {"sp1qq22l5s6l9460ww6t4tkzsy2a7zejurcmzz35pt0ffrzk5erlaykdcqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq57qc9nf",
366 "Invalid Silent payments address", ChainType::MAIN}, // invalid spend pubkey
367 {"sp1lq22l5s6l9460ww6t4tkzsy2a7zejurcmzz35pt0ffrzk5erlaykdcqugecjjnjqf7ggq39vl6wexjlm00n66z94v675n7wcux6d2krr68gaafydt",
368 "This implementation only supports Silent payments addresses v0 through v30 (got 31).", ChainType::MAIN}, // reserved version 31
369 {"sp1qq22l5s6l9460ww6t4tkzsy2a7zejurcmzz35pt0ffrzk5erlaykdcznsxsn",
370 "Silent payments data payload is too small (expected at least 66, got 33).", ChainType::MAIN}, // payload too small
371 {"tsp1qqthpye3hdcnydp9temp7yduy6uw5h2nw8u9fz677ccrna280qwj3uq60zeqs3zfpj3age62h4ljq2lyawwdecmk8a545yysk4x3tu3skjqm2thum",
372 "Silent Payments address must use Bech32m checksum", std::nullopt, /*chain_independent=*/true}, // bad checksum
373 {"sp1qqgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqf26rn7",
374 "Silent Payments address must use Bech32m checksum", std::nullopt, /*chain_independent=*/true}, // bad checksum
375 {"sprt1qqgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq2qu4kvg0nm62d5jtmqp54lkc7tul0dzt25ejtn4f80505z3u0h5jagf9zkp5",
376 "Invalid Silent payments address", ChainType::REGTEST}, // invalid scan pubkey
377 };
378
379 for (const auto& vec : invalid_vectors) {
381 SelectParams(chain);
382 auto sp = DecodeSilentPaymentsAddress(vec.address, Params());
383 BOOST_REQUIRE_MESSAGE(!sp.has_value(), vec.address);
384 if (vec.chain_independent || chain == vec.chain) {
385 BOOST_CHECK_EQUAL(sp.error(), vec.expected_error);
386 } else {
387 BOOST_CHECK_MESSAGE(sp.error().starts_with("Invalid or unsupported prefix for Silent Payments address"), sp.error());
388 }
389 }
390 }
391
393}
394
396} // namespace bip352
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
void SelectParams(const ChainType chain)
Sets the params returned by Params() to those for the given chain type.
const CChainParams & Params()
Return the currently selected parameters.
ChainType
Definition: chaintype.h:12
An encapsulated private key.
Definition: key.h:46
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:184
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:114
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:30
An encapsulated public key.
Definition: pubkey.h:43
const unsigned char * end() const
Definition: pubkey.h:124
const unsigned char * begin() const
Definition: pubkey.h:123
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:406
An input of a transaction.
Definition: transaction.h:63
CScriptWitness scriptWitness
Only serialized through CTransaction.
Definition: transaction.h:68
An output of a transaction.
Definition: transaction.h:141
A UTXO entry.
Definition: coins.h:46
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:165
bool empty() const
Definition: streams.h:199
Minimal stream for reading from an existing byte array by std::span.
Definition: streams.h:83
const std::vector< UniValue > & getValues() const
Int getInt() const
Definition: univalue.h:143
const unsigned char * begin() const
Definition: pubkey.h:304
static std::optional< SilentPaymentsLabel > Unserialize(Stream &s)
Definition: bip352.h:150
void Serialize(Stream &s) const
Definition: bip352.h:144
A silent payments recipient's scanning identity.
Definition: bip352.h:239
static std::optional< transaction_identifier > FromHex(std::string_view hex)
256-bit opaque blob.
Definition: uint256.h:196
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: hex_base.cpp:30
BOOST_CHECK_EQUAL(headers.FindFirst("key"), "value")
util::Expected< PrevoutsSummary, PrevoutsSummaryError > GetSilentPaymentsPrevoutsSummary(const std::vector< CTxIn > &vin, const std::map< COutPoint, Coin > &coins)
Get silent payments public data from transaction inputs.
Definition: bip352.cpp:255
std::optional< PubKey > GetPubKeyFromInput(const CTxIn &txin, const CScript &spk)
Get the public key from an input.
Definition: bip352.cpp:143
std::optional< std::map< size_t, WitnessV1Taproot > > GenerateSilentPaymentsTaprootDestinations(const std::map< size_t, SilentPaymentsDestination > &sp_dests, const std::vector< CKey > &plain_keys, const std::vector< KeyPair > &taproot_keys, const COutPoint &smallest_outpoint)
Generate silent payments taproot destinations.
Definition: bip352.cpp:353
CKey ParseHexToCKey(std::string_view hex)
util::Expected< SilentPaymentsDestination, std::string > DecodeSilentPaymentsAddress(const std::string &str, const CChainParams &params)
Decode a BIP352 "sp1..." address. Returns the destination, or an error message on failure.
Definition: bip352.cpp:67
BOOST_AUTO_TEST_CASE(bip352_send_and_receive_test_vectors)
#define BOOST_CHECK(expr)
Definition: object.cpp:16
static unsigned char smallest_outpoint[36]
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< unsigned char > > &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: solver.cpp:141
TxoutType
Definition: solver.h:22
@ WITNESS_V1_TAPROOT
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
Definition: strencodings.h:69
Basic testing setup.
Definition: setup_common.h:58
std::vector< std::vector< unsigned char > > stack
Definition: script.h:581
CTxDestination subtype to encode any future Witness version.
Definition: addresstype.h:96
static std::optional< SilentPaymentsDestination > From(const CPubKey &scan_pubkey, const CPubKey &spend_pubkey, uint8_t version=0, std::span< const unsigned char > extension_data={})
Definition: bip352.cpp:51
std::vector< uint16_t > keys
Definition: dbwrapper.cpp:376
static int count
constexpr std::array tests
Definition: unitester.cpp:101
std::string ToUpper(std::string_view str)
Returns the uppercase equivalent of the given string.