Branch data Line data Source code
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 : : #ifndef BITCOIN_COMMON_BIP352_H
6 : : #define BITCOIN_COMMON_BIP352_H
7 : :
8 : : #include <addresstype.h>
9 : : #include <attributes.h>
10 : : #include <compat/byteswap.h>
11 : : #include <key.h>
12 : : #include <primitives/transaction.h>
13 : : #include <pubkey.h>
14 : : #include <uint256.h>
15 : : #include <util/expected.h>
16 : :
17 : : #include <array>
18 : : #include <compare>
19 : : #include <cstdint>
20 : : #include <cstring>
21 : : #include <functional>
22 : : #include <map>
23 : : #include <memory>
24 : : #include <optional>
25 : : #include <span>
26 : : #include <string>
27 : : #include <variant>
28 : : #include <vector>
29 : :
30 : : struct secp256k1_silentpayments_label;
31 : : struct secp256k1_silentpayments_prevouts_summary;
32 : : struct secp256k1_pubkey;
33 : : class CChainParams;
34 : : class CScript;
35 : : class Coin;
36 : :
37 : : namespace bip352 {
38 : :
39 : : using PubKey = std::variant<CPubKey, XOnlyPubKey>;
40 : :
41 : : class PrevoutsSummary
42 : : {
43 : : private:
44 : : std::unique_ptr<secp256k1_silentpayments_prevouts_summary> m_prevouts_summary;
45 : :
46 : : public:
47 : : PrevoutsSummary(const secp256k1_silentpayments_prevouts_summary& prevouts_summary);
48 : : PrevoutsSummary(PrevoutsSummary&&) noexcept;
49 : : PrevoutsSummary& operator=(PrevoutsSummary&&) noexcept;
50 : : ~PrevoutsSummary();
51 : :
52 : : // Delete copy constructors
53 : : PrevoutsSummary(const PrevoutsSummary&) = delete;
54 : : PrevoutsSummary& operator=(const PrevoutsSummary&) = delete;
55 : :
56 : : const secp256k1_silentpayments_prevouts_summary* Get() const LIFETIMEBOUND;
57 : : };
58 : :
59 : : struct BIP352Comparator {
60 : 0 : bool operator()(const COutPoint& a, const COutPoint& b) const {
61 : : // BIP352 defines the "smallest outpoint" based on a lexicographic
62 : : // sort of the outpoints, using the 36-byte serialization:
63 : : // <txid, 32-bytes little-endian>:<vout, 4-bytes little-endian>
64 [ # # ]: 0 : if (a.hash != b.hash) return a.hash < b.hash;
65 : 0 : return internal_bswap_32(a.n) < internal_bswap_32(b.n);
66 : : }
67 : : };
68 : :
69 : 0 : struct SilentPaymentsDestination
70 : : {
71 : : private:
72 : : uint8_t m_version;
73 : : CPubKey m_scan_pubkey;
74 : : CPubKey m_spend_pubkey;
75 : : std::vector<unsigned char> m_extension_data;
76 : :
77 : 0 : SilentPaymentsDestination(
78 : : uint8_t version,
79 : : const CPubKey& scan_pubkey,
80 : : const CPubKey& spend_pubkey,
81 : : std::span<const unsigned char> extension_data = {}
82 : 0 : ) : m_version(version), m_scan_pubkey(scan_pubkey),
83 : 0 : m_spend_pubkey(spend_pubkey),
84 : 0 : m_extension_data(extension_data.begin(), extension_data.end()) {};
85 : : public:
86 : : static std::optional<SilentPaymentsDestination> From(
87 : : const CPubKey& scan_pubkey,
88 : : const CPubKey& spend_pubkey,
89 : : uint8_t version = 0,
90 : : std::span<const unsigned char> extension_data = {}
91 : : );
92 : :
93 : : uint8_t GetVersion() const { return m_version; }
94 : : const CPubKey& GetScanPubKey() const { return m_scan_pubkey; }
95 : : const CPubKey& GetSpendPubKey() const { return m_spend_pubkey; }
96 : : std::span<const unsigned char> GetExtensionData() const { return m_extension_data; }
97 : :
98 : : bool operator==(const SilentPaymentsDestination&) const = default;
99 : : };
100 : :
101 : : //! Decode a BIP352 "sp1..." address. Returns the destination, or an error message on failure.
102 : : util::Expected<SilentPaymentsDestination, std::string> DecodeSilentPaymentsAddress(
103 : : const std::string& str, const CChainParams& params);
104 : :
105 : : class SilentPaymentsLabel {
106 : : private:
107 : : std::unique_ptr<secp256k1_silentpayments_label> m_label;
108 : : unsigned char m_vch[CPubKey::COMPRESSED_SIZE];
109 : :
110 : : //! Parses raw bytes into a fully valid label
111 : : //! returns std::nullopt if vch is not a validly-encoded label.
112 : : static std::optional<SilentPaymentsLabel> FromBytes(std::span<const unsigned char, CPubKey::COMPRESSED_SIZE> vch);
113 : :
114 : : public:
115 : : SilentPaymentsLabel(const secp256k1_silentpayments_label& label);
116 : :
117 : : SilentPaymentsLabel(SilentPaymentsLabel&&) noexcept;
118 : : SilentPaymentsLabel& operator=(SilentPaymentsLabel&&) noexcept;
119 : : SilentPaymentsLabel(const SilentPaymentsLabel&);
120 : : SilentPaymentsLabel& operator=(const SilentPaymentsLabel&);
121 : :
122 : : ~SilentPaymentsLabel();
123 : :
124 : : friend bool operator==(const SilentPaymentsLabel& a, const SilentPaymentsLabel& b) {
125 : : return memcmp(a.m_vch, b.m_vch, CPubKey::COMPRESSED_SIZE) == 0;
126 : : }
127 : 0 : friend bool operator<(const SilentPaymentsLabel& a, const SilentPaymentsLabel& b) {
128 [ # # # # : 0 : return memcmp(a.m_vch, b.m_vch, CPubKey::COMPRESSED_SIZE) < 0;
# # ]
129 : : }
130 : : friend bool operator>(const SilentPaymentsLabel& a, const SilentPaymentsLabel& b) {
131 : : return b < a;
132 : : }
133 : : //! Transparent comparisons against a raw 33-byte compressed label key, so a
134 : : //! LabelTweakMap can be looked up by key bytes (e.g. from a secp256k1 callback)
135 : : //! without constructing a fully-parsed SilentPaymentsLabel.
136 : 0 : friend bool operator<(const SilentPaymentsLabel& a, std::span<const unsigned char, CPubKey::COMPRESSED_SIZE> b) {
137 : 0 : return memcmp(a.m_vch, b.data(), CPubKey::COMPRESSED_SIZE) < 0;
138 : : }
139 : 0 : friend bool operator<(std::span<const unsigned char, CPubKey::COMPRESSED_SIZE> a, const SilentPaymentsLabel& b) {
140 : 0 : return memcmp(a.data(), b.m_vch, CPubKey::COMPRESSED_SIZE) < 0;
141 : : }
142 : :
143 : : template <typename Stream>
144 : : void Serialize(Stream& s) const
145 : : {
146 : : s << std::span{m_vch, CPubKey::COMPRESSED_SIZE};
147 : : }
148 : :
149 : : template <typename Stream>
150 : : static std::optional<SilentPaymentsLabel> Unserialize(Stream& s)
151 : : {
152 : : std::array<unsigned char, CPubKey::COMPRESSED_SIZE> vch;
153 : : s >> std::span{vch};
154 : : return FromBytes(std::span{vch});
155 : : }
156 : :
157 : : const secp256k1_silentpayments_label* Get() const LIFETIMEBOUND;
158 : : };
159 : :
160 : 0 : struct SilentPaymentsOutput {
161 : : XOnlyPubKey output;
162 : : uint256 tweak;
163 : : std::optional<SilentPaymentsLabel> label;
164 : : };
165 : :
166 : : /**
167 : : * @brief Get the public key from an input.
168 : : *
169 : : * Get the public key from a silent payments eligible input. This requires knowledge of the prevout
170 : : * scriptPubKey to determine the type of input and whether or not it is eligible for silent payments.
171 : : *
172 : : * If the input is not eligible for silent payments, the input is skipped (indicated by returning a nullopt).
173 : : *
174 : : * @param txin The transaction input.
175 : : * @param spk The scriptPubKey of the prevout.
176 : : * @return The public key, or nullopt if not found.
177 : : */
178 : : std::optional<PubKey> GetPubKeyFromInput(const CTxIn& txin, const CScript& spk);
179 : :
180 : : /**
181 : : * @brief Generate silent payments taproot destinations.
182 : : *
183 : : * Given a set of silent payments destinations, generate the requested number of outputs. If a silent payment
184 : : * destination is repeated, this indicates multiple outputs are requested for the same recipient. The silent payment
185 : : * destinations are passed in a map where the key indicates their desired position in the final tx.vout array.
186 : : *
187 : : * @param sp_dests The silent payments destinations.
188 : : * @param plain_keys The private keys for non-taproot inputs.
189 : : * @param taproot_keys The keypairs for taproot inputs.
190 : : * @param smallest_outpoint The smallest_outpoint from the transaction inputs.
191 : : * @pre smallest_outpoint is not null, and at least one of plain_keys or taproot_keys is non-empty.
192 : : * @return The generated silent payments taproot destinations or std::nullopt if the set of provided inputs is invalid:
193 : : * - The size of any group (i.e. recipients sharing the same scan public key)
194 : : * exceeds the protocol limit SECP256K1_SILENTPAYMENTS_RECIPIENT_GROUP_LIMIT.
195 : : * - There is an invalid key in the set.
196 : : * - The inputs sum to zero.
197 : : */
198 : : 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);
199 : :
200 : : enum class PrevoutsSummaryError {
201 : : //! A prevout referenced by an input in `vin` has no corresponding entry in `coins`.
202 : : MISSING_COIN,
203 : : //! This transaction is not eligible to be scanned for silent payments outputs: either none
204 : : //! of its inputs yielded a public key eligible for silent payments (e.g. an input spends an
205 : : //! unknown segwit version), or the eligible inputs' public keys summed to the point at infinity.
206 : : NOT_ELIGIBLE,
207 : : };
208 : :
209 : : /**
210 : : * @brief Get silent payments public data from transaction inputs.
211 : : *
212 : : * Get the necessary data from the transaction inputs to be able to scan the transaction outputs for silent payments outputs.
213 : : * This requires knowledge of the prevout scriptPubKey, which is passed via `coins`.
214 : : *
215 : : * This function returns the public key sum and the input hash separately and is intended to be used by the wallet when scanning
216 : : * a transaction.
217 : : *
218 : : * If there are no eligible inputs, or one of the inputs spends an unknown segwit version (i.e > 1), this transaction is not
219 : : * eligible to be scanned for silent payments outputs; see PrevoutsSummaryError.
220 : : *
221 : : * @param vin The transaction inputs.
222 : : * @param coins The coins (potentially) spent in this transaction.
223 : : * @return util::Expected<PrevoutsSummary, PrevoutsSummaryError> The silent payments public data, or the reason it could not be computed.
224 : : */
225 : : util::Expected<PrevoutsSummary, PrevoutsSummaryError> GetSilentPaymentsPrevoutsSummary(const std::vector<CTxIn>& vin, const std::map<COutPoint, Coin>& coins);
226 : :
227 : : using LabelTweakMap = std::map<SilentPaymentsLabel, uint256, std::less<>>;
228 : :
229 : : /**
230 : : * @brief A silent payments recipient's scanning identity.
231 : : *
232 : : * Bundles a recipient's scan key, spend public key, and known labels (always including the change
233 : : * label) into a single self-contained object capable of scanning transactions and deriving the
234 : : * recipient's change destination.
235 : : *
236 : : * The change label is created automatically on construction if one is not supplied through
237 : : * the labels map; additional labels are registered on creation with GenerateLabeledAddress().
238 : : */
239 : : class SilentPaymentsReceiver {
240 : : private:
241 : : CKey m_scan_key;
242 : : CPubKey m_spend_pubkey;
243 : : std::unique_ptr<secp256k1_pubkey> m_spend_pubkey_obj;
244 : : LabelTweakMap m_labels;
245 : : LabelTweakMap::const_iterator m_change_it;
246 : :
247 : : SilentPaymentsDestination BuildLabeledDestination(const SilentPaymentsLabel& label) const;
248 : :
249 : : public:
250 : : SilentPaymentsReceiver(const CKey& scan_key, const CPubKey& spend_pubkey, const LabelTweakMap& labels = {});
251 : : ~SilentPaymentsReceiver();
252 : :
253 : : // Default move would leave m_scan_key and m_labels empty while
254 : : // m_spend_pubkey remains fully populated, leaving the
255 : : // SilentPaymentsReceiver object in an inconsistent state.
256 : : SilentPaymentsReceiver(SilentPaymentsReceiver&&) = delete;
257 : : SilentPaymentsReceiver& operator=(SilentPaymentsReceiver&&) = delete;
258 : :
259 : : SilentPaymentsReceiver(const SilentPaymentsReceiver&) = delete;
260 : : SilentPaymentsReceiver& operator=(const SilentPaymentsReceiver&) = delete;
261 : :
262 : : /**
263 : : * @brief Get this recipient's registered labels, including the change label.
264 : : *
265 : : * @return const LabelTweakMap& Each label mapped to its scalar tweak.
266 : : */
267 : : const LabelTweakMap& GetLabels() const;
268 : :
269 : : /**
270 : : * @brief Register label `m` (e.g. for a labeled sub-address to hand out to a payer) and generate
271 : : * the resulting address.
272 : : *
273 : : * Derives the label from this recipient's own scan key and `m`, registers it so Scan() can
274 : : * recognize outputs sent to it, and returns the address to hand out.
275 : : *
276 : : * @param m An integer m, greater than 0 (m = 0 is reserved for the change label).
277 : : * @return SilentPaymentsDestination The labeled destination, with `B_spend -> B_spend + label`.
278 : : */
279 : : SilentPaymentsDestination GenerateLabeledAddress(uint32_t m);
280 : :
281 : : /**
282 : : * @brief Get this recipient's silent payments change destination.
283 : : *
284 : : * @return SilentPaymentsDestination The destination to use for this recipient's own change outputs,
285 : : * i.e. `B_spend -> B_spend + change_label`.
286 : : */
287 : : SilentPaymentsDestination GetChangeDestination() const;
288 : :
289 : : /**
290 : : * @brief Scan a transaction for silent payments outputs.
291 : : *
292 : : * Scan the transaction for silent payments outputs intended for this recipient. The output, shared
293 : : * secret tweak, and (optionally) label public key is returned for each output found. If the output
294 : : * was sent to a labeled address, the label tweak is added to the shared secret tweak. The shared
295 : : * secret tweak is needed to spend the output, by adding it to the spend secret key. If no outputs
296 : : * are found, this transaction does not contain silent payments outputs for this recipient.
297 : : *
298 : : * @param prevouts_summary The silent payments public data.
299 : : * @param tx_outputs The taproot output public keys.
300 : : * @return The found outputs or std::nullopt in the case of an error.
301 : : */
302 : : std::optional<std::vector<SilentPaymentsOutput>> Scan(const PrevoutsSummary& prevouts_summary, const std::vector<XOnlyPubKey>& tx_outputs) const;
303 : : };
304 : : }; // namespace bip352
305 : : #endif // BITCOIN_COMMON_BIP352_H
|