-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add BIP352 silentpayments
module
#1519
base: master
Are you sure you want to change the base?
Changes from 2 commits
1c74941
9d6769f
7229d49
94c6e1f
5c546e2
566b5b8
5ce0db1
5b9714f
f42e0dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -188,6 +188,10 @@ AC_ARG_ENABLE(module_ellswift, | |
AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [], | ||
[SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])]) | ||
|
||
AC_ARG_ENABLE(module_silentpayments, | ||
AS_HELP_STRING([--enable-module-silentpayments],[enable Silent Payments module [default=no]]), [], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1c74941: can we just break the convention and make it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haha no :) |
||
[SECP_SET_DEFAULT([enable_module_silentpayments], [no], [yes])]) | ||
|
||
AC_ARG_ENABLE(external_default_callbacks, | ||
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [], | ||
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])]) | ||
|
@@ -394,6 +398,10 @@ SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS" | |
|
||
# Processing must be done in a reverse topological sorting of the dependency graph | ||
# (dependent module first). | ||
if test x"$enable_module_silentpayments" = x"yes"; then | ||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SILENTPAYMENTS=1" | ||
fi | ||
|
||
if test x"$enable_module_ellswift" = x"yes"; then | ||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1" | ||
fi | ||
|
@@ -450,6 +458,7 @@ AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"ye | |
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"]) | ||
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) | ||
AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"]) | ||
AM_CONDITIONAL([ENABLE_MODULE_SILENTPAYMENTS], [test x"$enable_module_silentpayments" = x"yes"]) | ||
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"]) | ||
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"]) | ||
AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"]) | ||
|
@@ -472,6 +481,7 @@ echo " module recovery = $enable_module_recovery" | |
echo " module extrakeys = $enable_module_extrakeys" | ||
echo " module schnorrsig = $enable_module_schnorrsig" | ||
echo " module ellswift = $enable_module_ellswift" | ||
echo " module silentpayments = $enable_module_silentpayments" | ||
echo | ||
echo " asm = $set_asm" | ||
echo " ecmult window size = $set_ecmult_window" | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,114 @@ | ||||||||||||||||||||||
#ifndef SECP256K1_SILENTPAYMENTS_H | ||||||||||||||||||||||
#define SECP256K1_SILENTPAYMENTS_H | ||||||||||||||||||||||
|
||||||||||||||||||||||
#include "secp256k1.h" | ||||||||||||||||||||||
#include "secp256k1_extrakeys.h" | ||||||||||||||||||||||
|
||||||||||||||||||||||
#ifdef __cplusplus | ||||||||||||||||||||||
extern "C" { | ||||||||||||||||||||||
#endif | ||||||||||||||||||||||
|
||||||||||||||||||||||
/* This module provides an implementation for Silent Payments, as specified in | ||||||||||||||||||||||
* BIP352. This particularly involves the creation of input tweak data by | ||||||||||||||||||||||
* summing up private or public keys and the derivation of a shared secret using | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/private/secret key for consistency with the rest of the lib |
||||||||||||||||||||||
* Elliptic Curve Diffie-Hellman. Combined are either: | ||||||||||||||||||||||
* - spender's private keys and recipient's public key (a * B, sender side) | ||||||||||||||||||||||
* - spender's public keys and recipient's private key (A * b, recipient side) | ||||||||||||||||||||||
* With this result, the necessary key material for ultimately creating/scanning | ||||||||||||||||||||||
* or spending Silent Payment outputs can be determined. | ||||||||||||||||||||||
* | ||||||||||||||||||||||
* Note that this module is _not_ a full implementation of BIP352, as it | ||||||||||||||||||||||
* inherently doesn't deal with higher-level concepts like addresses, output | ||||||||||||||||||||||
* script types or transactions. The intent is to provide a module for | ||||||||||||||||||||||
* abstracting away the elliptic-curve operations required for the protocol. For | ||||||||||||||||||||||
* any wallet software already using libsecp256k1, this API should provide all | ||||||||||||||||||||||
* the functions needed for a Silent Payments implementation without requiring | ||||||||||||||||||||||
* any further elliptic-curve operations from the wallet. | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
|
||||||||||||||||||||||
/* This struct serves as an In param for passing the silent payment address | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
would be more consistent with secp256k1.h |
||||||||||||||||||||||
* data. The index field is for when more than one address is being sent to in | ||||||||||||||||||||||
* a transaction. Index is set based on the original ordering of the addresses | ||||||||||||||||||||||
* and used to return the generated outputs matching the original ordering. | ||||||||||||||||||||||
* When more than one recipient is used the recipient array will be sorted in | ||||||||||||||||||||||
* place as part of generating the outputs, but the generated outputs will be | ||||||||||||||||||||||
* returned in the original ordering specified by the index to ensure the | ||||||||||||||||||||||
* caller is able to match up the generated outputs to the correct silent | ||||||||||||||||||||||
* payment address (e.g. to be able to assign the correct amounts to the | ||||||||||||||||||||||
Comment on lines
+33
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||
* correct generated outputs in the final transaction). | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
typedef struct { | ||||||||||||||||||||||
secp256k1_pubkey scan_pubkey; | ||||||||||||||||||||||
secp256k1_pubkey spend_pubkey; | ||||||||||||||||||||||
size_t index; | ||||||||||||||||||||||
} secp256k1_silentpayments_recipient; | ||||||||||||||||||||||
|
||||||||||||||||||||||
/** Create Silent Payment outputs for recipient(s). | ||||||||||||||||||||||
* | ||||||||||||||||||||||
* Given a list of n private keys a_1...a_n (one for each silent payment | ||||||||||||||||||||||
* eligible input to spend), a serialized outpoint, and a list of recipients, | ||||||||||||||||||||||
* create the taproot outputs. | ||||||||||||||||||||||
* | ||||||||||||||||||||||
* `outpoint_smallest36` refers to the smallest outpoint lexicographically | ||||||||||||||||||||||
* from the transaction inputs (both silent payments eligible and non-eligible | ||||||||||||||||||||||
* inputs). This value MUST be the smallest outpoint out of all of the | ||||||||||||||||||||||
* transaction inputs, otherwise the recipient will be unable to find the | ||||||||||||||||||||||
* payment. | ||||||||||||||||||||||
* | ||||||||||||||||||||||
* If necessary, the private keys are negated to enforce the right y-parity. | ||||||||||||||||||||||
* For that reason, the private keys have to be passed in via two different | ||||||||||||||||||||||
* parameter pairs, depending on whether the seckeys correspond to x-only | ||||||||||||||||||||||
* outputs or not. | ||||||||||||||||||||||
* | ||||||||||||||||||||||
* Returns: 1 if creation of outputs was successful. 0 if an error occured. | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 9d6769f: typo nit: s/occured/occurred here and in few more places in the file |
||||||||||||||||||||||
* Args: ctx: pointer to a context object | ||||||||||||||||||||||
* Out: generated_outputs: pointer to an array of pointers to xonly pubkeys, | ||||||||||||||||||||||
* one per recipient. | ||||||||||||||||||||||
* The order of outputs here matches the original | ||||||||||||||||||||||
* ordering of the recipients array. | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 9d6769f: the words "matches the original ordering" had me thoroughly confused, because I thought it referred to the array order. Try instead:
|
||||||||||||||||||||||
* In: recipients: pointer to an array of pointers to silent payment | ||||||||||||||||||||||
* recipients, where each recipient is a scan public | ||||||||||||||||||||||
* key, a spend public key, and an index indicating | ||||||||||||||||||||||
* its position in the original ordering. The | ||||||||||||||||||||||
* recipient array will be sorted in place, but | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 9d6769f: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is an implementation detail the caller does not need to be aware of, since we handle the grouping internally. From a callers perspective, all they need to do is pass an array of recipients, in any order. |
||||||||||||||||||||||
* generated outputs are saved in the | ||||||||||||||||||||||
* `generated_outputs` array to match the ordering | ||||||||||||||||||||||
* from the index field. This ensures the caller is | ||||||||||||||||||||||
* able to match the generated outputs to the | ||||||||||||||||||||||
* correct silent payment addresses. The same | ||||||||||||||||||||||
* recipient can be passed multiple times to create | ||||||||||||||||||||||
* multiple outputs for the same recipient. | ||||||||||||||||||||||
* n_recipients: the number of recipients. This is equal to the | ||||||||||||||||||||||
* total number of outputs to be generated as each | ||||||||||||||||||||||
* recipient may passed multiple times to generate | ||||||||||||||||||||||
* multiple outputs for the same recipient | ||||||||||||||||||||||
* outpoint_smallest36: serialized smallest outpoint (lexicographically) | ||||||||||||||||||||||
* from the transaction inputs | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 9d6769f: the Suggest adding to the doc (instead): Given how many times this has gone wrong, the following warning seems justified:
The test vector in this PR doesn't prevent this, because sorting is left to the implementer. Test vectors in the BIP don't necessary prevent this either, because implementers will assume it's all covered in libsecp. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a separate discussion on the Musig2 PR that I need to follow up on regarding this, where there might be a more clever way to enforce the array length without these suffix hints. For now, I think I will remove the 36 and add it to the docs, as you suggest. Agree that we can't enforce they are passing the correct outpoint out of a list of outpoints here, but I do think we can make it clear in the header file that this is not handled by libsecp and implementations MUST ensure they are following the test vectors from the BIP. I'll add something as such to the header documentation. |
||||||||||||||||||||||
* taproot_seckeys: pointer to an array of pointers to 32-byte | ||||||||||||||||||||||
* private keys of taproot inputs (can be NULL if no | ||||||||||||||||||||||
* private keys of taproot inputs are used) | ||||||||||||||||||||||
* n_taproot_seckeys: the number of sender's taproot input private keys | ||||||||||||||||||||||
* plain_seckeys: pointer to an array of pointers to 32-byte | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 9d6769f: why can't this be The PR description implies the logic is the other way around:
So you want to save the caller from having to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch, this is outdated documentation. The function does expect taproot_seckeys to be secp256k1_keypairs. |
||||||||||||||||||||||
* private keys of non-taproot inputs (can be NULL | ||||||||||||||||||||||
* if no private keys of non-taproot inputs are | ||||||||||||||||||||||
* used) | ||||||||||||||||||||||
* n_plain_seckeys: the number of sender's non-taproot input private | ||||||||||||||||||||||
* keys | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
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, | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any reason not to make the outer pointer constant since it is not modified in this function?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The recipients array is passed to |
||||||||||||||||||||||
size_t n_recipients, | ||||||||||||||||||||||
const unsigned char *outpoint_smallest36, | ||||||||||||||||||||||
const secp256k1_keypair * const *taproot_seckeys, | ||||||||||||||||||||||
size_t n_taproot_seckeys, | ||||||||||||||||||||||
const unsigned char * const *plain_seckeys, | ||||||||||||||||||||||
size_t n_plain_seckeys | ||||||||||||||||||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); | ||||||||||||||||||||||
|
||||||||||||||||||||||
#ifdef __cplusplus | ||||||||||||||||||||||
} | ||||||||||||||||||||||
#endif | ||||||||||||||||||||||
|
||||||||||||||||||||||
#endif /* SECP256K1_SILENTPAYMENTS_H */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
include_HEADERS += include/secp256k1_silentpayments.h | ||
noinst_HEADERS += src/modules/silentpayments/main_impl.h |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1c74941: since the next commit adds a dependency on extrakeys, and silent payments obviously depends on schnorr:
extrakeys
already checks forschnorr
, but I added it an explicit check forschnorr
because otherwise the error is confusing.Try with:
./configure --enable-module-silentpayments --disable-module-extrakeys
cmake .. -DSECP256K1_ENABLE_MODULE_SILENTPAYMENTS=ON -DSECP256K1_ENABLE_MODULE_SCHNORRSIG=OFF