9#include <chainparams.h>
49 return m_prevouts_summary.get();
56 std::span<const unsigned char> extension_data
58 if (version >= 31)
return std::nullopt;
59 if (version == 0 && !extension_data.empty()) {
71 static constexpr size_t SILENT_PAYMENTS_V0_DATA_SIZE = 66;
76 return util::Unexpected{
"Silent Payments address must use Bech32m checksum"};
81 if (dec.data.empty()) {
84 std::vector<unsigned char>
data;
85 if (!ConvertBits<5, 8, false>([&](
unsigned char c) {
data.push_back(c); }, dec.data.begin() + 1, dec.data.end())) {
86 return util::Unexpected{
"Invalid padding in Silent payments address (Bech32m data section)"};
88 if (
data.size() < SILENT_PAYMENTS_V0_DATA_SIZE) {
89 return util::Unexpected{
strprintf(
"Silent payments data payload is too small (expected at least %d, got %d).", SILENT_PAYMENTS_V0_DATA_SIZE,
data.size())};
91 const uint8_t version = dec.data[0];
93 return util::Unexpected{
strprintf(
"This implementation only supports Silent payments addresses v0 through v30 (got %d).", version)};
95 if (version == 0 &&
data.size() != SILENT_PAYMENTS_V0_DATA_SIZE) {
96 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())};
100 std::span<unsigned char> extension_data{
data.data() + SP_PUBKEYS_SIZE,
data.size() - SP_PUBKEYS_SIZE};
109 m_label = std::make_unique<secp256k1_silentpayments_label>(label);
128 : m_label{std::make_unique<secp256k1_silentpayments_label>(*label.m_label)}
133 if (
this != &label) {
134 m_label = std::make_unique<secp256k1_silentpayments_label>(*label.
m_label);
146 std::vector<std::vector<unsigned char>> solutions;
151 if (stack.empty())
return std::nullopt;
152 const bool has_annex = !stack.back().empty() && stack.back()[0] ==
ANNEX_TAG;
153 const size_t effective_size = stack.size() - (has_annex ? 1 : 0);
155 if (effective_size > 1) {
158 const auto& control = stack[effective_size - 1];
170 if (!key.IsFullyValid())
return std::nullopt;
176 if (stack.empty())
return std::nullopt;
178 if (!key.IsCompressed() || !key.IsFullyValid())
return std::nullopt;
193 const uint160 pubkey_hash{solutions[0]};
197 std::vector<unsigned char> pubkey_candidate;
201 if (pubkey_candidate.size() == 33 &&
Hash160(pubkey_candidate) == pubkey_hash) {
203 if (key.IsFullyValid())
return PubKey{key};
213 std::vector<std::vector<unsigned char>> stack;
217 if (stack.empty())
return std::nullopt;
218 CScript redeem{stack.
back().begin(), stack.back().end()};
222 if (!key.IsCompressed() || !key.IsFullyValid())
return std::nullopt;
230 const std::vector<CPubKey>& plain_pubkeys,
231 const std::vector<XOnlyPubKey>& taproot_pubkeys,
235 std::vector<secp256k1_pubkey> plain_pubkey_objs;
236 std::vector<secp256k1_pubkey*> plain_pubkey_ptrs;
237 plain_pubkey_objs.reserve(plain_pubkeys.size());
238 plain_pubkey_ptrs.reserve(plain_pubkeys.size());
239 for (
const CPubKey& pubkey : plain_pubkeys) {
241 &plain_pubkey_objs.emplace_back(), pubkey.data(), pubkey.size());
245 plain_pubkey_ptrs.push_back(&plain_pubkey_objs.back());
248 std::vector<secp256k1_xonly_pubkey> taproot_pubkey_objs;
249 std::vector<secp256k1_xonly_pubkey*> taproot_pubkey_ptrs;
250 taproot_pubkey_objs.reserve(taproot_pubkeys.size());
251 taproot_pubkey_ptrs.reserve(taproot_pubkeys.size());
252 for (
const XOnlyPubKey& pubkey : taproot_pubkeys) {
254 &taproot_pubkey_objs.emplace_back(), pubkey.data());
259 taproot_pubkey_ptrs.push_back(&taproot_pubkey_objs.back());
262 std::array<std::byte, 36> smallest_outpoint_ser;
267 taproot_pubkey_ptrs.data(), taproot_pubkey_ptrs.size(),
268 plain_pubkey_ptrs.data(), plain_pubkey_ptrs.size()
270 if (!
ret)
return std::nullopt;
278 std::vector<CPubKey> pubkeys;
279 std::vector<XOnlyPubKey> xonly_pubkeys;
280 std::vector<COutPoint> tx_outpoints;
281 for (
const CTxIn& txin : vin) {
282 const auto coin_it = coins.find(txin.prevout);
284 const Coin& coin = coin_it->second;
285 int witness_version{0};
286 std::vector<unsigned char> witness_program;
291 tx_outpoints.emplace_back(txin.prevout);
293 if (pubkey.has_value()) {
294 std::visit([&pubkeys, &xonly_pubkeys](
auto&& pubkey) {
295 using T = std::decay_t<
decltype(pubkey)>;
296 if constexpr (std::is_same_v<T, CPubKey>) {
297 pubkeys.push_back(pubkey);
298 }
else if constexpr (std::is_same_v<T, XOnlyPubKey>) {
299 xonly_pubkeys.push_back(pubkey);
308 return std::move(*
tweak);
312 const std::vector<SilentPaymentsDestination>& recipients,
313 const std::vector<CKey>& plain_keys,
314 const std::vector<KeyPair>& taproot_keypairs,
318 std::vector<const secp256k1_keypair *> taproot_keypair_ptrs;
319 std::vector<const unsigned char *> plain_key_ptrs;
320 taproot_keypair_ptrs.reserve(taproot_keypairs.size());
321 plain_key_ptrs.reserve(plain_keys.size());
323 std::vector<secp256k1_silentpayments_recipient> recipient_objs;
324 std::vector<const secp256k1_silentpayments_recipient *> recipient_ptrs;
325 recipient_objs.reserve(recipients.size());
326 recipient_ptrs.reserve(recipients.size());
328 std::vector<secp256k1_xonly_pubkey> generated_outputs;
329 std::vector<secp256k1_xonly_pubkey *> generated_output_ptrs;
330 generated_outputs.reserve(recipients.size());
331 generated_output_ptrs.reserve(recipients.size());
333 for (
size_t i = 0; i < recipients.size(); i++) {
339 recipient_obj.
index = i;
340 recipient_objs.push_back(recipient_obj);
341 recipient_ptrs.push_back(&recipient_objs[i]);
344 generated_outputs.push_back(generated_output);
345 generated_output_ptrs.push_back(&generated_outputs[i]);
348 for (
const auto& key : plain_keys) {
349 if (!key.IsValid())
return std::nullopt;
350 plain_key_ptrs.push_back(
UCharCast(key.begin()));
352 for (
const auto& keypair : taproot_keypairs) {
353 if (!keypair.IsValid())
return std::nullopt;
354 taproot_keypair_ptrs.push_back(keypair.GetSecpKeypair());
358 std::array<std::byte, 36> smallest_outpoint_ser;
362 generated_output_ptrs.data(),
363 recipient_ptrs.data(), recipient_ptrs.size(),
365 taproot_keypair_ptrs.data(), taproot_keypair_ptrs.size(),
366 plain_key_ptrs.data(), plain_key_ptrs.size()
368 if (!
ret)
return std::nullopt;
369 return generated_outputs;
374 if (sp_dests.empty())
return std::map<size_t, WitnessV1Taproot>();
377 assert(!plain_keys.empty() || !taproot_keys.empty());
380 std::map<size_t, WitnessV1Taproot> tr_dests;
381 std::vector<SilentPaymentsDestination> recipients;
382 recipients.reserve(sp_dests.size());
383 for (
const auto& [
_, addr] : sp_dests) {
384 recipients.push_back(addr);
389 if (!outputs)
return std::nullopt;
390 assert(sp_dests.size() == outputs->size());
392 for (
const auto& [i,
_] : sp_dests) {
393 unsigned char xonly_pubkey_bytes[32];
404 auto it = label_context->find(std::span<const unsigned char, CPubKey::COMPRESSED_SIZE>{key,
CPubKey::COMPRESSED_SIZE});
405 if (it != label_context->end()) {
406 return it->second.begin();
411static std::pair<SilentPaymentsLabel, uint256>
CreateLabel(
const CKey& scan_key,
const uint32_t m) {
413 unsigned char label_tweak[32];
429 return labeled_spend_pubkey;
433 const LabelTweakMap& labels) : m_scan_key(scan_key), m_spend_pubkey(spend_pubkey), m_labels(labels)
466 const std::vector<XOnlyPubKey>& tx_outputs
469 std::vector<secp256k1_silentpayments_found_output> found_output_objs;
470 std::vector<secp256k1_silentpayments_found_output *> found_output_ptrs;
471 std::vector<secp256k1_xonly_pubkey> tx_output_objs;
472 std::vector<const secp256k1_xonly_pubkey *> tx_output_ptrs;
473 found_output_objs.reserve(tx_outputs.size());
474 found_output_ptrs.reserve(tx_outputs.size());
475 tx_output_objs.reserve(tx_outputs.size());
476 tx_output_ptrs.reserve(tx_outputs.size());
488 tx_output_objs.push_back(tx_output_obj);
489 tx_output_ptrs.push_back(&tx_output_objs.back());
490 found_output_objs.emplace_back();
491 found_output_ptrs.push_back(&found_output_objs.back());
493 if (tx_output_ptrs.empty())
return std::vector<SilentPaymentsOutput>{};
496 uint32_t n_found_outputs = 0;
498 found_output_ptrs.data(), &n_found_outputs,
499 tx_output_ptrs.data(), tx_output_ptrs.size(),
501 prevouts_summary.
Get(),
506 if (!
ret)
return std::nullopt;
508 std::vector<SilentPaymentsOutput> outputs;
509 for (
size_t i = 0; i < n_found_outputs; i++) {
514 if (found_output_objs[i].found_with_label) {
517 outputs.emplace_back(std::move(sp_output));
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
const std::string & SilentPaymentsHRP() const
An encapsulated private key.
bool IsValid() const
Check whether this private key is valid.
const std::byte * begin() const
CPubKey GetPubKey() const
Compute the public key from a private key.
const std::byte * data() const
An outpoint - a combination of a transaction hash and an index n into its vout.
An encapsulated public key.
const unsigned char * data() const
bool IsCompressed() const
Check whether this is a compressed public key.
static constexpr unsigned int COMPRESSED_SIZE
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid())
unsigned int size() const
Simple read-only vector-like interface to the pubkey data.
const unsigned char * begin() const
Serialized script, used inside transaction inputs and outputs.
bool GetOp(const_iterator &pc, opcodetype &opcodeRet, std::vector< unsigned char > &vchRet) const
bool IsWitnessProgram(int &version, std::vector< unsigned char > &program) const
An input of a transaction.
CScriptWitness scriptWitness
Only serialized through CTransaction.
CTxOut out
unspent transaction output
Minimal stream for writing to an existing span of bytes.
const unsigned char * end() const
const unsigned char * begin() const
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...
PrevoutsSummary(const secp256k1_silentpayments_prevouts_summary &prevouts_summary)
const secp256k1_silentpayments_prevouts_summary * Get() const LIFETIMEBOUND
std::unique_ptr< secp256k1_silentpayments_label > m_label
SilentPaymentsLabel & operator=(SilentPaymentsLabel &&) noexcept
unsigned char m_vch[CPubKey::COMPRESSED_SIZE]
const secp256k1_silentpayments_label * Get() const LIFETIMEBOUND
SilentPaymentsLabel(const secp256k1_silentpayments_label &label)
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.
SilentPaymentsDestination GetChangeDestination() const
Get this recipient's silent payments change destination.
SilentPaymentsDestination BuildLabeledDestination(const SilentPaymentsLabel &label) const
~SilentPaymentsReceiver()
SilentPaymentsReceiver(const CKey &scan_key, const CPubKey &spend_pubkey, const LabelTweakMap &labels={})
const LabelTweakMap & GetLabels() const
Get this recipient's registered labels, including the change label.
LabelTweakMap::const_iterator m_change_it
SilentPaymentsDestination GenerateLabeledAddress(uint32_t m)
Register label m (e.g.
std::optional< std::vector< SilentPaymentsOutput > > Scan(const PrevoutsSummary &prevouts_summary, const std::vector< XOnlyPubKey > &tx_outputs) const
Scan a transaction for silent payments outputs.
std::unique_ptr< secp256k1_pubkey > m_spend_pubkey_obj
The util::Expected class provides a standard way for low-level functions to return either error value...
The util::Unexpected class represents an unexpected value stored in util::Expected.
static const PrecomputedData data
Precomputed COutPoint and CCoins values.
uint160 Hash160(const T1 &in1)
Compute the 160-bit hash an object.
#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
constexpr size_t TAPROOT_CONTROL_MAX_SIZE
constexpr script_verify_flags SCRIPT_VERIFY_NONE
Script verification flags.
constexpr size_t TAPROOT_CONTROL_BASE_SIZE
secp256k1_context * GetSecp256k1SignContext()
Access the secp256k1 context used for signing and MuSig2 nonce generation.
static int tweak(const secp256k1_context *ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache)
@ BECH32M
Bech32m encoding as defined in BIP350.
@ SILENT_PAYMENTS
BIP352 imposed 1023 character limit on Bech32m encoded silent payment addresses. This guarantees find...
DecodeResult Decode(const std::string &str, CharLimit limit)
Decode a Bech32 or Bech32m string.
util::Expected< PrevoutsSummary, PrevoutsSummaryError > GetSilentPaymentsPrevoutsSummary(const std::vector< CTxIn > &vin, const std::map< COutPoint, Coin > &coins)
Get silent payments public data from transaction inputs.
std::optional< PubKey > GetPubKeyFromInput(const CTxIn &txin, const CScript &spk)
Get the public key from an input.
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.
@ 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)
static std::pair< SilentPaymentsLabel, uint256 > CreateLabel(const CKey &scan_key, const uint32_t m)
util::Expected< SilentPaymentsDestination, std::string > DecodeSilentPaymentsAddress(const std::string &str, const CChainParams ¶ms)
Decode a BIP352 "sp1..." address. Returns the destination, or an error message on failure.
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)
std::map< SilentPaymentsLabel, uint256, std::less<> > LabelTweakMap
std::variant< CPubKey, XOnlyPubKey > PubKey
static CPubKey CreateLabeledSpendPubKey(const CPubKey &spend_pubkey, const SilentPaymentsLabel &label)
static std::optional< PrevoutsSummary > CreateInputPubkeysTweak(const std::vector< CPubKey > &plain_pubkeys, const std::vector< XOnlyPubKey > &taproot_pubkeys, const COutPoint &smallest_outpoint)
opcodetype
Script opcodes.
constexpr unsigned int ANNEX_TAG
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.
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.
#define SECP256K1_EC_COMPRESSED
Flag to pass to secp256k1_ec_pubkey_serialize.
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 ...
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.
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.
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.
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).
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.
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.
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.
const BaseSignatureChecker & DUMMY_CHECKER
A signature checker that accepts all signatures.
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.
unsigned char * UCharCast(char *c)
std::vector< std::vector< unsigned char > > stack
static std::optional< SilentPaymentsDestination > From(const CPubKey &scan_pubkey, const CPubKey &spend_pubkey, uint8_t version=0, std::span< const unsigned char > extension_data={})
SilentPaymentsDestination(uint8_t version, const CPubKey &scan_pubkey, const CPubKey &spend_pubkey, std::span< const unsigned char > extension_data={})
std::optional< SilentPaymentsLabel > label
Opaque data structure that holds a parsed and valid public key.
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.
secp256k1_pubkey scan_pubkey
secp256k1_pubkey spend_pubkey
Opaque data structure that holds a parsed and valid "x-only" public key.
consteval auto _(util::TranslatedLiteral str)