mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 18:45:52 +00:00
Update secp256k1 library to 0.6.0 (#5254)
This commit is contained in:
44
external/secp256k1/examples/CMakeLists.txt
vendored
44
external/secp256k1/examples/CMakeLists.txt
vendored
@@ -1,27 +1,31 @@
|
||||
add_library(example INTERFACE)
|
||||
target_include_directories(example INTERFACE
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
)
|
||||
target_link_libraries(example INTERFACE
|
||||
secp256k1
|
||||
$<$<PLATFORM_ID:Windows>:bcrypt>
|
||||
)
|
||||
if(NOT BUILD_SHARED_LIBS AND MSVC)
|
||||
target_link_options(example INTERFACE /IGNORE:4217)
|
||||
endif()
|
||||
function(add_example name)
|
||||
set(target_name ${name}_example)
|
||||
add_executable(${target_name} ${name}.c)
|
||||
target_include_directories(${target_name} PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
)
|
||||
target_link_libraries(${target_name}
|
||||
secp256k1
|
||||
$<$<PLATFORM_ID:Windows>:bcrypt>
|
||||
)
|
||||
set(test_name ${name}_example)
|
||||
add_test(NAME secp256k1_${test_name} COMMAND ${target_name})
|
||||
endfunction()
|
||||
|
||||
add_executable(ecdsa_example ecdsa.c)
|
||||
target_link_libraries(ecdsa_example example)
|
||||
add_test(NAME ecdsa_example COMMAND ecdsa_example)
|
||||
add_example(ecdsa)
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_ECDH)
|
||||
add_executable(ecdh_example ecdh.c)
|
||||
target_link_libraries(ecdh_example example)
|
||||
add_test(NAME ecdh_example COMMAND ecdh_example)
|
||||
add_example(ecdh)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
add_executable(schnorr_example schnorr.c)
|
||||
target_link_libraries(schnorr_example example)
|
||||
add_test(NAME schnorr_example COMMAND schnorr_example)
|
||||
add_example(schnorr)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
||||
add_example(ellswift)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_MUSIG)
|
||||
add_example(musig)
|
||||
endif()
|
||||
|
||||
24
external/secp256k1/examples/ecdh.c
vendored
24
external/secp256k1/examples/ecdh.c
vendored
@@ -42,18 +42,16 @@ int main(void) {
|
||||
assert(return_val);
|
||||
|
||||
/*** Key Generation ***/
|
||||
|
||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||
* order), we try to sample a new key. Note that the probability of this
|
||||
* happening is negligible. */
|
||||
while (1) {
|
||||
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
||||
break;
|
||||
}
|
||||
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* If the secret key is zero or out of range (greater than secp256k1's
|
||||
* order), we fail. Note that the probability of this occurring is negligible
|
||||
* with a properly functioning random number generator. */
|
||||
if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
||||
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Public key creation using a valid context with a verified secret key should never fail */
|
||||
@@ -108,7 +106,7 @@ int main(void) {
|
||||
|
||||
/* It's best practice to try to clear secrets from memory after using them.
|
||||
* This is done because some bugs can allow an attacker to leak memory, for
|
||||
* example through "out of bounds" array access (see Heartbleed), Or the OS
|
||||
* example through "out of bounds" array access (see Heartbleed), or the OS
|
||||
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
|
||||
*
|
||||
* Here we are preventing these writes from being optimized out, as any good compiler
|
||||
|
||||
24
external/secp256k1/examples/ecdsa.c
vendored
24
external/secp256k1/examples/ecdsa.c
vendored
@@ -49,18 +49,16 @@ int main(void) {
|
||||
assert(return_val);
|
||||
|
||||
/*** Key Generation ***/
|
||||
|
||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||
* order), we try to sample a new key. Note that the probability of this
|
||||
* happening is negligible. */
|
||||
while (1) {
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
if (secp256k1_ec_seckey_verify(ctx, seckey)) {
|
||||
break;
|
||||
}
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* If the secret key is zero or out of range (greater than secp256k1's
|
||||
* order), we fail. Note that the probability of this occurring is negligible
|
||||
* with a properly functioning random number generator. */
|
||||
if (!secp256k1_ec_seckey_verify(ctx, seckey)) {
|
||||
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Public key creation using a valid context with a verified secret key should never fail */
|
||||
@@ -128,7 +126,7 @@ int main(void) {
|
||||
|
||||
/* It's best practice to try to clear secrets from memory after using them.
|
||||
* This is done because some bugs can allow an attacker to leak memory, for
|
||||
* example through "out of bounds" array access (see Heartbleed), Or the OS
|
||||
* example through "out of bounds" array access (see Heartbleed), or the OS
|
||||
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
|
||||
*
|
||||
* Here we are preventing these writes from being optimized out, as any good compiler
|
||||
|
||||
121
external/secp256k1/examples/ellswift.c
vendored
Normal file
121
external/secp256k1/examples/ellswift.c
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
/*************************************************************************
|
||||
* Written in 2024 by Sebastian Falbesoner *
|
||||
* To the extent possible under law, the author(s) have dedicated all *
|
||||
* copyright and related and neighboring rights to the software in this *
|
||||
* file to the public domain worldwide. This software is distributed *
|
||||
* without any warranty. For the CC0 Public Domain Dedication, see *
|
||||
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||
*************************************************************************/
|
||||
|
||||
/** This file demonstrates how to use the ElligatorSwift module to perform
|
||||
* a key exchange according to BIP 324. Additionally, see the documentation
|
||||
* in include/secp256k1_ellswift.h and doc/ellswift.md.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_ellswift.h>
|
||||
|
||||
#include "examples_util.h"
|
||||
|
||||
int main(void) {
|
||||
secp256k1_context* ctx;
|
||||
unsigned char randomize[32];
|
||||
unsigned char auxrand1[32];
|
||||
unsigned char auxrand2[32];
|
||||
unsigned char seckey1[32];
|
||||
unsigned char seckey2[32];
|
||||
unsigned char ellswift_pubkey1[64];
|
||||
unsigned char ellswift_pubkey2[64];
|
||||
unsigned char shared_secret1[32];
|
||||
unsigned char shared_secret2[32];
|
||||
int return_val;
|
||||
|
||||
/* Create a secp256k1 context */
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
if (!fill_random(randomize, sizeof(randomize))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* Randomizing the context is recommended to protect against side-channel
|
||||
* leakage. See `secp256k1_context_randomize` in secp256k1.h for more
|
||||
* information about it. This should never fail. */
|
||||
return_val = secp256k1_context_randomize(ctx, randomize);
|
||||
assert(return_val);
|
||||
|
||||
/*** Generate secret keys ***/
|
||||
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* If the secret key is zero or out of range (greater than secp256k1's
|
||||
* order), we fail. Note that the probability of this occurring is negligible
|
||||
* with a properly functioning random number generator. */
|
||||
if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
||||
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generate ElligatorSwift public keys. This should never fail with valid context and
|
||||
verified secret keys. Note that providing additional randomness (fourth parameter) is
|
||||
optional, but recommended. */
|
||||
if (!fill_random(auxrand1, sizeof(auxrand1)) || !fill_random(auxrand2, sizeof(auxrand2))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey1, seckey1, auxrand1);
|
||||
assert(return_val);
|
||||
return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey2, seckey2, auxrand2);
|
||||
assert(return_val);
|
||||
|
||||
/*** Create the shared secret on each side ***/
|
||||
|
||||
/* Perform x-only ECDH with seckey1 and ellswift_pubkey2. Should never fail
|
||||
* with a verified seckey and valid pubkey. Note that both parties pass both
|
||||
* EllSwift pubkeys in the same order; the pubkey of the calling party is
|
||||
* determined by the "party" boolean (sixth parameter). */
|
||||
return_val = secp256k1_ellswift_xdh(ctx, shared_secret1, ellswift_pubkey1, ellswift_pubkey2,
|
||||
seckey1, 0, secp256k1_ellswift_xdh_hash_function_bip324, NULL);
|
||||
assert(return_val);
|
||||
|
||||
/* Perform x-only ECDH with seckey2 and ellswift_pubkey1. Should never fail
|
||||
* with a verified seckey and valid pubkey. */
|
||||
return_val = secp256k1_ellswift_xdh(ctx, shared_secret2, ellswift_pubkey1, ellswift_pubkey2,
|
||||
seckey2, 1, secp256k1_ellswift_xdh_hash_function_bip324, NULL);
|
||||
assert(return_val);
|
||||
|
||||
/* Both parties should end up with the same shared secret */
|
||||
return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1));
|
||||
assert(return_val == 0);
|
||||
|
||||
printf( " Secret Key1: ");
|
||||
print_hex(seckey1, sizeof(seckey1));
|
||||
printf( "EllSwift Pubkey1: ");
|
||||
print_hex(ellswift_pubkey1, sizeof(ellswift_pubkey1));
|
||||
printf("\n Secret Key2: ");
|
||||
print_hex(seckey2, sizeof(seckey2));
|
||||
printf( "EllSwift Pubkey2: ");
|
||||
print_hex(ellswift_pubkey2, sizeof(ellswift_pubkey2));
|
||||
printf("\n Shared Secret: ");
|
||||
print_hex(shared_secret1, sizeof(shared_secret1));
|
||||
|
||||
/* This will clear everything from the context and free the memory */
|
||||
secp256k1_context_destroy(ctx);
|
||||
|
||||
/* It's best practice to try to clear secrets from memory after using them.
|
||||
* This is done because some bugs can allow an attacker to leak memory, for
|
||||
* example through "out of bounds" array access (see Heartbleed), or the OS
|
||||
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
|
||||
*
|
||||
* Here we are preventing these writes from being optimized out, as any good compiler
|
||||
* will remove any writes that aren't used. */
|
||||
secure_erase(seckey1, sizeof(seckey1));
|
||||
secure_erase(seckey2, sizeof(seckey2));
|
||||
secure_erase(shared_secret1, sizeof(shared_secret1));
|
||||
secure_erase(shared_secret2, sizeof(shared_secret2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
2
external/secp256k1/examples/examples_util.h
vendored
2
external/secp256k1/examples/examples_util.h
vendored
@@ -95,7 +95,7 @@ static void secure_erase(void *ptr, size_t len) {
|
||||
* As best as we can tell, this is sufficient to break any optimisations that
|
||||
* might try to eliminate "superfluous" memsets.
|
||||
* This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is
|
||||
* pretty efficient, because the compiler can still implement the memset() efficently,
|
||||
* pretty efficient, because the compiler can still implement the memset() efficiently,
|
||||
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
|
||||
* Yang et al. (USENIX Security 2017) for more background.
|
||||
*/
|
||||
|
||||
260
external/secp256k1/examples/musig.c
vendored
Normal file
260
external/secp256k1/examples/musig.c
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
/*************************************************************************
|
||||
* To the extent possible under law, the author(s) have dedicated all *
|
||||
* copyright and related and neighboring rights to the software in this *
|
||||
* file to the public domain worldwide. This software is distributed *
|
||||
* without any warranty. For the CC0 Public Domain Dedication, see *
|
||||
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||
*************************************************************************/
|
||||
|
||||
/** This file demonstrates how to use the MuSig module to create a
|
||||
* 3-of-3 multisignature. Additionally, see the documentation in
|
||||
* include/secp256k1_musig.h and doc/musig.md.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_extrakeys.h>
|
||||
#include <secp256k1_musig.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
|
||||
#include "examples_util.h"
|
||||
|
||||
struct signer_secrets {
|
||||
secp256k1_keypair keypair;
|
||||
secp256k1_musig_secnonce secnonce;
|
||||
};
|
||||
|
||||
struct signer {
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_musig_pubnonce pubnonce;
|
||||
secp256k1_musig_partial_sig partial_sig;
|
||||
};
|
||||
|
||||
/* Number of public keys involved in creating the aggregate signature */
|
||||
#define N_SIGNERS 3
|
||||
/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */
|
||||
static int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) {
|
||||
unsigned char seckey[32];
|
||||
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 0;
|
||||
}
|
||||
/* Try to create a keypair with a valid context. This only fails if the
|
||||
* secret key is zero or out of range (greater than secp256k1's order). Note
|
||||
* that the probability of this occurring is negligible with a properly
|
||||
* functioning random number generator. */
|
||||
if (!secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secure_erase(seckey, sizeof(seckey));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Tweak the pubkey corresponding to the provided keyagg cache, update the cache
|
||||
* and return the tweaked aggregate pk. */
|
||||
static int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) {
|
||||
secp256k1_pubkey output_pk;
|
||||
/* For BIP 32 tweaking the plain_tweak is set to a hash as defined in BIP
|
||||
* 32. */
|
||||
unsigned char plain_tweak[32] = "this could be a BIP32 tweak....";
|
||||
/* For Taproot tweaking the xonly_tweak is set to the TapTweak hash as
|
||||
* defined in BIP 341 */
|
||||
unsigned char xonly_tweak[32] = "this could be a Taproot tweak..";
|
||||
|
||||
|
||||
/* Plain tweaking which, for example, allows deriving multiple child
|
||||
* public keys from a single aggregate key using BIP32 */
|
||||
if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, plain_tweak)) {
|
||||
return 0;
|
||||
}
|
||||
/* Note that we did not provide an output_pk argument, because the
|
||||
* resulting pk is also saved in the cache and so if one is just interested
|
||||
* in signing, the output_pk argument is unnecessary. On the other hand, if
|
||||
* one is not interested in signing, the same output_pk can be obtained by
|
||||
* calling `secp256k1_musig_pubkey_get` right after key aggregation to get
|
||||
* the full pubkey and then call `secp256k1_ec_pubkey_tweak_add`. */
|
||||
|
||||
/* Xonly tweaking which, for example, allows creating Taproot commitments */
|
||||
if (!secp256k1_musig_pubkey_xonly_tweak_add(ctx, &output_pk, cache, xonly_tweak)) {
|
||||
return 0;
|
||||
}
|
||||
/* Note that if we wouldn't care about signing, we can arrive at the same
|
||||
* output_pk by providing the untweaked public key to
|
||||
* `secp256k1_xonly_pubkey_tweak_add` (after converting it to an xonly pubkey
|
||||
* if necessary with `secp256k1_xonly_pubkey_from_pubkey`). */
|
||||
|
||||
/* Now we convert the output_pk to an xonly pubkey to allow to later verify
|
||||
* the Schnorr signature against it. For this purpose we can ignore the
|
||||
* `pk_parity` output argument; we would need it if we would have to open
|
||||
* the Taproot commitment. */
|
||||
if (!secp256k1_xonly_pubkey_from_pubkey(ctx, agg_pk, NULL, &output_pk)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Sign a message hash with the given key pairs and store the result in sig */
|
||||
static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const secp256k1_musig_keyagg_cache *cache, const unsigned char *msg32, unsigned char *sig64) {
|
||||
int i;
|
||||
const secp256k1_musig_pubnonce *pubnonces[N_SIGNERS];
|
||||
const secp256k1_musig_partial_sig *partial_sigs[N_SIGNERS];
|
||||
/* The same for all signers */
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_aggnonce agg_pubnonce;
|
||||
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
unsigned char seckey[32];
|
||||
unsigned char session_secrand[32];
|
||||
/* Create random session ID. It is absolutely necessary that the session ID
|
||||
* is unique for every call of secp256k1_musig_nonce_gen. Otherwise
|
||||
* it's trivial for an attacker to extract the secret key! */
|
||||
if (!fill_random(session_secrand, sizeof(session_secrand))) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) {
|
||||
return 0;
|
||||
}
|
||||
/* Initialize session and create secret nonce for signing and public
|
||||
* nonce to send to the other signers. */
|
||||
if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_secrand, seckey, &signer[i].pubkey, msg32, NULL, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
pubnonces[i] = &signer[i].pubnonce;
|
||||
|
||||
secure_erase(seckey, sizeof(seckey));
|
||||
}
|
||||
|
||||
/* Communication round 1: Every signer sends their pubnonce to the
|
||||
* coordinator. The coordinator runs secp256k1_musig_nonce_agg and sends
|
||||
* agg_pubnonce to each signer */
|
||||
if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Every signer creates a partial signature */
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
/* Initialize the signing session by processing the aggregate nonce */
|
||||
if (!secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, cache)) {
|
||||
return 0;
|
||||
}
|
||||
/* partial_sign will clear the secnonce by setting it to 0. That's because
|
||||
* you must _never_ reuse the secnonce (or use the same session_secrand to
|
||||
* create a secnonce). If you do, you effectively reuse the nonce and
|
||||
* leak the secret key. */
|
||||
if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, cache, &session)) {
|
||||
return 0;
|
||||
}
|
||||
partial_sigs[i] = &signer[i].partial_sig;
|
||||
}
|
||||
/* Communication round 2: Every signer sends their partial signature to the
|
||||
* coordinator, who verifies the partial signatures and aggregates them. */
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
/* To check whether signing was successful, it suffices to either verify
|
||||
* the aggregate signature with the aggregate public key using
|
||||
* secp256k1_schnorrsig_verify, or verify all partial signatures of all
|
||||
* signers individually. Verifying the aggregate signature is cheaper but
|
||||
* verifying the individual partial signatures has the advantage that it
|
||||
* can be used to determine which of the partial signatures are invalid
|
||||
* (if any), i.e., which of the partial signatures cause the aggregate
|
||||
* signature to be invalid and thus the protocol run to fail. It's also
|
||||
* fine to first verify the aggregate sig, and only verify the individual
|
||||
* sigs if it does not work.
|
||||
*/
|
||||
if (!secp256k1_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, cache, &session)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return secp256k1_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
secp256k1_context* ctx;
|
||||
int i;
|
||||
struct signer_secrets signer_secrets[N_SIGNERS];
|
||||
struct signer signers[N_SIGNERS];
|
||||
const secp256k1_pubkey *pubkeys_ptr[N_SIGNERS];
|
||||
secp256k1_xonly_pubkey agg_pk;
|
||||
secp256k1_musig_keyagg_cache cache;
|
||||
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg";
|
||||
unsigned char sig[64];
|
||||
|
||||
/* Create a secp256k1 context */
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
printf("Creating key pairs......");
|
||||
fflush(stdout);
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
if (!create_keypair(ctx, &signer_secrets[i], &signers[i])) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
pubkeys_ptr[i] = &signers[i].pubkey;
|
||||
}
|
||||
printf("ok\n");
|
||||
|
||||
/* The aggregate public key produced by secp256k1_musig_pubkey_agg depends
|
||||
* on the order of the provided public keys. If there is no canonical order
|
||||
* of the signers, the individual public keys can optionally be sorted with
|
||||
* secp256k1_ec_pubkey_sort to ensure that the aggregate public key is
|
||||
* independent of the order of signers. */
|
||||
printf("Sorting public keys.....");
|
||||
fflush(stdout);
|
||||
if (!secp256k1_ec_pubkey_sort(ctx, pubkeys_ptr, N_SIGNERS)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
|
||||
printf("Combining public keys...");
|
||||
fflush(stdout);
|
||||
/* If you just want to aggregate and not sign, you can call
|
||||
* secp256k1_musig_pubkey_agg with the keyagg_cache argument set to NULL
|
||||
* while providing a non-NULL agg_pk argument. */
|
||||
if (!secp256k1_musig_pubkey_agg(ctx, NULL, &cache, pubkeys_ptr, N_SIGNERS)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Tweaking................");
|
||||
fflush(stdout);
|
||||
/* Optionally tweak the aggregate key */
|
||||
if (!tweak(ctx, &agg_pk, &cache)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Signing message.........");
|
||||
fflush(stdout);
|
||||
if (!sign(ctx, signer_secrets, signers, &cache, msg, sig)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Verifying signature.....");
|
||||
fflush(stdout);
|
||||
if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &agg_pk)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
|
||||
/* It's best practice to try to clear secrets from memory after using them.
|
||||
* This is done because some bugs can allow an attacker to leak memory, for
|
||||
* example through "out of bounds" array access (see Heartbleed), or the OS
|
||||
* swapping them to disk. Hence, we overwrite secret key material with zeros.
|
||||
*
|
||||
* Here we are preventing these writes from being optimized out, as any good compiler
|
||||
* will remove any writes that aren't used. */
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
secure_erase(&signer_secrets[i], sizeof(signer_secrets[i]));
|
||||
}
|
||||
secp256k1_context_destroy(ctx);
|
||||
return 0;
|
||||
}
|
||||
31
external/secp256k1/examples/schnorr.c
vendored
31
external/secp256k1/examples/schnorr.c
vendored
@@ -18,9 +18,9 @@
|
||||
#include "examples_util.h"
|
||||
|
||||
int main(void) {
|
||||
unsigned char msg[12] = "Hello World!";
|
||||
unsigned char msg[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
|
||||
unsigned char msg_hash[32];
|
||||
unsigned char tag[17] = "my_fancy_protocol";
|
||||
unsigned char tag[] = {'m', 'y', '_', 'f', 'a', 'n', 'c', 'y', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l'};
|
||||
unsigned char seckey[32];
|
||||
unsigned char randomize[32];
|
||||
unsigned char auxiliary_rand[32];
|
||||
@@ -43,20 +43,17 @@ int main(void) {
|
||||
assert(return_val);
|
||||
|
||||
/*** Key Generation ***/
|
||||
|
||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||
* order), we try to sample a new key. Note that the probability of this
|
||||
* happening is negligible. */
|
||||
while (1) {
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* Try to create a keypair with a valid context, it should only fail if
|
||||
* the secret key is zero or out of range. */
|
||||
if (secp256k1_keypair_create(ctx, &keypair, seckey)) {
|
||||
break;
|
||||
}
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* Try to create a keypair with a valid context. This only fails if the
|
||||
* secret key is zero or out of range (greater than secp256k1's order). Note
|
||||
* that the probability of this occurring is negligible with a properly
|
||||
* functioning random number generator. */
|
||||
if (!secp256k1_keypair_create(ctx, &keypair, seckey)) {
|
||||
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Extract the X-only public key from the keypair. We pass NULL for
|
||||
@@ -146,7 +143,7 @@ int main(void) {
|
||||
|
||||
/* It's best practice to try to clear secrets from memory after using them.
|
||||
* This is done because some bugs can allow an attacker to leak memory, for
|
||||
* example through "out of bounds" array access (see Heartbleed), Or the OS
|
||||
* example through "out of bounds" array access (see Heartbleed), or the OS
|
||||
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
|
||||
*
|
||||
* Here we are preventing these writes from being optimized out, as any good compiler
|
||||
|
||||
Reference in New Issue
Block a user