Skip to content

Commit

Permalink
Update src/secp256k1 subtree to version with Silent Payments support
Browse files Browse the repository at this point in the history
This commit contains the secp256k1 draft PR bitcoin#1471
(bitcoin-core/secp256k1#1471) applied on tag
v0.4.0 and squashed, without the BIP352 test running suite in Python.
  • Loading branch information
theStack committed Dec 26, 2023
1 parent 4b1196a commit 5f73bf3
Show file tree
Hide file tree
Showing 9 changed files with 606 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/secp256k1/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
endif()

option(SECP256K1_ENABLE_MODULE_SILENTPAYMENTS "Enable Silent Payments module." OFF)
if(SECP256K1_ENABLE_MODULE_SILENTPAYMENTS)
add_compile_definitions(ENABLE_MODULE_SILENTPAYMENTS=1)
endif()

option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF)
if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS)
add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1)
Expand Down Expand Up @@ -276,6 +281,7 @@ message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOV
message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}")
message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}")
message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}")
message(" Silent Payments ..................... ${SECP256K1_ENABLE_MODULE_SILENTPAYMENTS}")
message("Parameters:")
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}")
Expand Down
4 changes: 4 additions & 0 deletions src/secp256k1/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,7 @@ endif
if ENABLE_MODULE_ELLSWIFT
include src/modules/ellswift/Makefile.am.include
endif

if ENABLE_MODULE_SILENTPAYMENTS
include src/modules/silentpayments/Makefile.am.include
endif
10 changes: 10 additions & 0 deletions src/secp256k1/configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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]]), [],
[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])])
Expand Down Expand Up @@ -404,6 +408,10 @@ if test x"$enable_module_ellswift" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1"
fi

if test x"$enable_module_silentpayments" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SILENTPAYMENTS=1"
fi

# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
# module to set enable_module_extrakeys=yes
if test x"$enable_module_extrakeys" = x"yes"; then
Expand Down Expand Up @@ -447,6 +455,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"])
Expand All @@ -469,6 +478,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"
Expand Down
204 changes: 204 additions & 0 deletions src/secp256k1/include/secp256k1_silentpayments.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
#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 the ECC related parts of
* 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 Elliptic Curve Diffie-Hellman.
* Combined are either:
* - spender's private keys and receiver's public key (a * B, sender side)
* - spender's public keys and receiver's private key (A * b, receiver 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 cryptographical
* helpers for low-level calculations that are most error-prone to custom
* implementations (e.g. enforcing the right y-parity for key material, ECDH
* calculation etc.). For any wallet software already using libsecp256k1, this
* API should provide all the functions needed for a Silent Payments
* implementation without the need for any further manual elliptic-curve
* operations.
*/

/** Create Silent Payment tweak data from input private keys.
*
* Given a list of n private keys a_0...a_(n-1) (one for each input to spend)
* and an outpoints_hash, compute the corresponding input private keys tweak data:
*
* a_tweaked = (a_0 + a_1 + ... a_(n-1)) * outpoints_hash
*
* 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 they were used for creating taproot outputs or not.
* The resulting data is needed to create a shared secret for the sender side.
*
* Returns: 1 if shared secret creation was successful. 0 if an error occured.
* Args: ctx: pointer to a context object
* Out: tweak_data32: pointer to the resulting 32-byte tweak data
* In: plain_seckeys: pointer to an array of 32-byte 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
* taproot_seckeys: pointer to an array of 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
* outpoints_hash32: hash of the sorted serialized outpoints
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_create_private_tweak_data(
const secp256k1_context *ctx,
unsigned char *tweak_data32,
const unsigned char *plain_seckeys,
size_t n_plain_seckeys,
const unsigned char *taproot_seckeys,
size_t n_taproot_seckeys,
const unsigned char *outpoints_hash32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(7);

/** Create Silent Payment shared secret for the sender side.
*
* Given private input tweak data a_tweaked a recipient's scan public key B_scan,
* compute the corresponding shared secret using ECDH:
*
* shared_secret = a_tweaked * B_scan
* (where a_tweaked = (a_0 + a_1 + ... a_(n-1)) * outpoints_hash)
*
* The resulting data is needed as input for creating silent payments outputs
* belonging to the same receiver scan public key.
*
* Returns: 1 if shared secret creation was successful. 0 if an error occured.
* Args: ctx: pointer to a context object
* Out: shared_secret33: pointer to the resulting 33-byte shared secret
* In: tweak_data32: pointer to 32-byte private input tweak data
* receiver_scan_pubkey: pointer to the receiver's scan pubkey
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_send_create_shared_secret(
const secp256k1_context *ctx,
unsigned char *shared_secret33,
const unsigned char *tweak_data32,
const secp256k1_pubkey *receiver_scan_pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);

/** Create Silent Payment tweak data from input public keys.
*
* Given a list of n public keys A_0...A_(n-1) (one for each input to spend)
* and an outpoints_hash, compute the corresponding input public keys tweak data:
*
* A_tweaked = (A_0 + A_1 + ... A_(n-1)) * outpoints_hash
*
* If necessary, the public keys are negated to enforce the right y-parity.
* For that reason, the public keys have to be passed in via two different parameter
* pairs, depending on whether they were used for creating taproot outputs or not.
* The resulting data is needed to create a shared secret for the receiver's side.
*
* Returns: 1 if tweak data creation was successful. 0 if an error occured.
* Args: ctx: pointer to a context object
* Out: tweak_data33: pointer to the resulting 33-byte tweak data
* In: plain_pubkeys: pointer to an array of non-taproot public keys
* (can be NULL if no non-taproot inputs are used)
* n_plain_pubkeys: the number of non-taproot input public keys
* xonly_pubkeys: pointer to an array of taproot x-only public keys
* (can be NULL if no taproot input public keys are used)
* n_xonly_pubkeys: the number of taproot input public keys
* outpoints_hash32: hash of the sorted serialized outpoints
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_create_public_tweak_data(
const secp256k1_context *ctx,
unsigned char *tweak_data33,
const secp256k1_pubkey *plain_pubkeys,
size_t n_plain_pubkeys,
const secp256k1_xonly_pubkey *xonly_pubkeys,
size_t n_xonly_pubkeys,
const unsigned char *outpoints_hash32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(7);

/** Create Silent Payment shared secret for the receiver side.
*
* Given public input tweak data A_tweaked and a recipient's scan private key
* b_scan, compute the corresponding shared secret using ECDH:
*
* shared_secret = A_tweaked * b_scan
* (where A_tweaked = (A_0 + A_1 + ... A_(n-1)) * outpoints_hash)
*
* The resulting data is needed as input for creating silent payments outputs
* belonging to the same receiver scan public key.
*
* Returns: 1 if shared secret creation was successful. 0 if an error occured.
* Args: ctx: pointer to a context object
* Out: shared_secret33: pointer to the resulting 33-byte shared secret
* In: tweak_data33: pointer to 33-byte public input tweak data
* receiver_scan_seckey: pointer to the receiver's scan private key
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_receive_create_shared_secret(
const secp256k1_context *ctx,
unsigned char *shared_secret33,
const unsigned char *tweak_data33,
const unsigned char *receiver_scan_seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);

/** Create Silent Payment output public key (both for sender and receiver).
*
* Given a shared_secret, a recipient's spend public key B_spend, and an
* output counter k, calculate the corresponding output public key:
*
* P_output = B_spend + sha256(shared_secret || ser_32(k)) * G
*
* Returns: 1 if outputs creation was successful. 0 if an error occured.
* Args: ctx: pointer to a context object
* Out: output_xonly_pubkey: pointer to the resulting output x-only pubkey
* In: shared_secret33: shared secret, derived from either sender's
* or receiver's perspective with routines from above
* receiver_spend_pubkey: pointer to the receiver's spend pubkey
* k: output counter (usually set to 0, should be increased for
* every additional output to the same recipient)
* label_tweak32: an optional 32-byte label tweak
* (not supported yet, must be set to NULL right now)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_create_output_pubkey(
const secp256k1_context *ctx,
secp256k1_xonly_pubkey *output_xonly_pubkey,
const unsigned char *shared_secret33,
const secp256k1_pubkey *receiver_spend_pubkey,
unsigned int k,
const unsigned char *label_tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);

/** Create Silent Payment output private key (for spending receiver's funds).
*
* Given a shared_secret, a recipient's spend private key b_spend, and an
* output counter k, calculate the corresponding output private key d:
*
* d = (b_spend + sha256(shared_secret || ser_32(k))) mod n
*
* Returns: 1 if private key creation was successful. 0 if an error occured.
* Args: ctx: pointer to a context object
* Out: output_seckey: pointer to the resulting spending private key
* In: shared_secret33: shared secret, derived from either sender's
* or receiver's perspective with routines from above
* receiver_spend_seckey: pointer to the receiver's spend private key
* k: output counter (usually set to 0, should be increased for
* every additional output to the same recipient)
* label_tweak32: an optional 32-byte label tweak
* (not supported yet, must be set to NULL right now)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_create_output_seckey(
const secp256k1_context *ctx,
unsigned char *output_seckey,
const unsigned char *shared_secret33,
const unsigned char *receiver_spend_seckey,
unsigned int k,
const unsigned char *label_tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);

#ifdef __cplusplus
}
#endif

#endif /* SECP256K1_SILENTPAYMENTS_H */
2 changes: 2 additions & 0 deletions src/secp256k1/src/modules/silentpayments/Makefile.am.include
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
Loading

0 comments on commit 5f73bf3

Please sign in to comment.