Skip to content

Commit 4c38baf

Browse files
josibaketheStack
authored andcommitted
silentpayments: receiving
Add routine for scanning a transaction and returning the necessary spending data for any found outputs. This function works with labels via a lookup callback and requires access to the transaction outputs. Requiring access to the transaction outputs is not suitable for light clients, but light client support is enabled in the next commit. Add an opaque data type for passing around the prevout public key sum and the input hash tweak (input_hash). This data is passed to the scanner before the ECDH step as two separate elements so that the scanner can multiply the scan_key * input_hash before doing ECDH. Finally, add test coverage for the receiving API.
1 parent df0a1fe commit 4c38baf

File tree

3 files changed

+572
-1
lines changed

3 files changed

+572
-1
lines changed

include/secp256k1_silentpayments.h

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef SECP256K1_SILENTPAYMENTS_H
22
#define SECP256K1_SILENTPAYMENTS_H
33

4+
#include <stdint.h>
45
#include "secp256k1.h"
56
#include "secp256k1_extrakeys.h"
67

@@ -26,7 +27,6 @@ extern "C" {
2627
* any further elliptic-curve operations from the wallet.
2728
*/
2829

29-
3030
/** The data from a single recipient address
3131
*
3232
* This struct serves as an input argument to `silentpayments_sender_create_outputs`.
@@ -180,6 +180,157 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipien
180180
const secp256k1_pubkey *label
181181
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
182182

183+
/** Opaque data structure that holds silent payments prevout summary data.
184+
*
185+
* This structure does not contain secret data. Guaranteed to be 101 bytes in
186+
* size. It can be safely copied/moved. Created with
187+
* `secp256k1_silentpayments_recipient_prevouts_summary_create`.
188+
*/
189+
typedef struct secp256k1_silentpayments_prevouts_summary {
190+
unsigned char data[101];
191+
} secp256k1_silentpayments_prevouts_summary;
192+
193+
/** Compute Silent Payment prevout summary from prevout public keys and transaction
194+
* inputs.
195+
*
196+
* Given a list of n public keys A_1...A_n (one for each silent payment
197+
* eligible input to spend) and a serialized outpoint_smallest36, create a
198+
* `prevouts_summary` object. This object summarizes the prevout data from the
199+
* transaction inputs needed for scanning.
200+
*
201+
* `outpoint_smallest36` refers to the smallest outpoint lexicographically
202+
* from the transaction inputs (both silent payments eligible and non-eligible
203+
* inputs). This value MUST be the smallest outpoint out of all of the
204+
* transaction inputs, otherwise the recipient will be unable to find the
205+
* payment.
206+
*
207+
* The public keys have to be passed in via two different parameter pairs, one
208+
* for regular and one for x-only public keys, in order to avoid the need of
209+
* users converting to a common public key format before calling this function.
210+
* The resulting data can be used for scanning on the recipient side.
211+
*
212+
* Returns: 1 if prevout summary creation was successful.
213+
* 0 if the transaction is not a silent payments transaction.
214+
*
215+
* Args: ctx: pointer to a context object
216+
* Out: prevouts_summary: pointer to prevouts_summary object containing the
217+
* summed public key and input_hash.
218+
* In: outpoint_smallest36: serialized smallest outpoint (lexicographically)
219+
* from the transaction inputs
220+
* xonly_pubkeys: pointer to an array of pointers to taproot
221+
* x-only public keys (can be NULL if no taproot
222+
* inputs are used)
223+
* n_xonly_pubkeys: the size of the xonly_pubkeys array.
224+
* plain_pubkeys: pointer to an array of pointers to non-taproot
225+
* public keys (can be NULL if no non-taproot
226+
* inputs are used)
227+
* n_plain_pubkeys: the size of the plain_pubkeys array.
228+
*/
229+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_prevouts_summary_create(
230+
const secp256k1_context *ctx,
231+
secp256k1_silentpayments_prevouts_summary *prevouts_summary,
232+
const unsigned char *outpoint_smallest36,
233+
const secp256k1_xonly_pubkey * const *xonly_pubkeys,
234+
size_t n_xonly_pubkeys,
235+
const secp256k1_pubkey * const *plain_pubkeys,
236+
size_t n_plain_pubkeys
237+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
238+
239+
/** Callback function for label lookups
240+
*
241+
* This function is implemented by the recipient to check if a value exists in
242+
* the recipients label cache during scanning.
243+
*
244+
* For creating the labels cache data,
245+
* `secp256k1_silentpayments_recipient_create_label` can be used.
246+
*
247+
* Returns: pointer to the 32-byte label tweak if there is a match.
248+
* NULL pointer if there is no match.
249+
*
250+
* In: label: pointer to the label public key to check (computed during
251+
* scanning)
252+
* label_context: pointer to the recipients label cache.
253+
*/
254+
typedef const unsigned char* (*secp256k1_silentpayments_label_lookup)(const unsigned char* label33, const void* label_context);
255+
256+
/** Found outputs struct
257+
*
258+
* Struct for holding a found output along with data needed to spend it later.
259+
*
260+
* output: the x-only public key for the taproot output
261+
* tweak: the 32-byte tweak needed to spend the output
262+
* found_with_label: boolean value to indicate if the output was sent to a
263+
* labeled address. If true, label will be set with a valid
264+
* public key.
265+
* label: public key representing the label used.
266+
* If found_with_label = false, this is set to an invalid
267+
* public key.
268+
*/
269+
typedef struct secp256k1_silentpayments_found_output {
270+
secp256k1_xonly_pubkey output;
271+
unsigned char tweak[32];
272+
int found_with_label;
273+
secp256k1_pubkey label;
274+
} secp256k1_silentpayments_found_output;
275+
276+
/** Scan for Silent Payment transaction outputs.
277+
*
278+
* Given a prevouts_summary object, a recipient's 32 byte scan key and spend public key,
279+
* and the relevant transaction outputs, scan for outputs belonging to
280+
* the recipient and return the tweak(s) needed for spending the output(s). An
281+
* optional label_lookup callback function and label_context can be passed if
282+
* the recipient uses labels. This allows for checking if a label exists in
283+
* the recipients label cache and retrieving the label tweak during scanning.
284+
*
285+
* If used, the `label_lookup` function must return a pointer to a 32-byte label
286+
* tweak if the label is found, or NULL otherwise. The returned pointer must remain
287+
* valid until the next call to `label_lookup` or until the function returns,
288+
* whichever comes first. It is not retained beyond that.
289+
*
290+
* For creating the labels cache, `secp256k1_silentpayments_recipient_create_label`
291+
* can be used.
292+
*
293+
* Returns: 1 if output scanning was successful.
294+
* 0 if the transaction is not a silent payments transaction,
295+
* or if the arguments are invalid.
296+
*
297+
* Args: ctx: pointer to a context object
298+
* Out: found_outputs: pointer to an array of pointers to found
299+
* output objects. The found outputs array MUST
300+
* have the same length as the tx_outputs array.
301+
* n_found_outputs: pointer to an integer indicating the final
302+
* size of the found outputs array. This number
303+
* represents the number of outputs found while
304+
* scanning (0 if none are found).
305+
* In: tx_outputs: pointer to the transaction's x-only public key outputs
306+
* n_tx_outputs: the size of the tx_outputs array.
307+
* scan_key32: pointer to the recipient's 32 byte scan key. The scan
308+
* key is valid if it passes secp256k1_ec_seckey_verify
309+
* prevouts_summary: pointer to the transaction prevouts summary data
310+
* (see `_recipient_prevouts_summary_create`).
311+
* unlabeled_spend_pubkey: pointer to the recipient's unlabeled spend public key
312+
* label_lookup: pointer to a callback function for looking up
313+
* a label value. This function takes a label
314+
* public key as an argument and returns a pointer to
315+
* the label tweak if the label exists, otherwise
316+
* returns a NULL pointer (NULL if labels are not
317+
* used)
318+
* label_context: pointer to a label context object (NULL if
319+
* labels are not used or context is not needed)
320+
*/
321+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_scan_outputs(
322+
const secp256k1_context *ctx,
323+
secp256k1_silentpayments_found_output **found_outputs,
324+
size_t *n_found_outputs,
325+
const secp256k1_xonly_pubkey * const *tx_outputs,
326+
size_t n_tx_outputs,
327+
const unsigned char *scan_key32,
328+
const secp256k1_silentpayments_prevouts_summary *prevouts_summary,
329+
const secp256k1_pubkey *unlabeled_spend_pubkey,
330+
const secp256k1_silentpayments_label_lookup label_lookup,
331+
const void *label_context
332+
) 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);
333+
183334
#ifdef __cplusplus
184335
}
185336
#endif

0 commit comments

Comments
 (0)