Bitcoin Core 32.99.0
P2P Digital Currency
bip352.cpp
Go to the documentation of this file.
1// Copyright (c) 2023 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
7#include <addresstype.h>
8#include <bech32.h>
9#include <chainparams.h>
10#include <coins.h>
11#include <key.h>
13#include <pubkey.h>
14#include <script/interpreter.h>
15#include <script/script.h>
16#include <script/sign.h>
17#include <script/solver.h>
18#include <script/verify_flags.h>
19#include <secp256k1.h>
20#include <secp256k1_extrakeys.h>
22#include <span.h>
23#include <streams.h>
24#include <tinyformat.h>
25#include <uint256.h>
26#include <util/strencodings.h>
27
28#include <algorithm>
29#include <cassert>
30#include <cstddef>
31#include <optional>
32#include <span>
33#include <type_traits>
34#include <utility>
35
36namespace bip352 {
37
39 : m_prevouts_summary{std::make_unique<secp256k1_silentpayments_prevouts_summary>(prevouts_summary)} {}
40
42PrevoutsSummary& PrevoutsSummary::operator=(PrevoutsSummary&&) noexcept = default;
43
45
47{
48 return m_prevouts_summary.get();
49}
50
51std::optional<SilentPaymentsDestination> SilentPaymentsDestination::From(
52 const CPubKey& scan_pubkey,
53 const CPubKey& spend_pubkey,
54 uint8_t version,
55 std::span<const unsigned char> extension_data
56) {
57 if (version >= 31) return std::nullopt;
58 if (version == 0 && !extension_data.empty()) {
59 // V0 address has no extension data
60 return std::nullopt;
61 }
62 if (!scan_pubkey.IsFullyValid() || !scan_pubkey.IsCompressed()) return std::nullopt;
63 if (!spend_pubkey.IsFullyValid() || !spend_pubkey.IsCompressed()) return std::nullopt;
64 return SilentPaymentsDestination(version, scan_pubkey, spend_pubkey, extension_data);
65}
66
68 const std::string& str, const CChainParams& params)
69{
70 static constexpr size_t SILENT_PAYMENTS_V0_DATA_SIZE = 66;
71 static constexpr size_t SP_PUBKEYS_SIZE = 2 * CPubKey::COMPRESSED_SIZE;
72
74 if (dec.encoding != bech32::Encoding::BECH32M) {
75 return util::Unexpected{"Silent Payments address must use Bech32m checksum"};
76 }
77 if (dec.hrp != params.SilentPaymentsHRP()) {
78 return util::Unexpected{strprintf("Invalid or unsupported prefix for Silent Payments address (expected %s, got %s).", params.SilentPaymentsHRP(), dec.hrp)};
79 }
80 if (dec.data.empty()) {
81 return util::Unexpected{"Empty Bech32 data section"};
82 }
83 std::vector<unsigned char> data;
84 if (!ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, dec.data.begin() + 1, dec.data.end())) {
85 return util::Unexpected{"Invalid padding in Silent payments address (Bech32m data section)"};
86 }
87 if (data.size() < SILENT_PAYMENTS_V0_DATA_SIZE) {
88 return util::Unexpected{strprintf("Silent payments data payload is too small (expected at least %d, got %d).", SILENT_PAYMENTS_V0_DATA_SIZE, data.size())};
89 }
90 const uint8_t version = dec.data[0];
91 if (version >= 31) {
92 return util::Unexpected{strprintf("This implementation only supports Silent payments addresses v0 through v30 (got %d).", version)};
93 }
94 if (version == 0 && data.size() != SILENT_PAYMENTS_V0_DATA_SIZE) {
95 return util::Unexpected{strprintf("Silent payments version is v0 but data is not the correct size (expected %d, got %d).", SILENT_PAYMENTS_V0_DATA_SIZE, data.size())};
96 }
97 CPubKey scan_pubkey{data.begin(), data.begin() + CPubKey::COMPRESSED_SIZE};
98 CPubKey spend_pubkey{data.begin() + CPubKey::COMPRESSED_SIZE, data.begin() + 2 * CPubKey::COMPRESSED_SIZE};
99 std::span<unsigned char> extension_data{data.data() + SP_PUBKEYS_SIZE, data.size() - SP_PUBKEYS_SIZE};
100 auto sp_dest = SilentPaymentsDestination::From(scan_pubkey, spend_pubkey, version, extension_data);
101 if (!sp_dest) {
102 return util::Unexpected{"Invalid Silent payments address"};
103 }
104 return *sp_dest;
105}
106
108 m_label = std::make_unique<secp256k1_silentpayments_label>(label);
110 assert(ret);
111}
112
113std::optional<SilentPaymentsLabel> SilentPaymentsLabel::FromBytes(std::span<const unsigned char, CPubKey::COMPRESSED_SIZE> vch)
114{
117 return std::nullopt;
118 }
119 return SilentPaymentsLabel(label_obj);
120}
121
123SilentPaymentsLabel& SilentPaymentsLabel::operator=(SilentPaymentsLabel&&) noexcept = default;
125
127 : m_label{std::make_unique<secp256k1_silentpayments_label>(*label.m_label)}
128{
129 memcpy(m_vch, label.m_vch, CPubKey::COMPRESSED_SIZE);
130}
132 if (this != &label) {
133 m_label = std::make_unique<secp256k1_silentpayments_label>(*label.m_label);
134 memcpy(m_vch, label.m_vch, CPubKey::COMPRESSED_SIZE);
135 }
136 return *this;
137}
138
140 return m_label.get();
141}
142
143std::optional<PubKey> GetPubKeyFromInput(const CTxIn& txin, const CScript& spk)
144{
145 std::vector<std::vector<unsigned char>> solutions;
146 const TxoutType type = Solver(spk, solutions);
147
148 if (type == TxoutType::WITNESS_V1_TAPROOT) {
149 const auto& stack = txin.scriptWitness.stack;
150 if (stack.empty()) return std::nullopt;
151 const bool has_annex = !stack.back().empty() && stack.back()[0] == ANNEX_TAG;
152 const size_t effective_size = stack.size() - (has_annex ? 1 : 0);
153
154 if (effective_size > 1) {
155 // BIP-352: skip script-path spends using NUMS-H internal key.
156 // Validate control block size before checking internal key.
157 const auto& control = stack[effective_size - 1];
158 if (control.size() < TAPROOT_CONTROL_BASE_SIZE ||
159 control.size() > TAPROOT_CONTROL_MAX_SIZE ||
160 (control.size() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE != 0) {
161 return std::nullopt;
162 }
163 if (std::equal(WitnessV1Taproot::NUMS_H.begin(), WitnessV1Taproot::NUMS_H.end(), control.begin() + 1)) {
164 return std::nullopt;
165 }
166 }
167
168 XOnlyPubKey key{solutions[0]};
169 if (!key.IsFullyValid()) return std::nullopt;
170 return PubKey{key};
171 }
172
173 if (type == TxoutType::WITNESS_V0_KEYHASH) {
174 const auto& stack = txin.scriptWitness.stack;
175 if (stack.empty()) return std::nullopt;
176 CPubKey key{stack.back()};
177 if (!key.IsCompressed() || !key.IsFullyValid()) return std::nullopt;
178 return PubKey{key};
179 }
180
181 if (type == TxoutType::PUBKEYHASH) {
182 std::vector<std::vector<unsigned char>> stack;
184 return std::nullopt;
185 }
186 if (stack.empty()) return std::nullopt;
187 CPubKey key{stack.back()};
188 if (!key.IsCompressed() || !key.IsFullyValid()) return std::nullopt;
189 return PubKey{key};
190 }
191
192 if (type == TxoutType::SCRIPTHASH) {
193 // P2SH-P2WPKH only: eval scriptSig, verify redeem script is P2WPKH.
194 std::vector<std::vector<unsigned char>> stack;
196 return std::nullopt;
197 }
198 if (stack.empty()) return std::nullopt;
199 CScript redeem{stack.back().begin(), stack.back().end()};
200 if (Solver(redeem, solutions) != TxoutType::WITNESS_V0_KEYHASH) return std::nullopt;
201 if (txin.scriptWitness.stack.empty()) return std::nullopt;
202 CPubKey key{txin.scriptWitness.stack.back()};
203 if (!key.IsCompressed() || !key.IsFullyValid()) return std::nullopt;
204 return PubKey{key};
205 }
206
207 return std::nullopt;
208}
209
210static std::optional<PrevoutsSummary> CreateInputPubkeysTweak(
211 const std::vector<CPubKey>& plain_pubkeys,
212 const std::vector<XOnlyPubKey>& taproot_pubkeys,
214{
216 std::vector<secp256k1_pubkey> plain_pubkey_objs;
217 std::vector<secp256k1_pubkey*> plain_pubkey_ptrs;
218 plain_pubkey_objs.reserve(plain_pubkeys.size());
219 plain_pubkey_ptrs.reserve(plain_pubkeys.size());
220 for (const CPubKey& pubkey : plain_pubkeys) {
222 &plain_pubkey_objs.emplace_back(), pubkey.data(), pubkey.size());
223 // This pubkey is expected to be valid because GetPubKeyFromInput()
224 // already called IsFullyValid() before including it here
225 assert(ret);
226 plain_pubkey_ptrs.push_back(&plain_pubkey_objs.back());
227 }
228
229 std::vector<secp256k1_xonly_pubkey> taproot_pubkey_objs;
230 std::vector<secp256k1_xonly_pubkey*> taproot_pubkey_ptrs;
231 taproot_pubkey_objs.reserve(taproot_pubkeys.size());
232 taproot_pubkey_ptrs.reserve(taproot_pubkeys.size());
233 for (const XOnlyPubKey& pubkey : taproot_pubkeys) {
235 &taproot_pubkey_objs.emplace_back(), pubkey.data());
236 // This xonlypubkey is expected to be valid because
237 // GetPubKeyFromInput() already called IsFullyValid()
238 // before including it here
239 assert(ret);
240 taproot_pubkey_ptrs.push_back(&taproot_pubkey_objs.back());
241 }
242
243 std::array<std::byte, 36> smallest_outpoint_ser;
244 SpanWriter{smallest_outpoint_ser} << smallest_outpoint;
246 &prevouts_summary,
247 UCharCast(smallest_outpoint_ser.data()),
248 taproot_pubkey_ptrs.data(), taproot_pubkey_ptrs.size(),
249 plain_pubkey_ptrs.data(), plain_pubkey_ptrs.size()
250 );
251 if (!ret) return std::nullopt;
252 return PrevoutsSummary(prevouts_summary);
253}
254
255util::Expected<PrevoutsSummary, PrevoutsSummaryError> GetSilentPaymentsPrevoutsSummary(const std::vector<CTxIn>& vin, const std::map<COutPoint, Coin>& coins)
256{
257 // Extract the keys from the inputs
258 // or skip if no valid inputs
259 std::vector<CPubKey> pubkeys;
260 std::vector<XOnlyPubKey> xonly_pubkeys;
261 std::vector<COutPoint> tx_outpoints;
262 for (const CTxIn& txin : vin) {
263 const auto coin_it = coins.find(txin.prevout);
264 if (coin_it == coins.end()) return util::Unexpected(PrevoutsSummaryError::MISSING_COIN);
265 const Coin& coin = coin_it->second;
266 int witness_version{0};
267 std::vector<unsigned char> witness_program;
268 // BIP352 v0 skips transactions spending future witness versions.
269 if (coin.out.scriptPubKey.IsWitnessProgram(witness_version, witness_program) && witness_version > 1) {
271 }
272 tx_outpoints.emplace_back(txin.prevout);
273 auto pubkey = GetPubKeyFromInput(txin, coin.out.scriptPubKey);
274 if (pubkey.has_value()) {
275 std::visit([&pubkeys, &xonly_pubkeys](auto&& pubkey) {
276 using T = std::decay_t<decltype(pubkey)>;
277 if constexpr (std::is_same_v<T, CPubKey>) {
278 pubkeys.push_back(pubkey);
279 } else if constexpr (std::is_same_v<T, XOnlyPubKey>) {
280 xonly_pubkeys.push_back(pubkey);
281 }
282 }, *pubkey);
283 }
284 }
285 if (pubkeys.size() + xonly_pubkeys.size() == 0) return util::Unexpected(PrevoutsSummaryError::NOT_ELIGIBLE);
286 auto smallest_outpoint = std::min_element(tx_outpoints.begin(), tx_outpoints.end(), BIP352Comparator());
287 auto tweak = CreateInputPubkeysTweak(pubkeys, xonly_pubkeys, *smallest_outpoint);
289 return std::move(*tweak);
290}
291
292static std::optional<std::vector<secp256k1_xonly_pubkey>> CreateOutputs(
293 const std::vector<SilentPaymentsDestination>& recipients,
294 const std::vector<CKey>& plain_keys,
295 const std::vector<KeyPair>& taproot_keypairs,
297) {
298 bool ret;
299 std::vector<const secp256k1_keypair *> taproot_keypair_ptrs;
300 std::vector<const unsigned char *> plain_key_ptrs;
301 taproot_keypair_ptrs.reserve(taproot_keypairs.size());
302 plain_key_ptrs.reserve(plain_keys.size());
303
304 std::vector<secp256k1_silentpayments_recipient> recipient_objs;
305 std::vector<const secp256k1_silentpayments_recipient *> recipient_ptrs;
306 recipient_objs.reserve(recipients.size());
307 recipient_ptrs.reserve(recipients.size());
308
309 std::vector<secp256k1_xonly_pubkey> generated_outputs;
310 std::vector<secp256k1_xonly_pubkey *> generated_output_ptrs;
311 generated_outputs.reserve(recipients.size());
312 generated_output_ptrs.reserve(recipients.size());
313
314 for (size_t i = 0; i < recipients.size(); i++) {
316 ret = secp256k1_ec_pubkey_parse(secp256k1_context_static, &recipient_obj.scan_pubkey, recipients[i].GetScanPubKey().data(), recipients[i].GetScanPubKey().size());
317 assert(ret);
318 ret = secp256k1_ec_pubkey_parse(secp256k1_context_static, &recipient_obj.spend_pubkey, recipients[i].GetSpendPubKey().data(), recipients[i].GetSpendPubKey().size());
319 assert(ret);
320 recipient_obj.index = i;
321 recipient_objs.push_back(recipient_obj);
322 recipient_ptrs.push_back(&recipient_objs[i]);
323
324 secp256k1_xonly_pubkey generated_output{};
325 generated_outputs.push_back(generated_output);
326 generated_output_ptrs.push_back(&generated_outputs[i]);
327 }
328
329 for (const auto& key : plain_keys) {
330 if (!key.IsValid()) return std::nullopt;
331 plain_key_ptrs.push_back(UCharCast(key.begin()));
332 }
333 for (const auto& keypair : taproot_keypairs) {
334 if (!keypair.IsValid()) return std::nullopt;
335 taproot_keypair_ptrs.push_back(keypair.GetSecpKeypair());
336 }
337
338 // Serialize the outpoint
339 std::array<std::byte, 36> smallest_outpoint_ser;
340 SpanWriter{smallest_outpoint_ser} << smallest_outpoint;
341
343 generated_output_ptrs.data(),
344 recipient_ptrs.data(), recipient_ptrs.size(),
345 UCharCast(smallest_outpoint_ser.data()),
346 taproot_keypair_ptrs.data(), taproot_keypair_ptrs.size(),
347 plain_key_ptrs.data(), plain_key_ptrs.size()
348 );
349 if (!ret) return std::nullopt;
350 return generated_outputs;
351}
352
353std::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)
354{
355 if (sp_dests.empty()) return std::map<size_t, WitnessV1Taproot>();
356
357 assert(!smallest_outpoint.IsNull());
358 assert(!plain_keys.empty() || !taproot_keys.empty());
359
360 bool ret;
361 std::map<size_t, WitnessV1Taproot> tr_dests;
362 std::vector<SilentPaymentsDestination> recipients;
363 recipients.reserve(sp_dests.size());
364 for (const auto& [_, addr] : sp_dests) {
365 recipients.push_back(addr);
366 }
367 auto outputs = CreateOutputs(recipients, plain_keys, taproot_keys, smallest_outpoint);
368 // This will fail if any input pubkey is null or
369 // inputs were maliciously crafted to sum to zero
370 if (!outputs) return std::nullopt;
371 assert(sp_dests.size() == outputs->size());
372 size_t output_i{0};
373 for (const auto& [i, _] : sp_dests) {
374 unsigned char xonly_pubkey_bytes[32];
375 ret = secp256k1_xonly_pubkey_serialize(secp256k1_context_static, xonly_pubkey_bytes, &outputs.value()[output_i]);
376 assert(ret);
377 tr_dests[i] = WitnessV1Taproot{XOnlyPubKey{xonly_pubkey_bytes}};
378 output_i++;
379 }
380 return tr_dests;
381}
382
383static const unsigned char* LabelLookupCallback(const unsigned char* key, const void* context) {
384 auto label_context = static_cast<const LabelTweakMap*>(context);
385 auto it = label_context->find(std::span<const unsigned char, CPubKey::COMPRESSED_SIZE>{key, CPubKey::COMPRESSED_SIZE});
386 if (it != label_context->end()) {
387 return it->second.begin();
388 }
389 return nullptr;
390}
391
392static std::pair<SilentPaymentsLabel, uint256> CreateLabel(const CKey& scan_key, const uint32_t m) {
394 unsigned char label_tweak[32];
395 bool ret = secp256k1_silentpayments_recipient_label_create(GetSecp256k1SignContext(), &label_obj, label_tweak, UCharCast(scan_key.data()), m);
396 assert(ret);
397 return {SilentPaymentsLabel(label_obj), uint256{label_tweak}};
398}
399
400static CPubKey CreateLabeledSpendPubKey(const CPubKey& spend_pubkey, const SilentPaymentsLabel& label) {
401 secp256k1_pubkey spend_obj, labeled_spend_obj;
402 bool ret = secp256k1_ec_pubkey_parse(secp256k1_context_static, &spend_obj, spend_pubkey.data(), spend_pubkey.size());
403 assert(ret);
405 assert(ret);
406 size_t pubkeylen = CPubKey::COMPRESSED_SIZE;
407 CPubKey labeled_spend_pubkey;
408 ret = secp256k1_ec_pubkey_serialize(secp256k1_context_static, (unsigned char*)labeled_spend_pubkey.begin(), &pubkeylen, &labeled_spend_obj, SECP256K1_EC_COMPRESSED);
409 assert(ret);
410 return labeled_spend_pubkey;
411}
412
414 const LabelTweakMap& labels) : m_scan_key(scan_key), m_spend_pubkey(spend_pubkey), m_labels(labels)
415{
416 m_change_it = m_labels.emplace(CreateLabel(scan_key, 0)).first;
417 m_spend_pubkey_obj = std::make_unique<secp256k1_pubkey>();
419 assert(ret);
420}
421
423
425 return m_labels;
426}
427
429 CPubKey labeled_spend_pubkey = CreateLabeledSpendPubKey(m_spend_pubkey, label);
430 auto dest{SilentPaymentsDestination::From(m_scan_key.GetPubKey(), labeled_spend_pubkey)};
431 assert(dest);
432 return *dest;
433}
434
436 assert(m >= 1);
437 auto it = m_labels.emplace(CreateLabel(m_scan_key, m)).first;
438 return BuildLabeledDestination(it->first);
439}
440
443}
444
445std::optional<std::vector<SilentPaymentsOutput>> SilentPaymentsReceiver::Scan(
446 const PrevoutsSummary& prevouts_summary,
447 const std::vector<XOnlyPubKey>& tx_outputs
448) const {
449 bool ret;
450 std::vector<secp256k1_silentpayments_found_output> found_output_objs;
451 std::vector<secp256k1_silentpayments_found_output *> found_output_ptrs;
452 std::vector<secp256k1_xonly_pubkey> tx_output_objs;
453 std::vector<const secp256k1_xonly_pubkey *> tx_output_ptrs;
454 found_output_objs.reserve(tx_outputs.size());
455 found_output_ptrs.reserve(tx_outputs.size());
456 tx_output_objs.reserve(tx_outputs.size());
457 tx_output_ptrs.reserve(tx_outputs.size());
458
461
462 for (const XOnlyPubKey& tx_output : tx_outputs) {
463 secp256k1_xonly_pubkey tx_output_obj;
464 ret = secp256k1_xonly_pubkey_parse(secp256k1_context_static, &tx_output_obj, tx_output.data());
465 if (!ret) {
466 // It is possible that a P2TR output encodes an invalid x-only pubkey.
467 continue;
468 }
469 tx_output_objs.push_back(tx_output_obj);
470 tx_output_ptrs.push_back(&tx_output_objs.back());
471 found_output_objs.emplace_back();
472 found_output_ptrs.push_back(&found_output_objs.back());
473 }
474 if (tx_output_ptrs.empty()) return std::vector<SilentPaymentsOutput>{};
475
476 // Scan the outputs!
477 uint32_t n_found_outputs = 0;
479 found_output_ptrs.data(), &n_found_outputs,
480 tx_output_ptrs.data(), tx_output_ptrs.size(),
482 prevouts_summary.Get(),
483 m_spend_pubkey_obj.get(),
485 &m_labels
486 );
487 if (!ret) return std::nullopt;
488
489 std::vector<SilentPaymentsOutput> outputs;
490 for (size_t i = 0; i < n_found_outputs; i++) {
491 SilentPaymentsOutput sp_output;
492 ret = secp256k1_xonly_pubkey_serialize(secp256k1_context_static, sp_output.output.begin(), &found_output_objs[i].output);
493 assert(ret);
494 sp_output.tweak = uint256{found_output_objs[i].tweak};
495 if (found_output_objs[i].found_with_label) {
496 sp_output.label = SilentPaymentsLabel(found_output_objs[i].label);
497 }
498 outputs.emplace_back(std::move(sp_output));
499 }
500 return outputs;
501}
502}; // namespace bip352
int ret
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition: chainparams.h:77
const std::string & SilentPaymentsHRP() const
Definition: chainparams.h:116
An encapsulated private key.
Definition: key.h:46
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:134
const std::byte * begin() const
Definition: key.h:130
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:184
const std::byte * data() const
Definition: key.h:129
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 * data() const
Definition: pubkey.h:122
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:209
static constexpr unsigned int COMPRESSED_SIZE
Definition: pubkey.h:49
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid())
Definition: pubkey.cpp:320
unsigned int size() const
Simple read-only vector-like interface to the pubkey data.
Definition: pubkey.h:121
const unsigned char * begin() const
Definition: pubkey.h:123
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:406
bool IsWitnessProgram(int &version, std::vector< unsigned char > &program) const
Definition: script.cpp:250
An input of a transaction.
Definition: transaction.h:63
CScript scriptSig
Definition: transaction.h:66
CScriptWitness scriptWitness
Only serialized through CTransaction.
Definition: transaction.h:68
CScript scriptPubKey
Definition: transaction.h:144
A UTXO entry.
Definition: coins.h:46
CTxOut out
unspent transaction output
Definition: coins.h:49
Minimal stream for writing to an existing span of bytes.
Definition: streams.h:130
const unsigned char * end() const
Definition: pubkey.h:305
const unsigned char * begin() const
Definition: pubkey.h:304
static const XOnlyPubKey NUMS_H
Nothing Up My Sleeve point H Used as an internal key for provably disabling the key path spend see BI...
Definition: pubkey.h:244
PrevoutsSummary(const secp256k1_silentpayments_prevouts_summary &prevouts_summary)
Definition: bip352.cpp:38
const secp256k1_silentpayments_prevouts_summary * Get() const LIFETIMEBOUND
Definition: bip352.cpp:46
std::unique_ptr< secp256k1_silentpayments_label > m_label
Definition: bip352.h:107
SilentPaymentsLabel & operator=(SilentPaymentsLabel &&) noexcept
unsigned char m_vch[CPubKey::COMPRESSED_SIZE]
Definition: bip352.h:108
const secp256k1_silentpayments_label * Get() const LIFETIMEBOUND
Definition: bip352.cpp:139
SilentPaymentsLabel(const secp256k1_silentpayments_label &label)
Definition: bip352.cpp:107
static std::optional< SilentPaymentsLabel > FromBytes(std::span< const unsigned char, CPubKey::COMPRESSED_SIZE > vch)
Parses raw bytes into a fully valid label returns std::nullopt if vch is not a validly-encoded label.
Definition: bip352.cpp:113
SilentPaymentsDestination GetChangeDestination() const
Get this recipient's silent payments change destination.
Definition: bip352.cpp:441
SilentPaymentsDestination BuildLabeledDestination(const SilentPaymentsLabel &label) const
Definition: bip352.cpp:428
SilentPaymentsReceiver(const CKey &scan_key, const CPubKey &spend_pubkey, const LabelTweakMap &labels={})
Definition: bip352.cpp:413
const LabelTweakMap & GetLabels() const
Get this recipient's registered labels, including the change label.
Definition: bip352.cpp:424
LabelTweakMap::const_iterator m_change_it
Definition: bip352.h:245
SilentPaymentsDestination GenerateLabeledAddress(uint32_t m)
Register label m (e.g.
Definition: bip352.cpp:435
std::optional< std::vector< SilentPaymentsOutput > > Scan(const PrevoutsSummary &prevouts_summary, const std::vector< XOnlyPubKey > &tx_outputs) const
Scan a transaction for silent payments outputs.
Definition: bip352.cpp:445
std::unique_ptr< secp256k1_pubkey > m_spend_pubkey_obj
Definition: bip352.h:243
T & back()
Definition: prevector.h:408
256-bit opaque blob.
Definition: uint256.h:196
The util::Expected class provides a standard way for low-level functions to return either error value...
Definition: expected.h:44
The util::Unexpected class represents an unexpected value stored in util::Expected.
Definition: expected.h:21
static const PrecomputedData data
Precomputed COutPoint and CCoins values.
#define T(expected, seed, data)
bool EvalScript(std::vector< std::vector< unsigned char > > &stack, const CScript &script, script_verify_flags flags, const BaseSignatureChecker &checker, SigVersion sigversion, ScriptExecutionData &execdata, ScriptError *serror)
@ BASE
Bare scripts and BIP16 P2SH-wrapped redeemscripts.
constexpr size_t TAPROOT_CONTROL_NODE_SIZE
Definition: interpreter.h:245
constexpr size_t TAPROOT_CONTROL_MAX_SIZE
Definition: interpreter.h:247
constexpr script_verify_flags SCRIPT_VERIFY_NONE
Script verification flags.
Definition: interpreter.h:48
constexpr size_t TAPROOT_CONTROL_BASE_SIZE
Definition: interpreter.h:244
secp256k1_context * GetSecp256k1SignContext()
Access the secp256k1 context used for signing and MuSig2 nonce generation.
Definition: key.cpp:443
static int tweak(const secp256k1_context *ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache)
Definition: musig.c:64
@ BECH32M
Bech32m encoding as defined in BIP350.
@ SILENT_PAYMENTS
BIP352 imposed 1023 character limit on Bech32m encoded silent payment addresses. This guarantees find...
Definition: bech32.h:42
DecodeResult Decode(const std::string &str, CharLimit limit)
Decode a Bech32 or Bech32m string.
Definition: bech32.cpp:373
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
@ NOT_ELIGIBLE
This transaction is not eligible to be scanned for silent payments outputs: either none of its inputs...
@ MISSING_COIN
A prevout referenced by an input in vin has no corresponding entry in coins.
static const unsigned char * LabelLookupCallback(const unsigned char *key, const void *context)
Definition: bip352.cpp:383
static std::pair< SilentPaymentsLabel, uint256 > CreateLabel(const CKey &scan_key, const uint32_t m)
Definition: bip352.cpp:392
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
static std::optional< std::vector< secp256k1_xonly_pubkey > > CreateOutputs(const std::vector< SilentPaymentsDestination > &recipients, const std::vector< CKey > &plain_keys, const std::vector< KeyPair > &taproot_keypairs, const COutPoint &smallest_outpoint)
Definition: bip352.cpp:292
std::map< SilentPaymentsLabel, uint256, std::less<> > LabelTweakMap
Definition: bip352.h:227
std::variant< CPubKey, XOnlyPubKey > PubKey
Definition: bip352.h:39
static CPubKey CreateLabeledSpendPubKey(const CPubKey &spend_pubkey, const SilentPaymentsLabel &label)
Definition: bip352.cpp:400
static std::optional< PrevoutsSummary > CreateInputPubkeysTweak(const std::vector< CPubKey > &plain_pubkeys, const std::vector< XOnlyPubKey > &taproot_pubkeys, const COutPoint &smallest_outpoint)
Definition: bip352.cpp:210
constexpr unsigned int ANNEX_TAG
Definition: script.h:59
SECP256K1_API int secp256k1_ec_pubkey_serialize(const secp256k1_context *ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey *pubkey, unsigned int flags) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
Serialize a pubkey object into a serialized byte sequence.
Definition: secp256k1.c:282
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *input, size_t inputlen) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Parse a variable-length public key into the pubkey object.
Definition: secp256k1.c:264
#define SECP256K1_EC_COMPRESSED
Flag to pass to secp256k1_ec_pubkey_serialize.
Definition: secp256k1.h:216
SECP256K1_API const secp256k1_context *const secp256k1_context_static
A built-in constant secp256k1 context object with static storage duration, to be used in conjunction ...
Definition: secp256k1.h:237
SECP256K1_API int secp256k1_xonly_pubkey_serialize(const secp256k1_context *ctx, unsigned char *output32, const secp256k1_xonly_pubkey *pubkey) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Serialize an xonly_pubkey object into a 32-byte sequence.
Definition: main_impl.h:51
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(const secp256k1_context *ctx, secp256k1_xonly_pubkey *pubkey, const unsigned char *input32) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Parse a 32-byte sequence into a xonly_pubkey object.
Definition: main_impl.h:29
SECP256K1_API int secp256k1_silentpayments_recipient_label_serialize(const secp256k1_context *ctx, unsigned char *out33, const secp256k1_silentpayments_label *label) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Serialize a Silent Payments label.
Definition: main_impl.h:374
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_prevouts_summary_create(const secp256k1_context *ctx, secp256k1_silentpayments_prevouts_summary *prevouts_summary, const unsigned char *outpoint_smallest36, const secp256k1_xonly_pubkey *const *xonly_pubkeys, size_t n_xonly_pubkeys, const secp256k1_pubkey *const *pubkeys, size_t n_pubkeys) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Compute Silent Payments prevouts summary from prevout public keys and transaction inputs.
Definition: main_impl.h:484
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_label_parse(const secp256k1_context *ctx, secp256k1_silentpayments_label *label, const unsigned char *in33) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Parse a Silent Payments label.
Definition: main_impl.h:358
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_sender_create_outputs(const secp256k1_context *ctx, secp256k1_xonly_pubkey **generated_outputs, const secp256k1_silentpayments_recipient **recipients, size_t n_recipients, const unsigned char *outpoint_smallest36, const secp256k1_keypair *const *keypairs, size_t n_keypairs, const unsigned char *const *seckeys, size_t n_seckeys) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5)
Create Silent Payments outputs for recipient(s).
Definition: main_impl.h:187
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_create_labeled_spend_pubkey(const secp256k1_context *ctx, secp256k1_pubkey *labeled_spend_pubkey, const secp256k1_pubkey *unlabeled_spend_pubkey, const secp256k1_silentpayments_label *label) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
Create Silent Payments labeled spend public key.
Definition: main_impl.h:426
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_scan_outputs(const secp256k1_context *ctx, secp256k1_silentpayments_found_output **found_outputs, uint32_t *n_found_outputs, const secp256k1_xonly_pubkey *const *tx_outputs, size_t n_tx_outputs, const unsigned char *scan_key32, const secp256k1_silentpayments_prevouts_summary *prevouts_summary, const secp256k1_pubkey *unlabeled_spend_pubkey, secp256k1_silentpayments_label_lookup label_lookup, const void *label_context) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8)
Scan for Silent Payments transaction outputs.
Definition: main_impl.h:598
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_label_create(const secp256k1_context *ctx, secp256k1_silentpayments_label *label, unsigned char *label_tweak32, const unsigned char *scan_key32, uint32_t m) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
Create Silent Payments label tweak and label.
Definition: main_impl.h:389
const BaseSignatureChecker & DUMMY_CHECKER
A signature checker that accepts all signatures.
Definition: sign.cpp:958
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
@ WITNESS_V0_KEYHASH
unsigned char * UCharCast(char *c)
Definition: span.h:95
std::vector< std::vector< unsigned char > > stack
Definition: script.h:581
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
SilentPaymentsDestination(uint8_t version, const CPubKey &scan_pubkey, const CPubKey &spend_pubkey, std::span< const unsigned char > extension_data={})
Definition: bip352.h:77
std::optional< SilentPaymentsLabel > label
Definition: bip352.h:163
Opaque data structure that holds a parsed and valid public key.
Definition: secp256k1.h:62
unsigned char data[64]
Definition: secp256k1.h:63
Opaque data structure that holds a Silent Payments label.
Opaque data structure that holds Silent Payments prevouts summary data.
The data from a single recipient address.
Opaque data structure that holds a parsed and valid "x-only" public key.
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
consteval auto _(util::TranslatedLiteral str)
Definition: translation.h:79
assert(!tx.IsCoinBase())
WalletContext context