9#include <chainparams.h>
48 return m_prevouts_summary.get();
55 std::span<const unsigned char> extension_data
57 if (version >= 31)
return std::nullopt;
58 if (version == 0 && !extension_data.empty()) {
70 static constexpr size_t SILENT_PAYMENTS_V0_DATA_SIZE = 66;
75 return util::Unexpected{
"Silent Payments address must use Bech32m checksum"};
80 if (dec.data.empty()) {
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)"};
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())};
90 const uint8_t version = dec.data[0];
92 return util::Unexpected{
strprintf(
"This implementation only supports Silent payments addresses v0 through v30 (got %d).", version)};
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())};
99 std::span<unsigned char> extension_data{
data.data() + SP_PUBKEYS_SIZE,
data.size() - SP_PUBKEYS_SIZE};
108 m_label = std::make_unique<secp256k1_silentpayments_label>(label);
127 : m_label{std::make_unique<secp256k1_silentpayments_label>(*label.m_label)}
132 if (
this != &label) {
133 m_label = std::make_unique<secp256k1_silentpayments_label>(*label.
m_label);
145 std::vector<std::vector<unsigned char>> solutions;
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);
154 if (effective_size > 1) {
157 const auto& control = stack[effective_size - 1];
169 if (!key.IsFullyValid())
return std::nullopt;
175 if (stack.empty())
return std::nullopt;
177 if (!key.IsCompressed() || !key.IsFullyValid())
return std::nullopt;
182 std::vector<std::vector<unsigned char>> stack;
186 if (stack.empty())
return std::nullopt;
188 if (!key.IsCompressed() || !key.IsFullyValid())
return std::nullopt;
194 std::vector<std::vector<unsigned char>> stack;
198 if (stack.empty())
return std::nullopt;
199 CScript redeem{stack.
back().begin(), stack.back().end()};
203 if (!key.IsCompressed() || !key.IsFullyValid())
return std::nullopt;
211 const std::vector<CPubKey>& plain_pubkeys,
212 const std::vector<XOnlyPubKey>& taproot_pubkeys,
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());
226 plain_pubkey_ptrs.push_back(&plain_pubkey_objs.back());
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());
240 taproot_pubkey_ptrs.push_back(&taproot_pubkey_objs.back());
243 std::array<std::byte, 36> smallest_outpoint_ser;
248 taproot_pubkey_ptrs.data(), taproot_pubkey_ptrs.size(),
249 plain_pubkey_ptrs.data(), plain_pubkey_ptrs.size()
251 if (!
ret)
return std::nullopt;
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);
265 const Coin& coin = coin_it->second;
266 int witness_version{0};
267 std::vector<unsigned char> witness_program;
272 tx_outpoints.emplace_back(txin.prevout);
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);
289 return std::move(*
tweak);
293 const std::vector<SilentPaymentsDestination>& recipients,
294 const std::vector<CKey>& plain_keys,
295 const std::vector<KeyPair>& taproot_keypairs,
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());
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());
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());
314 for (
size_t i = 0; i < recipients.size(); i++) {
320 recipient_obj.
index = i;
321 recipient_objs.push_back(recipient_obj);
322 recipient_ptrs.push_back(&recipient_objs[i]);
325 generated_outputs.push_back(generated_output);
326 generated_output_ptrs.push_back(&generated_outputs[i]);
329 for (
const auto& key : plain_keys) {
330 if (!key.IsValid())
return std::nullopt;
331 plain_key_ptrs.push_back(
UCharCast(key.begin()));
333 for (
const auto& keypair : taproot_keypairs) {
334 if (!keypair.IsValid())
return std::nullopt;
335 taproot_keypair_ptrs.push_back(keypair.GetSecpKeypair());
339 std::array<std::byte, 36> smallest_outpoint_ser;
343 generated_output_ptrs.data(),
344 recipient_ptrs.data(), recipient_ptrs.size(),
346 taproot_keypair_ptrs.data(), taproot_keypair_ptrs.size(),
347 plain_key_ptrs.data(), plain_key_ptrs.size()
349 if (!
ret)
return std::nullopt;
350 return generated_outputs;
355 if (sp_dests.empty())
return std::map<size_t, WitnessV1Taproot>();
358 assert(!plain_keys.empty() || !taproot_keys.empty());
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);
370 if (!outputs)
return std::nullopt;
371 assert(sp_dests.size() == outputs->size());
373 for (
const auto& [i,
_] : sp_dests) {
374 unsigned char xonly_pubkey_bytes[32];
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();
392static std::pair<SilentPaymentsLabel, uint256>
CreateLabel(
const CKey& scan_key,
const uint32_t m) {
394 unsigned char label_tweak[32];
410 return labeled_spend_pubkey;
414 const LabelTweakMap& labels) : m_scan_key(scan_key), m_spend_pubkey(spend_pubkey), m_labels(labels)
447 const std::vector<XOnlyPubKey>& tx_outputs
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());
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());
474 if (tx_output_ptrs.empty())
return std::vector<SilentPaymentsOutput>{};
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(),
487 if (!
ret)
return std::nullopt;
489 std::vector<SilentPaymentsOutput> outputs;
490 for (
size_t i = 0; i < n_found_outputs; i++) {
495 if (found_output_objs[i].found_with_label) {
498 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 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.
#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)
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)