2020-12-17 08:33:49 +02:00
|
|
|
/***********************************************************************
|
|
|
|
|
* Copyright (c) 2013-2015 Pieter Wuille *
|
|
|
|
|
* Distributed under the MIT software license, see the accompanying *
|
|
|
|
|
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
|
|
|
|
***********************************************************************/
|
2013-05-09 15:24:32 +02:00
|
|
|
|
2022-03-17 22:26:19 +01:00
|
|
|
/* This is a C project. It should not be compiled with a C++ compiler,
|
|
|
|
|
* and we error out if we detect one.
|
|
|
|
|
*
|
|
|
|
|
* We still want to be able to test the project with a C++ compiler
|
|
|
|
|
* because it is still good to know if this will lead to real trouble, so
|
|
|
|
|
* there is a possibility to override the check. But be warned that
|
|
|
|
|
* compiling with a C++ compiler is not supported. */
|
|
|
|
|
#if defined(__cplusplus) && !defined(SECP256K1_CPLUSPLUS_TEST_OVERRIDE)
|
|
|
|
|
#error Trying to compile a C project with a C++ compiler.
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-05-01 17:08:52 +00:00
|
|
|
#define SECP256K1_BUILD
|
|
|
|
|
|
2021-05-04 13:19:33 -04:00
|
|
|
#include "../include/secp256k1.h"
|
|
|
|
|
#include "../include/secp256k1_preallocated.h"
|
2014-09-08 23:09:06 +02:00
|
|
|
|
2020-08-12 15:52:20 -07:00
|
|
|
#include "assumptions.h"
|
2022-12-06 16:35:35 -05:00
|
|
|
#include "checkmem.h"
|
2014-08-18 23:07:46 +02:00
|
|
|
#include "util.h"
|
2022-02-01 14:43:16 +01:00
|
|
|
|
2014-03-07 01:11:01 +01:00
|
|
|
#include "field_impl.h"
|
2014-10-28 04:08:15 -07:00
|
|
|
#include "scalar_impl.h"
|
2014-03-07 01:11:01 +01:00
|
|
|
#include "group_impl.h"
|
2020-12-05 22:40:54 +00:00
|
|
|
#include "eccommit_impl.h"
|
2014-03-07 01:11:01 +01:00
|
|
|
#include "ecmult_impl.h"
|
2015-05-13 17:31:47 -05:00
|
|
|
#include "ecmult_const_impl.h"
|
2014-10-26 03:42:24 -07:00
|
|
|
#include "ecmult_gen_impl.h"
|
2014-03-07 01:11:01 +01:00
|
|
|
#include "ecdsa_impl.h"
|
2014-10-27 02:57:27 -07:00
|
|
|
#include "eckey_impl.h"
|
2014-12-13 17:02:30 +01:00
|
|
|
#include "hash_impl.h"
|
2022-02-01 14:43:16 +01:00
|
|
|
#include "int128_impl.h"
|
2017-07-22 18:03:17 +00:00
|
|
|
#include "scratch_impl.h"
|
2020-08-17 13:48:22 -07:00
|
|
|
#include "selftest.h"
|
2024-04-17 17:33:51 +00:00
|
|
|
#include "hsort_impl.h"
|
2013-03-31 06:34:15 +02:00
|
|
|
|
2021-05-01 17:08:52 +00:00
|
|
|
#ifdef SECP256K1_NO_BUILD
|
|
|
|
|
# error "secp256k1.h processed without SECP256K1_BUILD defined while building secp256k1.c"
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-07-07 00:47:41 +02:00
|
|
|
#ifdef ENABLE_MODULE_GENERATOR
|
2023-04-21 11:00:37 +02:00
|
|
|
# include "../include/secp256k1_generator.h"
|
2016-07-07 00:47:41 +02:00
|
|
|
#endif
|
|
|
|
|
|
Pedersen commitments, borromean ring signatures, and ZK range proofs.
This commit adds three new cryptosystems to libsecp256k1:
Pedersen commitments are a system for making blinded commitments
to a value. Functionally they work like:
commit_b,v = H(blind_b || value_v),
except they are additively homorphic, e.g.
C(b1, v1) - C(b2, v2) = C(b1 - b2, v1 - v2) and
C(b1, v1) - C(b1, v1) = 0, etc.
The commitments themselves are EC points, serialized as 33 bytes.
In addition to the commit function this implementation includes
utility functions for verifying that a set of commitments sums
to zero, and for picking blinding factors that sum to zero.
If the blinding factors are uniformly random, pedersen commitments
have information theoretic privacy.
Borromean ring signatures are a novel efficient ring signature
construction for AND/OR admissions policies (the code here implements
an AND of ORs, each of any size). This construction requires
32 bytes of signature per pubkey used plus 32 bytes of constant
overhead. With these you can construct signatures like "Given pubkeys
A B C D E F G, the signer knows the discrete logs
satisifying (A || B) & (C || D || E) & (F || G)".
ZK range proofs allow someone to prove a pedersen commitment is in
a particular range (e.g. [0..2^64)) without revealing the specific
value. The construction here is based on the above borromean
ring signature and uses a radix-4 encoding and other optimizations
to maximize efficiency. It also supports encoding proofs with a
non-private base-10 exponent and minimum-value to allow trading
off secrecy for size and speed (or just avoiding wasting space
keeping data private that was already public due to external
constraints).
A proof for a 32-bit mantissa takes 2564 bytes, but 2048 bytes of
this can be used to communicate a private message to a receiver
who shares a secret random seed with the prover.
Also: get rid of precomputed H tables (Pieter Wuille)
2015-08-05 19:04:14 +02:00
|
|
|
#ifdef ENABLE_MODULE_RANGEPROOF
|
2023-04-21 11:00:37 +02:00
|
|
|
# include "../include/secp256k1_rangeproof.h"
|
Pedersen commitments, borromean ring signatures, and ZK range proofs.
This commit adds three new cryptosystems to libsecp256k1:
Pedersen commitments are a system for making blinded commitments
to a value. Functionally they work like:
commit_b,v = H(blind_b || value_v),
except they are additively homorphic, e.g.
C(b1, v1) - C(b2, v2) = C(b1 - b2, v1 - v2) and
C(b1, v1) - C(b1, v1) = 0, etc.
The commitments themselves are EC points, serialized as 33 bytes.
In addition to the commit function this implementation includes
utility functions for verifying that a set of commitments sums
to zero, and for picking blinding factors that sum to zero.
If the blinding factors are uniformly random, pedersen commitments
have information theoretic privacy.
Borromean ring signatures are a novel efficient ring signature
construction for AND/OR admissions policies (the code here implements
an AND of ORs, each of any size). This construction requires
32 bytes of signature per pubkey used plus 32 bytes of constant
overhead. With these you can construct signatures like "Given pubkeys
A B C D E F G, the signer knows the discrete logs
satisifying (A || B) & (C || D || E) & (F || G)".
ZK range proofs allow someone to prove a pedersen commitment is in
a particular range (e.g. [0..2^64)) without revealing the specific
value. The construction here is based on the above borromean
ring signature and uses a radix-4 encoding and other optimizations
to maximize efficiency. It also supports encoding proofs with a
non-private base-10 exponent and minimum-value to allow trading
off secrecy for size and speed (or just avoiding wasting space
keeping data private that was already public due to external
constraints).
A proof for a 32-bit mantissa takes 2564 bytes, but 2048 bytes of
this can be used to communicate a private message to a receiver
who shares a secret random seed with the prover.
Also: get rid of precomputed H tables (Pieter Wuille)
2015-08-05 19:04:14 +02:00
|
|
|
#endif
|
|
|
|
|
|
2020-12-05 23:34:14 +00:00
|
|
|
#ifdef ENABLE_MODULE_ECDSA_S2C
|
2023-04-21 11:00:37 +02:00
|
|
|
# include "../include/secp256k1_ecdsa_s2c.h"
|
2020-12-05 23:34:14 +00:00
|
|
|
static void secp256k1_ecdsa_s2c_opening_save(secp256k1_ecdsa_s2c_opening* opening, secp256k1_ge* ge);
|
|
|
|
|
#else
|
|
|
|
|
typedef void secp256k1_ecdsa_s2c_opening;
|
|
|
|
|
static void secp256k1_ecdsa_s2c_opening_save(secp256k1_ecdsa_s2c_opening* opening, secp256k1_ge* ge) {
|
|
|
|
|
(void) opening;
|
|
|
|
|
(void) ge;
|
|
|
|
|
VERIFY_CHECK(0);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-07-18 16:29:10 -04:00
|
|
|
#define ARG_CHECK(cond) do { \
|
|
|
|
|
if (EXPECT(!(cond), 0)) { \
|
2015-09-21 20:57:54 +02:00
|
|
|
secp256k1_callback_call(&ctx->illegal_callback, #cond); \
|
2015-07-18 16:29:10 -04:00
|
|
|
return 0; \
|
|
|
|
|
} \
|
|
|
|
|
} while(0)
|
|
|
|
|
|
2022-12-07 12:59:45 +01:00
|
|
|
#define ARG_CHECK_VOID(cond) do { \
|
2019-03-04 13:09:45 +01:00
|
|
|
if (EXPECT(!(cond), 0)) { \
|
|
|
|
|
secp256k1_callback_call(&ctx->illegal_callback, #cond); \
|
2022-12-07 12:59:45 +01:00
|
|
|
return; \
|
2019-03-04 13:09:45 +01:00
|
|
|
} \
|
|
|
|
|
} while(0)
|
|
|
|
|
|
2022-11-28 21:10:30 +00:00
|
|
|
/* Note that whenever you change the context struct, you must also change the
|
|
|
|
|
* context_eq function. */
|
2015-02-03 17:27:00 -08:00
|
|
|
struct secp256k1_context_struct {
|
2015-09-21 20:57:54 +02:00
|
|
|
secp256k1_ecmult_gen_context ecmult_gen_ctx;
|
2025-12-17 11:15:33 -05:00
|
|
|
secp256k1_hash_ctx hash_ctx;
|
2015-09-21 20:57:54 +02:00
|
|
|
secp256k1_callback illegal_callback;
|
|
|
|
|
secp256k1_callback error_callback;
|
2020-01-11 13:31:50 +00:00
|
|
|
int declassify;
|
2015-02-03 17:27:00 -08:00
|
|
|
};
|
|
|
|
|
|
2022-07-06 17:09:31 +02:00
|
|
|
static const secp256k1_context secp256k1_context_static_ = {
|
2018-08-15 21:27:25 +00:00
|
|
|
{ 0 },
|
2025-12-17 11:15:33 -05:00
|
|
|
{ secp256k1_sha256_transform },
|
2019-03-09 11:41:21 +01:00
|
|
|
{ secp256k1_default_illegal_callback_fn, 0 },
|
2020-01-11 13:31:50 +00:00
|
|
|
{ secp256k1_default_error_callback_fn, 0 },
|
|
|
|
|
0
|
2018-08-15 21:27:25 +00:00
|
|
|
};
|
2024-11-22 22:28:30 +01:00
|
|
|
const secp256k1_context * const secp256k1_context_static = &secp256k1_context_static_;
|
|
|
|
|
const secp256k1_context * const secp256k1_context_no_precomp = &secp256k1_context_static_;
|
2018-08-15 21:27:25 +00:00
|
|
|
|
2022-12-05 14:35:54 +01:00
|
|
|
/* Helper function that determines if a context is proper, i.e., is not the static context or a copy thereof.
|
|
|
|
|
*
|
2024-06-24 14:24:48 -07:00
|
|
|
* This is intended for "context" functions such as secp256k1_context_clone. Functions that need specific
|
2022-12-05 14:35:54 +01:00
|
|
|
* features of a context should still check for these features directly. For example, a function that needs
|
|
|
|
|
* ecmult_gen should directly check for the existence of the ecmult_gen context. */
|
|
|
|
|
static int secp256k1_context_is_proper(const secp256k1_context* ctx) {
|
|
|
|
|
return secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 12:48:24 +02:00
|
|
|
void secp256k1_selftest(void) {
|
|
|
|
|
if (!secp256k1_selftest_passes()) {
|
|
|
|
|
secp256k1_callback_call(&default_error_callback, "self test failed");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-22 16:23:09 +02:00
|
|
|
size_t secp256k1_context_preallocated_size(unsigned int flags) {
|
2021-11-09 13:09:36 +01:00
|
|
|
size_t ret = sizeof(secp256k1_context);
|
2020-10-26 14:38:30 +01:00
|
|
|
/* A return value of 0 is reserved as an indicator for errors when we call this function internally. */
|
|
|
|
|
VERIFY_CHECK(ret != 0);
|
2018-10-22 16:23:09 +02:00
|
|
|
|
|
|
|
|
if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) {
|
|
|
|
|
secp256k1_callback_call(&default_illegal_callback,
|
|
|
|
|
"Invalid flags");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-20 12:25:48 -05:00
|
|
|
if (EXPECT(!SECP256K1_CHECKMEM_RUNNING() && (flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY), 0)) {
|
|
|
|
|
secp256k1_callback_call(&default_illegal_callback,
|
|
|
|
|
"Declassify flag requires running with memory checking");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-22 16:23:09 +02:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-25 17:14:10 +02:00
|
|
|
size_t secp256k1_context_preallocated_clone_size(const secp256k1_context* ctx) {
|
2018-10-25 18:08:14 +02:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2022-12-07 14:38:45 +01:00
|
|
|
ARG_CHECK(secp256k1_context_is_proper(ctx));
|
|
|
|
|
return sizeof(secp256k1_context);
|
2018-10-25 17:14:10 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-22 16:25:26 +02:00
|
|
|
secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigned int flags) {
|
2018-10-25 18:08:14 +02:00
|
|
|
size_t prealloc_size;
|
|
|
|
|
secp256k1_context* ret;
|
2018-10-22 16:25:26 +02:00
|
|
|
|
2022-07-15 12:48:24 +02:00
|
|
|
secp256k1_selftest();
|
2020-10-26 14:38:30 +01:00
|
|
|
|
2018-10-25 18:08:14 +02:00
|
|
|
prealloc_size = secp256k1_context_preallocated_size(flags);
|
2020-10-26 14:38:30 +01:00
|
|
|
if (prealloc_size == 0) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
VERIFY_CHECK(prealloc != NULL);
|
2021-11-09 13:09:36 +01:00
|
|
|
ret = (secp256k1_context*)prealloc;
|
2015-07-18 16:29:10 -04:00
|
|
|
ret->illegal_callback = default_illegal_callback;
|
|
|
|
|
ret->error_callback = default_error_callback;
|
2025-12-17 11:15:33 -05:00
|
|
|
secp256k1_hash_ctx_init(&ret->hash_ctx);
|
2015-02-03 17:27:00 -08:00
|
|
|
|
2020-10-26 14:38:30 +01:00
|
|
|
/* Flags have been checked by secp256k1_context_preallocated_size. */
|
|
|
|
|
VERIFY_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_CONTEXT);
|
2025-12-17 11:15:33 -05:00
|
|
|
secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->hash_ctx);
|
2020-01-11 13:31:50 +00:00
|
|
|
ret->declassify = !!(flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY);
|
2015-02-03 17:27:00 -08:00
|
|
|
|
2021-11-09 13:09:36 +01:00
|
|
|
return ret;
|
2018-10-22 16:25:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
secp256k1_context* secp256k1_context_create(unsigned int flags) {
|
|
|
|
|
size_t const prealloc_size = secp256k1_context_preallocated_size(flags);
|
2026-01-30 15:58:30 +01:00
|
|
|
secp256k1_context* ctx = checked_malloc(&default_error_callback, prealloc_size);
|
2018-10-22 16:25:26 +02:00
|
|
|
if (EXPECT(secp256k1_context_preallocated_create(ctx, flags) == NULL, 0)) {
|
|
|
|
|
free(ctx);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ctx;
|
2013-03-31 06:34:15 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-25 17:14:10 +02:00
|
|
|
secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context* ctx, void* prealloc) {
|
2018-10-25 18:08:14 +02:00
|
|
|
secp256k1_context* ret;
|
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
|
|
|
ARG_CHECK(prealloc != NULL);
|
2022-12-07 14:38:45 +01:00
|
|
|
ARG_CHECK(secp256k1_context_is_proper(ctx));
|
2018-10-25 18:08:14 +02:00
|
|
|
|
|
|
|
|
ret = (secp256k1_context*)prealloc;
|
2021-11-09 13:09:36 +01:00
|
|
|
*ret = *ctx;
|
2015-04-11 14:06:54 -05:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-25 17:14:10 +02:00
|
|
|
secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
|
2018-10-25 18:08:14 +02:00
|
|
|
secp256k1_context* ret;
|
|
|
|
|
size_t prealloc_size;
|
|
|
|
|
|
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2022-12-07 14:38:45 +01:00
|
|
|
ARG_CHECK(secp256k1_context_is_proper(ctx));
|
|
|
|
|
|
2018-10-25 18:08:14 +02:00
|
|
|
prealloc_size = secp256k1_context_preallocated_clone_size(ctx);
|
2026-01-30 15:58:30 +01:00
|
|
|
ret = checked_malloc(&ctx->error_callback, prealloc_size);
|
2018-10-25 17:14:10 +02:00
|
|
|
ret = secp256k1_context_preallocated_clone(ctx, ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-22 16:25:26 +02:00
|
|
|
void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
|
2022-12-07 14:38:45 +01:00
|
|
|
ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx));
|
|
|
|
|
|
|
|
|
|
/* Defined as noop */
|
|
|
|
|
if (ctx == NULL) {
|
|
|
|
|
return;
|
2018-10-22 16:25:26 +02:00
|
|
|
}
|
2022-12-07 14:38:45 +01:00
|
|
|
|
|
|
|
|
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
|
2018-10-22 16:25:26 +02:00
|
|
|
}
|
2015-09-01 01:41:35 +00:00
|
|
|
|
2018-10-22 16:25:26 +02:00
|
|
|
void secp256k1_context_destroy(secp256k1_context* ctx) {
|
2022-12-07 14:38:45 +01:00
|
|
|
ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx));
|
|
|
|
|
|
|
|
|
|
/* Defined as noop */
|
|
|
|
|
if (ctx == NULL) {
|
|
|
|
|
return;
|
2015-09-21 17:21:35 +00:00
|
|
|
}
|
2022-12-07 14:38:45 +01:00
|
|
|
|
|
|
|
|
secp256k1_context_preallocated_destroy(ctx);
|
|
|
|
|
free(ctx);
|
2013-03-31 06:34:15 +02:00
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
|
2022-12-05 14:35:54 +01:00
|
|
|
/* We compare pointers instead of checking secp256k1_context_is_proper() here
|
|
|
|
|
because setting callbacks is allowed on *copies* of the static context:
|
|
|
|
|
it's harmless and makes testing easier. */
|
2022-12-07 12:59:45 +01:00
|
|
|
ARG_CHECK_VOID(ctx != secp256k1_context_static);
|
2015-09-23 21:56:04 +00:00
|
|
|
if (fun == NULL) {
|
2019-03-09 11:41:21 +01:00
|
|
|
fun = secp256k1_default_illegal_callback_fn;
|
2015-09-21 17:21:35 +00:00
|
|
|
}
|
2015-07-18 16:29:10 -04:00
|
|
|
ctx->illegal_callback.fn = fun;
|
|
|
|
|
ctx->illegal_callback.data = data;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
|
2022-12-05 14:35:54 +01:00
|
|
|
/* We compare pointers instead of checking secp256k1_context_is_proper() here
|
|
|
|
|
because setting callbacks is allowed on *copies* of the static context:
|
|
|
|
|
it's harmless and makes testing easier. */
|
2022-12-07 12:59:45 +01:00
|
|
|
ARG_CHECK_VOID(ctx != secp256k1_context_static);
|
2015-09-23 21:56:04 +00:00
|
|
|
if (fun == NULL) {
|
2019-03-09 11:41:21 +01:00
|
|
|
fun = secp256k1_default_error_callback_fn;
|
2015-09-21 17:21:35 +00:00
|
|
|
}
|
2015-07-18 16:29:10 -04:00
|
|
|
ctx->error_callback.fn = fun;
|
|
|
|
|
ctx->error_callback.data = data;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-23 13:41:55 -05:00
|
|
|
void secp256k1_context_set_sha256_compression(secp256k1_context *ctx, secp256k1_sha256_compression_function fn_compression) {
|
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
|
|
|
ARG_CHECK_VOID(secp256k1_context_is_proper(ctx));
|
|
|
|
|
if (!fn_compression) { /* Reset hash context */
|
|
|
|
|
secp256k1_hash_ctx_init(&ctx->hash_ctx);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Check and set */
|
|
|
|
|
ARG_CHECK_VOID(secp256k1_selftest_sha256(fn_compression));
|
|
|
|
|
ctx->hash_ctx.fn_sha256_compression = fn_compression;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 11:15:33 -05:00
|
|
|
static SECP256K1_INLINE const secp256k1_hash_ctx* secp256k1_get_hash_context(const secp256k1_context *ctx) {
|
|
|
|
|
return &ctx->hash_ctx;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-11 13:24:37 +00:00
|
|
|
static secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) {
|
2017-07-22 18:03:17 +00:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2018-03-20 13:21:33 +00:00
|
|
|
return secp256k1_scratch_create(&ctx->error_callback, max_size);
|
2017-07-22 18:03:17 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-11 13:24:37 +00:00
|
|
|
static void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) {
|
2019-03-13 23:30:51 +00:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
|
|
|
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
|
2017-07-22 18:03:17 +00:00
|
|
|
}
|
|
|
|
|
|
2020-01-11 13:31:50 +00:00
|
|
|
/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour
|
2022-12-06 16:35:35 -05:00
|
|
|
* of the software.
|
2020-01-11 13:31:50 +00:00
|
|
|
*/
|
2020-03-30 14:51:38 +00:00
|
|
|
static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, const void *p, size_t len) {
|
2022-12-06 16:35:35 -05:00
|
|
|
if (EXPECT(ctx->declassify, 0)) SECP256K1_CHECKMEM_DEFINE(p, len);
|
2020-01-11 13:31:50 +00:00
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
|
2024-01-06 15:53:30 +00:00
|
|
|
secp256k1_ge_from_bytes(ge, pubkey->data);
|
2015-07-18 16:29:10 -04:00
|
|
|
ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));
|
|
|
|
|
return 1;
|
2015-07-20 13:36:55 -04:00
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
|
2024-01-06 15:53:30 +00:00
|
|
|
secp256k1_ge_to_bytes(pubkey->data, ge);
|
2015-07-20 13:36:55 -04:00
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) {
|
|
|
|
|
secp256k1_ge Q;
|
2015-07-20 13:36:55 -04:00
|
|
|
|
2015-09-27 23:45:12 +00:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
|
|
|
ARG_CHECK(pubkey != NULL);
|
|
|
|
|
memset(pubkey, 0, sizeof(*pubkey));
|
|
|
|
|
ARG_CHECK(input != NULL);
|
2015-07-20 13:36:55 -04:00
|
|
|
if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-09-07 18:23:52 -07:00
|
|
|
if (!secp256k1_ge_is_in_correct_subgroup(&Q)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-07-20 13:36:55 -04:00
|
|
|
secp256k1_pubkey_save(pubkey, &Q);
|
|
|
|
|
secp256k1_ge_clear(&Q);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) {
|
|
|
|
|
secp256k1_ge Q;
|
2015-10-30 09:16:40 +00:00
|
|
|
size_t len;
|
2015-07-20 13:36:55 -04:00
|
|
|
|
2015-09-27 23:45:12 +00:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
|
|
|
ARG_CHECK(outputlen != NULL);
|
2020-07-26 05:25:14 +00:00
|
|
|
ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33u : 65u));
|
2015-10-30 09:16:40 +00:00
|
|
|
len = *outputlen;
|
|
|
|
|
*outputlen = 0;
|
|
|
|
|
ARG_CHECK(output != NULL);
|
|
|
|
|
memset(output, 0, len);
|
2015-09-27 23:45:12 +00:00
|
|
|
ARG_CHECK(pubkey != NULL);
|
2015-10-21 17:43:29 +02:00
|
|
|
ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION);
|
2015-10-30 09:16:40 +00:00
|
|
|
if (secp256k1_pubkey_load(ctx, &Q, pubkey)) {
|
2025-11-17 16:58:01 +01:00
|
|
|
if (flags & SECP256K1_FLAGS_BIT_COMPRESSION) {
|
|
|
|
|
secp256k1_eckey_pubkey_serialize33(&Q, output);
|
|
|
|
|
*outputlen = 33;
|
|
|
|
|
} else {
|
|
|
|
|
secp256k1_eckey_pubkey_serialize65(&Q, output);
|
|
|
|
|
*outputlen = 65;
|
2015-10-30 09:16:40 +00:00
|
|
|
}
|
2025-12-09 16:08:35 -05:00
|
|
|
return 1;
|
2015-10-30 09:16:40 +00:00
|
|
|
}
|
2025-12-09 16:08:35 -05:00
|
|
|
return 0;
|
2015-07-20 13:36:55 -04:00
|
|
|
}
|
|
|
|
|
|
2020-11-22 17:33:46 +00:00
|
|
|
int secp256k1_ec_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_pubkey* pubkey0, const secp256k1_pubkey* pubkey1) {
|
|
|
|
|
unsigned char out[2][33];
|
|
|
|
|
const secp256k1_pubkey* pk[2];
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
|
|
|
pk[0] = pubkey0; pk[1] = pubkey1;
|
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
|
size_t out_size = sizeof(out[i]);
|
|
|
|
|
/* If the public key is NULL or invalid, ec_pubkey_serialize will call
|
|
|
|
|
* the illegal_callback and return 0. In that case we will serialize the
|
|
|
|
|
* key as all zeros which is less than any valid public key. This
|
|
|
|
|
* results in consistent comparisons even if NULL or invalid pubkeys are
|
|
|
|
|
* involved and prevents edge cases such as sorting algorithms that use
|
|
|
|
|
* this function and do not terminate as a result. */
|
|
|
|
|
if (!secp256k1_ec_pubkey_serialize(ctx, out[i], &out_size, pk[i], SECP256K1_EC_COMPRESSED)) {
|
|
|
|
|
/* Note that ec_pubkey_serialize should already set the output to
|
|
|
|
|
* zero in that case, but it's not guaranteed by the API, we can't
|
|
|
|
|
* test it and writing a VERIFY_CHECK is more complex than
|
|
|
|
|
* explicitly memsetting (again). */
|
|
|
|
|
memset(out[i], 0, sizeof(out[i]));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return secp256k1_memcmp_var(out[0], out[1], sizeof(out[0]));
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-17 17:33:51 +00:00
|
|
|
static int secp256k1_ec_pubkey_sort_cmp(const void* pk1, const void* pk2, void *ctx) {
|
|
|
|
|
return secp256k1_ec_pubkey_cmp((secp256k1_context *)ctx,
|
|
|
|
|
*(secp256k1_pubkey **)pk1,
|
|
|
|
|
*(secp256k1_pubkey **)pk2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int secp256k1_ec_pubkey_sort(const secp256k1_context* ctx, const secp256k1_pubkey **pubkeys, size_t n_pubkeys) {
|
2025-12-06 01:04:18 +01:00
|
|
|
size_t i;
|
|
|
|
|
|
2024-04-17 17:33:51 +00:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
|
|
|
ARG_CHECK(pubkeys != NULL);
|
2025-12-06 01:04:18 +01:00
|
|
|
for (i = 0; i < n_pubkeys; i++) {
|
|
|
|
|
ARG_CHECK(pubkeys[i] != NULL);
|
|
|
|
|
}
|
2024-04-17 17:33:51 +00:00
|
|
|
|
|
|
|
|
/* Suppress wrong warning (fixed in MSVC 19.33) */
|
|
|
|
|
#if defined(_MSC_VER) && (_MSC_VER < 1933)
|
|
|
|
|
#pragma warning(push)
|
|
|
|
|
#pragma warning(disable: 4090)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Casting away const is fine because neither secp256k1_hsort nor
|
|
|
|
|
* secp256k1_ec_pubkey_sort_cmp modify the data pointed to by the cmp_data
|
|
|
|
|
* argument. */
|
|
|
|
|
secp256k1_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), secp256k1_ec_pubkey_sort_cmp, (void *)ctx);
|
|
|
|
|
|
|
|
|
|
#if defined(_MSC_VER) && (_MSC_VER < 1933)
|
|
|
|
|
#pragma warning(pop)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) {
|
2015-08-27 03:09:23 +02:00
|
|
|
(void)ctx;
|
2015-09-21 20:57:54 +02:00
|
|
|
if (sizeof(secp256k1_scalar) == 32) {
|
|
|
|
|
/* When the secp256k1_scalar type is exactly 32 byte, use its
|
|
|
|
|
* representation inside secp256k1_ecdsa_signature, as conversion is very fast.
|
2015-08-27 03:09:23 +02:00
|
|
|
* Note that secp256k1_ecdsa_signature_save must use the same representation. */
|
|
|
|
|
memcpy(r, &sig->data[0], 32);
|
|
|
|
|
memcpy(s, &sig->data[32], 32);
|
|
|
|
|
} else {
|
|
|
|
|
secp256k1_scalar_set_b32(r, &sig->data[0], NULL);
|
|
|
|
|
secp256k1_scalar_set_b32(s, &sig->data[32], NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s) {
|
|
|
|
|
if (sizeof(secp256k1_scalar) == 32) {
|
2015-08-27 03:09:23 +02:00
|
|
|
memcpy(&sig->data[0], r, 32);
|
|
|
|
|
memcpy(&sig->data[32], s, 32);
|
|
|
|
|
} else {
|
|
|
|
|
secp256k1_scalar_get_b32(&sig->data[0], r);
|
|
|
|
|
secp256k1_scalar_get_b32(&sig->data[32], s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
|
|
|
|
|
secp256k1_scalar r, s;
|
2015-07-26 16:00:55 +02:00
|
|
|
|
2016-04-26 15:49:02 +00:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2015-07-18 16:29:10 -04:00
|
|
|
ARG_CHECK(sig != NULL);
|
|
|
|
|
ARG_CHECK(input != NULL);
|
2015-07-26 16:00:55 +02:00
|
|
|
|
2015-07-26 16:51:58 +02:00
|
|
|
if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) {
|
2015-08-27 03:09:23 +02:00
|
|
|
secp256k1_ecdsa_signature_save(sig, &r, &s);
|
2015-07-26 16:00:55 +02:00
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
memset(sig, 0, sizeof(*sig));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-28 17:40:21 +02:00
|
|
|
int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input64) {
|
|
|
|
|
secp256k1_scalar r, s;
|
|
|
|
|
int ret = 1;
|
|
|
|
|
int overflow = 0;
|
|
|
|
|
|
2016-04-26 15:49:02 +00:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2015-09-28 17:40:21 +02:00
|
|
|
ARG_CHECK(sig != NULL);
|
|
|
|
|
ARG_CHECK(input64 != NULL);
|
|
|
|
|
|
|
|
|
|
secp256k1_scalar_set_b32(&r, &input64[0], &overflow);
|
|
|
|
|
ret &= !overflow;
|
|
|
|
|
secp256k1_scalar_set_b32(&s, &input64[32], &overflow);
|
|
|
|
|
ret &= !overflow;
|
|
|
|
|
if (ret) {
|
|
|
|
|
secp256k1_ecdsa_signature_save(sig, &r, &s);
|
|
|
|
|
} else {
|
|
|
|
|
memset(sig, 0, sizeof(*sig));
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) {
|
|
|
|
|
secp256k1_scalar r, s;
|
2015-07-26 16:00:55 +02:00
|
|
|
|
2016-04-26 15:49:02 +00:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2015-07-18 16:29:10 -04:00
|
|
|
ARG_CHECK(output != NULL);
|
|
|
|
|
ARG_CHECK(outputlen != NULL);
|
|
|
|
|
ARG_CHECK(sig != NULL);
|
2015-07-26 16:00:55 +02:00
|
|
|
|
2015-08-27 03:09:23 +02:00
|
|
|
secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
|
2015-07-26 16:51:58 +02:00
|
|
|
return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s);
|
2015-07-26 16:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
2015-09-28 17:40:21 +02:00
|
|
|
int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) {
|
|
|
|
|
secp256k1_scalar r, s;
|
|
|
|
|
|
2016-04-26 15:49:02 +00:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2015-09-28 17:40:21 +02:00
|
|
|
ARG_CHECK(output64 != NULL);
|
|
|
|
|
ARG_CHECK(sig != NULL);
|
|
|
|
|
|
|
|
|
|
secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
|
|
|
|
|
secp256k1_scalar_get_b32(&output64[0], &r);
|
|
|
|
|
secp256k1_scalar_get_b32(&output64[32], &s);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-14 18:54:32 +02:00
|
|
|
int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) {
|
|
|
|
|
secp256k1_scalar r, s;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
|
|
|
ARG_CHECK(sigin != NULL);
|
|
|
|
|
|
|
|
|
|
secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin);
|
|
|
|
|
ret = secp256k1_scalar_is_high(&s);
|
|
|
|
|
if (sigout != NULL) {
|
|
|
|
|
if (ret) {
|
|
|
|
|
secp256k1_scalar_negate(&s, &s);
|
|
|
|
|
}
|
|
|
|
|
secp256k1_ecdsa_signature_save(sigout, &r, &s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 15:53:31 +00:00
|
|
|
int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msghash32, const secp256k1_pubkey *pubkey) {
|
2015-09-21 20:57:54 +02:00
|
|
|
secp256k1_ge q;
|
|
|
|
|
secp256k1_scalar r, s;
|
|
|
|
|
secp256k1_scalar m;
|
2015-09-01 14:22:32 -04:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2020-12-03 15:53:31 +00:00
|
|
|
ARG_CHECK(msghash32 != NULL);
|
2015-07-18 16:29:10 -04:00
|
|
|
ARG_CHECK(sig != NULL);
|
|
|
|
|
ARG_CHECK(pubkey != NULL);
|
2014-08-18 23:07:46 +02:00
|
|
|
|
2020-12-03 15:53:31 +00:00
|
|
|
secp256k1_scalar_set_b32(&m, msghash32, NULL);
|
2015-08-27 03:09:23 +02:00
|
|
|
secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
|
2015-10-14 18:54:32 +02:00
|
|
|
return (!secp256k1_scalar_is_high(&s) &&
|
|
|
|
|
secp256k1_pubkey_load(ctx, &q, pubkey) &&
|
2021-06-25 18:46:11 -04:00
|
|
|
secp256k1_ecdsa_sig_verify(&r, &s, &q, &m));
|
2013-03-16 15:51:55 +01:00
|
|
|
}
|
|
|
|
|
|
2017-06-22 23:31:23 -07:00
|
|
|
static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *offset, const void *data, unsigned int len) {
|
|
|
|
|
memcpy(buf + *offset, data, len);
|
|
|
|
|
*offset += len;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 11:15:33 -05:00
|
|
|
static int nonce_function_rfc6979_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
|
2015-07-24 15:44:49 +02:00
|
|
|
unsigned char keydata[112];
|
2017-06-22 23:31:23 -07:00
|
|
|
unsigned int offset = 0;
|
2017-09-27 15:01:26 -07:00
|
|
|
secp256k1_rfc6979_hmac_sha256 rng;
|
2015-01-25 17:32:08 +00:00
|
|
|
unsigned int i;
|
2022-01-17 04:07:16 +02:00
|
|
|
secp256k1_scalar msg;
|
|
|
|
|
unsigned char msgmod32[32];
|
|
|
|
|
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
|
|
|
|
secp256k1_scalar_get_b32(msgmod32, &msg);
|
2015-07-08 18:10:25 -04:00
|
|
|
/* We feed a byte array to the PRNG as input, consisting of:
|
2022-01-17 04:07:16 +02:00
|
|
|
* - the private key (32 bytes) and reduced message (32 bytes), see RFC 6979 3.2d.
|
2015-07-08 18:10:25 -04:00
|
|
|
* - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data.
|
2015-10-19 23:35:29 +00:00
|
|
|
* - optionally 16 extra bytes with the algorithm name.
|
|
|
|
|
* Because the arguments have distinct fixed lengths it is not possible for
|
|
|
|
|
* different argument mixtures to emulate each other and result in the same
|
|
|
|
|
* nonces.
|
2015-07-08 18:10:25 -04:00
|
|
|
*/
|
2017-06-22 23:31:23 -07:00
|
|
|
buffer_append(keydata, &offset, key32, 32);
|
2022-01-17 04:07:16 +02:00
|
|
|
buffer_append(keydata, &offset, msgmod32, 32);
|
2015-07-08 18:10:25 -04:00
|
|
|
if (data != NULL) {
|
2017-06-22 23:31:23 -07:00
|
|
|
buffer_append(keydata, &offset, data, 32);
|
2015-07-08 18:10:25 -04:00
|
|
|
}
|
2015-07-24 15:44:49 +02:00
|
|
|
if (algo16 != NULL) {
|
2017-06-22 23:31:23 -07:00
|
|
|
buffer_append(keydata, &offset, algo16, 16);
|
2015-07-24 15:44:49 +02:00
|
|
|
}
|
2025-12-17 11:15:33 -05:00
|
|
|
secp256k1_rfc6979_hmac_sha256_initialize(hash_ctx, &rng, keydata, offset);
|
2015-01-25 17:32:08 +00:00
|
|
|
for (i = 0; i <= counter; i++) {
|
2025-12-17 11:15:33 -05:00
|
|
|
secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, nonce32, 32);
|
2014-12-13 18:06:33 +01:00
|
|
|
}
|
|
|
|
|
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
2020-04-27 18:55:36 +02:00
|
|
|
|
2025-09-08 12:21:48 -04:00
|
|
|
secp256k1_memclear_explicit(keydata, sizeof(keydata));
|
2020-04-27 18:55:36 +02:00
|
|
|
secp256k1_rfc6979_hmac_sha256_clear(&rng);
|
2014-12-13 18:06:33 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 11:15:33 -05:00
|
|
|
static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
|
|
|
|
|
return nonce_function_rfc6979_impl(secp256k1_get_hash_context(secp256k1_context_static), nonce32, msg32, key32, algo16, data, counter);
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
|
|
|
|
|
const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979;
|
2014-12-13 18:06:33 +01:00
|
|
|
|
2020-12-05 23:34:14 +00:00
|
|
|
static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, secp256k1_sha256* s2c_sha, secp256k1_ecdsa_s2c_opening *s2c_opening, const unsigned char* s2c_data32, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
|
2015-09-21 20:57:54 +02:00
|
|
|
secp256k1_scalar sec, non, msg;
|
2026-04-02 18:03:37 +03:00
|
|
|
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
|
2015-08-27 03:09:23 +02:00
|
|
|
int ret = 0;
|
2019-12-17 15:56:09 +00:00
|
|
|
int is_sec_valid;
|
2020-01-11 01:01:05 +00:00
|
|
|
unsigned char nonce32[32];
|
|
|
|
|
unsigned int count = 0;
|
2020-05-27 00:37:59 +03:00
|
|
|
/* Default initialization here is important so we won't pass uninit values to the cmov in the end */
|
|
|
|
|
*r = secp256k1_scalar_zero;
|
|
|
|
|
*s = secp256k1_scalar_zero;
|
|
|
|
|
if (recid) {
|
|
|
|
|
*recid = 0;
|
|
|
|
|
}
|
2020-12-05 23:34:14 +00:00
|
|
|
/* sign-to-contract commitments only work with the default nonce function,
|
|
|
|
|
* because we need to ensure that s2c_data is actually hashed into the nonce and
|
|
|
|
|
* not just ignored. Otherwise an attacker can exfiltrate the secret key by
|
|
|
|
|
* signing the same message thrice with different commitments. */
|
2026-04-02 18:03:37 +03:00
|
|
|
VERIFY_CHECK(s2c_data32 == NULL || noncefp == NULL || noncefp == secp256k1_nonce_function_default);
|
2015-08-27 03:09:23 +02:00
|
|
|
|
|
|
|
|
/* Fail if the secret key is invalid. */
|
2019-12-17 15:56:09 +00:00
|
|
|
is_sec_valid = secp256k1_scalar_set_b32_seckey(&sec, seckey);
|
|
|
|
|
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_one, !is_sec_valid);
|
2020-01-11 01:01:05 +00:00
|
|
|
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
|
|
|
|
while (1) {
|
2019-12-17 15:56:09 +00:00
|
|
|
int is_nonce_valid;
|
2026-01-23 13:41:55 -05:00
|
|
|
|
|
|
|
|
if (noncefp == NULL) {
|
|
|
|
|
/* Use ctx-aware function by default */
|
|
|
|
|
ret = nonce_function_rfc6979_impl(secp256k1_get_hash_context(ctx), nonce32, msg32, seckey, NULL, (void*)noncedata, count);
|
|
|
|
|
} else {
|
|
|
|
|
ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-11 01:01:05 +00:00
|
|
|
if (!ret) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-12-17 15:56:09 +00:00
|
|
|
is_nonce_valid = secp256k1_scalar_set_b32_seckey(&non, nonce32);
|
2024-06-24 14:24:48 -07:00
|
|
|
/* The nonce is still secret here, but it being invalid is less likely than 1:2^255. */
|
2019-12-17 15:56:09 +00:00
|
|
|
secp256k1_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid));
|
|
|
|
|
if (is_nonce_valid) {
|
2020-12-05 23:34:14 +00:00
|
|
|
if (s2c_data32 != NULL) {
|
|
|
|
|
secp256k1_ge nonce_p;
|
|
|
|
|
|
|
|
|
|
/* Compute original nonce commitment/pubkey */
|
2026-07-02 18:43:56 +03:00
|
|
|
secp256k1_ecmult_gen_ge(&ctx->ecmult_gen_ctx, &nonce_p, &non);
|
2020-12-05 23:34:14 +00:00
|
|
|
if (s2c_opening != NULL) {
|
|
|
|
|
secp256k1_ecdsa_s2c_opening_save(s2c_opening, &nonce_p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Because the nonce is valid, the nonce point isn't the point
|
|
|
|
|
* at infinity and we can declassify that information to be able to
|
|
|
|
|
* serialize the point. */
|
|
|
|
|
secp256k1_declassify(ctx, &nonce_p.infinity, sizeof(nonce_p.infinity));
|
|
|
|
|
|
|
|
|
|
/* Tweak nonce with s2c commitment. */
|
2026-04-02 18:03:37 +03:00
|
|
|
ret = secp256k1_ec_commit_seckey(hash_ctx, &non, &nonce_p, s2c_sha, s2c_data32, 32);
|
2020-12-05 23:34:14 +00:00
|
|
|
secp256k1_declassify(ctx, &ret, sizeof(ret)); /* may be secret that the tweak falied, but happens with negligible probability */
|
|
|
|
|
if (!ret) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-27 00:37:59 +03:00
|
|
|
ret = secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, r, s, &sec, &msg, &non, recid);
|
2020-01-11 13:31:50 +00:00
|
|
|
/* The final signature is no longer a secret, nor is the fact that we were successful or not. */
|
|
|
|
|
secp256k1_declassify(ctx, &ret, sizeof(ret));
|
|
|
|
|
if (ret) {
|
2015-08-27 03:09:23 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-11 01:01:05 +00:00
|
|
|
count++;
|
2015-08-27 03:09:23 +02:00
|
|
|
}
|
2019-12-17 15:56:09 +00:00
|
|
|
/* We don't want to declassify is_sec_valid and therefore the range of
|
|
|
|
|
* seckey. As a result is_sec_valid is included in ret only after ret was
|
|
|
|
|
* used as a branching variable. */
|
|
|
|
|
ret &= is_sec_valid;
|
2025-09-08 12:21:48 -04:00
|
|
|
secp256k1_memclear_explicit(nonce32, sizeof(nonce32));
|
2020-01-11 01:01:05 +00:00
|
|
|
secp256k1_scalar_clear(&msg);
|
|
|
|
|
secp256k1_scalar_clear(&non);
|
|
|
|
|
secp256k1_scalar_clear(&sec);
|
2020-05-27 00:37:59 +03:00
|
|
|
secp256k1_scalar_cmov(r, &secp256k1_scalar_zero, !ret);
|
|
|
|
|
secp256k1_scalar_cmov(s, &secp256k1_scalar_zero, !ret);
|
|
|
|
|
if (recid) {
|
|
|
|
|
const int zero = 0;
|
|
|
|
|
secp256k1_int_cmov(recid, &zero, !ret);
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 15:53:31 +00:00
|
|
|
int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
|
2020-05-27 00:37:59 +03:00
|
|
|
secp256k1_scalar r, s;
|
|
|
|
|
int ret;
|
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
|
|
|
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
2020-12-03 15:53:31 +00:00
|
|
|
ARG_CHECK(msghash32 != NULL);
|
2020-05-27 00:37:59 +03:00
|
|
|
ARG_CHECK(signature != NULL);
|
|
|
|
|
ARG_CHECK(seckey != NULL);
|
|
|
|
|
|
2021-03-08 13:01:12 +00:00
|
|
|
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, NULL, NULL, NULL, msghash32, seckey, noncefp, noncedata);
|
2020-01-11 01:01:05 +00:00
|
|
|
secp256k1_ecdsa_signature_save(signature, &r, &s);
|
2019-12-17 15:56:09 +00:00
|
|
|
return ret;
|
2015-08-27 03:09:23 +02:00
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) {
|
|
|
|
|
secp256k1_scalar sec;
|
2015-01-25 17:32:08 +00:00
|
|
|
int ret;
|
2015-09-01 14:22:32 -04:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2015-07-18 16:29:10 -04:00
|
|
|
ARG_CHECK(seckey != NULL);
|
2015-01-25 17:32:08 +00:00
|
|
|
|
2019-12-17 15:56:09 +00:00
|
|
|
ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
|
2014-10-28 04:08:15 -07:00
|
|
|
secp256k1_scalar_clear(&sec);
|
2013-05-05 00:49:30 +02:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-12 14:43:48 +00:00
|
|
|
static int secp256k1_ec_pubkey_create_helper(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_scalar *seckey_scalar, secp256k1_ge *p, const unsigned char *seckey) {
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = secp256k1_scalar_set_b32_seckey(seckey_scalar, seckey);
|
|
|
|
|
secp256k1_scalar_cmov(seckey_scalar, &secp256k1_scalar_one, !ret);
|
|
|
|
|
|
2026-05-19 16:29:05 +02:00
|
|
|
secp256k1_ecmult_gen_ge(ecmult_gen_ctx, p, seckey_scalar);
|
2020-05-12 14:43:48 +00:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) {
|
2015-09-21 20:57:54 +02:00
|
|
|
secp256k1_ge p;
|
2020-05-12 14:43:48 +00:00
|
|
|
secp256k1_scalar seckey_scalar;
|
Eliminate multiple-returns from secp256k1.c.
Goto, multiple returns, continue, and/or multiple breaks in a
loop are often used to build complex or non-local control
flow in software.
(They're all basically the same thing, and anyone axiomatically
opposing goto and not the rest is probably cargo-culting from
the title of Dijkstra's essay without thinking hard about it.)
Personally, I think the current use of these constructs in the
code base is fine: no where are we using them to create control-
flow that couldn't easily be described in plain English, which
is hard to read or reason about, or which looks like a trap for
future developers.
Some, however, prefer a more rules based approach to software
quality. In particular, MISRA forbids all of these constructs,
and for good experience based reasons. Rules also have the
benefit of being machine checkable and surviving individual
developers.
(To be fair-- MISRA also has a process for accommodating code that
breaks the rules for good reason).
I think that in general we should also try to satisfy the rules-
based measures of software quality, except where there is an
objective reason not do: a measurable performance difference,
logic that turns to spaghetti, etc.
Changing out all the multiple returns in secp256k1.c appears to
be basically neutral: Some parts become slightly less clear,
some parts slightly more.
2015-02-17 01:01:48 -08:00
|
|
|
int ret = 0;
|
2015-09-01 14:22:32 -04:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2015-07-18 16:29:10 -04:00
|
|
|
ARG_CHECK(pubkey != NULL);
|
2015-10-30 09:16:40 +00:00
|
|
|
memset(pubkey, 0, sizeof(*pubkey));
|
|
|
|
|
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
2015-07-18 16:29:10 -04:00
|
|
|
ARG_CHECK(seckey != NULL);
|
2014-08-18 23:07:46 +02:00
|
|
|
|
2020-05-12 14:43:48 +00:00
|
|
|
ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey);
|
2020-01-11 01:01:05 +00:00
|
|
|
secp256k1_pubkey_save(pubkey, &p);
|
2020-10-20 14:53:50 +02:00
|
|
|
secp256k1_memczero(pubkey, sizeof(*pubkey), !ret);
|
2020-01-11 01:01:05 +00:00
|
|
|
|
2020-05-12 14:43:48 +00:00
|
|
|
secp256k1_scalar_clear(&seckey_scalar);
|
2015-07-13 13:09:00 +01:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-19 15:02:29 +00:00
|
|
|
int secp256k1_ec_seckey_negate(const secp256k1_context* ctx, unsigned char *seckey) {
|
2016-07-28 16:05:40 +00:00
|
|
|
secp256k1_scalar sec;
|
2019-12-17 16:52:07 +00:00
|
|
|
int ret = 0;
|
2016-07-28 16:05:40 +00:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
|
|
|
ARG_CHECK(seckey != NULL);
|
|
|
|
|
|
2019-12-17 16:52:07 +00:00
|
|
|
ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
|
|
|
|
|
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
|
2016-07-28 16:05:40 +00:00
|
|
|
secp256k1_scalar_negate(&sec, &sec);
|
|
|
|
|
secp256k1_scalar_get_b32(seckey, &sec);
|
|
|
|
|
|
2019-05-15 15:55:01 +09:00
|
|
|
secp256k1_scalar_clear(&sec);
|
2019-12-17 16:52:07 +00:00
|
|
|
return ret;
|
2016-07-28 16:05:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) {
|
|
|
|
|
int ret = 0;
|
|
|
|
|
secp256k1_ge p;
|
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
|
|
|
ARG_CHECK(pubkey != NULL);
|
|
|
|
|
|
|
|
|
|
ret = secp256k1_pubkey_load(ctx, &p, pubkey);
|
|
|
|
|
memset(pubkey, 0, sizeof(*pubkey));
|
|
|
|
|
if (ret) {
|
|
|
|
|
secp256k1_ge_neg(&p, &p);
|
|
|
|
|
secp256k1_pubkey_save(pubkey, &p);
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-12 14:43:48 +00:00
|
|
|
|
2020-12-04 14:16:43 +00:00
|
|
|
static int secp256k1_ec_seckey_tweak_add_helper(secp256k1_scalar *sec, const unsigned char *tweak32) {
|
2015-09-21 20:57:54 +02:00
|
|
|
secp256k1_scalar term;
|
2020-05-12 14:43:48 +00:00
|
|
|
int overflow = 0;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
2020-12-04 14:16:43 +00:00
|
|
|
secp256k1_scalar_set_b32(&term, tweak32, &overflow);
|
2020-05-12 14:43:48 +00:00
|
|
|
ret = (!overflow) & secp256k1_eckey_privkey_tweak_add(sec, &term);
|
|
|
|
|
secp256k1_scalar_clear(&term);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-04 14:16:43 +00:00
|
|
|
int secp256k1_ec_seckey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) {
|
2015-09-21 20:57:54 +02:00
|
|
|
secp256k1_scalar sec;
|
Eliminate multiple-returns from secp256k1.c.
Goto, multiple returns, continue, and/or multiple breaks in a
loop are often used to build complex or non-local control
flow in software.
(They're all basically the same thing, and anyone axiomatically
opposing goto and not the rest is probably cargo-culting from
the title of Dijkstra's essay without thinking hard about it.)
Personally, I think the current use of these constructs in the
code base is fine: no where are we using them to create control-
flow that couldn't easily be described in plain English, which
is hard to read or reason about, or which looks like a trap for
future developers.
Some, however, prefer a more rules based approach to software
quality. In particular, MISRA forbids all of these constructs,
and for good experience based reasons. Rules also have the
benefit of being machine checkable and surviving individual
developers.
(To be fair-- MISRA also has a process for accommodating code that
breaks the rules for good reason).
I think that in general we should also try to satisfy the rules-
based measures of software quality, except where there is an
objective reason not do: a measurable performance difference,
logic that turns to spaghetti, etc.
Changing out all the multiple returns in secp256k1.c appears to
be basically neutral: Some parts become slightly less clear,
some parts slightly more.
2015-02-17 01:01:48 -08:00
|
|
|
int ret = 0;
|
2015-09-01 14:22:32 -04:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2015-07-18 16:29:10 -04:00
|
|
|
ARG_CHECK(seckey != NULL);
|
2020-12-04 14:16:43 +00:00
|
|
|
ARG_CHECK(tweak32 != NULL);
|
2014-08-18 23:07:46 +02:00
|
|
|
|
2019-12-17 16:52:07 +00:00
|
|
|
ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
|
2020-12-04 14:16:43 +00:00
|
|
|
ret &= secp256k1_ec_seckey_tweak_add_helper(&sec, tweak32);
|
2020-01-11 01:01:05 +00:00
|
|
|
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
|
|
|
|
|
secp256k1_scalar_get_b32(seckey, &sec);
|
2014-10-27 03:27:55 -07:00
|
|
|
|
2014-10-28 04:08:15 -07:00
|
|
|
secp256k1_scalar_clear(&sec);
|
2013-05-27 01:18:48 +02:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-25 18:46:11 -04:00
|
|
|
static int secp256k1_ec_pubkey_tweak_add_helper(secp256k1_ge *p, const unsigned char *tweak32) {
|
2020-05-12 14:45:22 +00:00
|
|
|
secp256k1_scalar term;
|
|
|
|
|
int overflow = 0;
|
2020-12-04 14:16:43 +00:00
|
|
|
secp256k1_scalar_set_b32(&term, tweak32, &overflow);
|
2021-06-25 18:46:11 -04:00
|
|
|
return !overflow && secp256k1_eckey_pubkey_tweak_add(p, &term);
|
2020-05-12 14:45:22 +00:00
|
|
|
}
|
|
|
|
|
|
2020-12-04 14:16:43 +00:00
|
|
|
int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak32) {
|
2015-09-21 20:57:54 +02:00
|
|
|
secp256k1_ge p;
|
Eliminate multiple-returns from secp256k1.c.
Goto, multiple returns, continue, and/or multiple breaks in a
loop are often used to build complex or non-local control
flow in software.
(They're all basically the same thing, and anyone axiomatically
opposing goto and not the rest is probably cargo-culting from
the title of Dijkstra's essay without thinking hard about it.)
Personally, I think the current use of these constructs in the
code base is fine: no where are we using them to create control-
flow that couldn't easily be described in plain English, which
is hard to read or reason about, or which looks like a trap for
future developers.
Some, however, prefer a more rules based approach to software
quality. In particular, MISRA forbids all of these constructs,
and for good experience based reasons. Rules also have the
benefit of being machine checkable and surviving individual
developers.
(To be fair-- MISRA also has a process for accommodating code that
breaks the rules for good reason).
I think that in general we should also try to satisfy the rules-
based measures of software quality, except where there is an
objective reason not do: a measurable performance difference,
logic that turns to spaghetti, etc.
Changing out all the multiple returns in secp256k1.c appears to
be basically neutral: Some parts become slightly less clear,
some parts slightly more.
2015-02-17 01:01:48 -08:00
|
|
|
int ret = 0;
|
2015-09-01 14:22:32 -04:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2015-07-18 16:29:10 -04:00
|
|
|
ARG_CHECK(pubkey != NULL);
|
2020-12-04 14:16:43 +00:00
|
|
|
ARG_CHECK(tweak32 != NULL);
|
2014-08-18 23:07:46 +02:00
|
|
|
|
2020-05-12 14:45:22 +00:00
|
|
|
ret = secp256k1_pubkey_load(ctx, &p, pubkey);
|
2015-10-21 04:17:05 +00:00
|
|
|
memset(pubkey, 0, sizeof(*pubkey));
|
2021-06-25 18:46:11 -04:00
|
|
|
ret = ret && secp256k1_ec_pubkey_tweak_add_helper(&p, tweak32);
|
2015-10-21 04:17:05 +00:00
|
|
|
if (ret) {
|
2020-05-12 14:45:22 +00:00
|
|
|
secp256k1_pubkey_save(pubkey, &p);
|
2013-07-14 17:43:13 +02:00
|
|
|
}
|
2014-10-27 03:27:55 -07:00
|
|
|
|
2013-07-14 17:43:13 +02:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-04 14:16:43 +00:00
|
|
|
int secp256k1_ec_seckey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) {
|
2015-09-21 20:57:54 +02:00
|
|
|
secp256k1_scalar factor;
|
|
|
|
|
secp256k1_scalar sec;
|
Eliminate multiple-returns from secp256k1.c.
Goto, multiple returns, continue, and/or multiple breaks in a
loop are often used to build complex or non-local control
flow in software.
(They're all basically the same thing, and anyone axiomatically
opposing goto and not the rest is probably cargo-culting from
the title of Dijkstra's essay without thinking hard about it.)
Personally, I think the current use of these constructs in the
code base is fine: no where are we using them to create control-
flow that couldn't easily be described in plain English, which
is hard to read or reason about, or which looks like a trap for
future developers.
Some, however, prefer a more rules based approach to software
quality. In particular, MISRA forbids all of these constructs,
and for good experience based reasons. Rules also have the
benefit of being machine checkable and surviving individual
developers.
(To be fair-- MISRA also has a process for accommodating code that
breaks the rules for good reason).
I think that in general we should also try to satisfy the rules-
based measures of software quality, except where there is an
objective reason not do: a measurable performance difference,
logic that turns to spaghetti, etc.
Changing out all the multiple returns in secp256k1.c appears to
be basically neutral: Some parts become slightly less clear,
some parts slightly more.
2015-02-17 01:01:48 -08:00
|
|
|
int ret = 0;
|
2015-01-25 17:32:08 +00:00
|
|
|
int overflow = 0;
|
2015-09-01 14:22:32 -04:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2015-07-18 16:29:10 -04:00
|
|
|
ARG_CHECK(seckey != NULL);
|
2020-12-04 14:16:43 +00:00
|
|
|
ARG_CHECK(tweak32 != NULL);
|
2014-08-18 23:07:46 +02:00
|
|
|
|
2020-12-04 14:16:43 +00:00
|
|
|
secp256k1_scalar_set_b32(&factor, tweak32, &overflow);
|
2019-12-17 16:52:07 +00:00
|
|
|
ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
|
|
|
|
|
ret &= (!overflow) & secp256k1_eckey_privkey_tweak_mul(&sec, &factor);
|
2020-01-11 01:01:05 +00:00
|
|
|
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
|
|
|
|
|
secp256k1_scalar_get_b32(seckey, &sec);
|
2014-10-27 03:27:55 -07:00
|
|
|
|
2014-10-28 04:08:15 -07:00
|
|
|
secp256k1_scalar_clear(&sec);
|
|
|
|
|
secp256k1_scalar_clear(&factor);
|
2013-07-14 17:43:13 +02:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-04 14:16:43 +00:00
|
|
|
int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak32) {
|
2015-09-21 20:57:54 +02:00
|
|
|
secp256k1_ge p;
|
|
|
|
|
secp256k1_scalar factor;
|
Eliminate multiple-returns from secp256k1.c.
Goto, multiple returns, continue, and/or multiple breaks in a
loop are often used to build complex or non-local control
flow in software.
(They're all basically the same thing, and anyone axiomatically
opposing goto and not the rest is probably cargo-culting from
the title of Dijkstra's essay without thinking hard about it.)
Personally, I think the current use of these constructs in the
code base is fine: no where are we using them to create control-
flow that couldn't easily be described in plain English, which
is hard to read or reason about, or which looks like a trap for
future developers.
Some, however, prefer a more rules based approach to software
quality. In particular, MISRA forbids all of these constructs,
and for good experience based reasons. Rules also have the
benefit of being machine checkable and surviving individual
developers.
(To be fair-- MISRA also has a process for accommodating code that
breaks the rules for good reason).
I think that in general we should also try to satisfy the rules-
based measures of software quality, except where there is an
objective reason not do: a measurable performance difference,
logic that turns to spaghetti, etc.
Changing out all the multiple returns in secp256k1.c appears to
be basically neutral: Some parts become slightly less clear,
some parts slightly more.
2015-02-17 01:01:48 -08:00
|
|
|
int ret = 0;
|
2015-01-25 17:32:08 +00:00
|
|
|
int overflow = 0;
|
2015-09-01 14:22:32 -04:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2015-07-18 16:29:10 -04:00
|
|
|
ARG_CHECK(pubkey != NULL);
|
2020-12-04 14:16:43 +00:00
|
|
|
ARG_CHECK(tweak32 != NULL);
|
2014-08-18 23:07:46 +02:00
|
|
|
|
2020-12-04 14:16:43 +00:00
|
|
|
secp256k1_scalar_set_b32(&factor, tweak32, &overflow);
|
2015-10-21 04:17:05 +00:00
|
|
|
ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey);
|
|
|
|
|
memset(pubkey, 0, sizeof(*pubkey));
|
|
|
|
|
if (ret) {
|
2021-06-25 18:46:11 -04:00
|
|
|
if (secp256k1_eckey_pubkey_tweak_mul(&p, &factor)) {
|
2015-07-20 13:36:55 -04:00
|
|
|
secp256k1_pubkey_save(pubkey, &p);
|
|
|
|
|
} else {
|
2015-10-21 04:17:05 +00:00
|
|
|
ret = 0;
|
Eliminate multiple-returns from secp256k1.c.
Goto, multiple returns, continue, and/or multiple breaks in a
loop are often used to build complex or non-local control
flow in software.
(They're all basically the same thing, and anyone axiomatically
opposing goto and not the rest is probably cargo-culting from
the title of Dijkstra's essay without thinking hard about it.)
Personally, I think the current use of these constructs in the
code base is fine: no where are we using them to create control-
flow that couldn't easily be described in plain English, which
is hard to read or reason about, or which looks like a trap for
future developers.
Some, however, prefer a more rules based approach to software
quality. In particular, MISRA forbids all of these constructs,
and for good experience based reasons. Rules also have the
benefit of being machine checkable and surviving individual
developers.
(To be fair-- MISRA also has a process for accommodating code that
breaks the rules for good reason).
I think that in general we should also try to satisfy the rules-
based measures of software quality, except where there is an
objective reason not do: a measurable performance difference,
logic that turns to spaghetti, etc.
Changing out all the multiple returns in secp256k1.c appears to
be basically neutral: Some parts become slightly less clear,
some parts slightly more.
2015-02-17 01:01:48 -08:00
|
|
|
}
|
2013-05-27 01:18:48 +02:00
|
|
|
}
|
2014-10-27 03:27:55 -07:00
|
|
|
|
2013-05-27 01:18:48 +02:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-21 20:57:54 +02:00
|
|
|
int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) {
|
2015-09-01 14:22:32 -04:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2022-12-07 14:50:14 +01:00
|
|
|
ARG_CHECK(secp256k1_context_is_proper(ctx));
|
|
|
|
|
|
2019-01-27 13:17:37 +01:00
|
|
|
if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) {
|
2025-12-17 11:15:33 -05:00
|
|
|
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, secp256k1_get_hash_context(ctx), seed32);
|
2019-01-27 13:17:37 +01:00
|
|
|
}
|
2015-04-15 21:35:50 +00:00
|
|
|
return 1;
|
|
|
|
|
}
|
2015-06-29 15:06:28 -05:00
|
|
|
|
2015-10-31 19:04:34 +00:00
|
|
|
int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, size_t n) {
|
|
|
|
|
size_t i;
|
2015-09-21 20:57:54 +02:00
|
|
|
secp256k1_gej Qj;
|
|
|
|
|
secp256k1_ge Q;
|
2015-07-24 15:44:49 +02:00
|
|
|
|
2020-07-30 12:26:28 +03:00
|
|
|
VERIFY_CHECK(ctx != NULL);
|
2015-07-24 15:44:49 +02:00
|
|
|
ARG_CHECK(pubnonce != NULL);
|
2015-10-31 09:52:30 +00:00
|
|
|
memset(pubnonce, 0, sizeof(*pubnonce));
|
2015-07-24 15:44:49 +02:00
|
|
|
ARG_CHECK(n >= 1);
|
|
|
|
|
ARG_CHECK(pubnonces != NULL);
|
|
|
|
|
|
|
|
|
|
secp256k1_gej_set_infinity(&Qj);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
2020-07-30 12:26:28 +03:00
|
|
|
ARG_CHECK(pubnonces[i] != NULL);
|
2015-07-24 15:44:49 +02:00
|
|
|
secp256k1_pubkey_load(ctx, &Q, pubnonces[i]);
|
|
|
|
|
secp256k1_gej_add_ge(&Qj, &Qj, &Q);
|
|
|
|
|
}
|
|
|
|
|
if (secp256k1_gej_is_infinity(&Qj)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
secp256k1_ge_set_gej(&Q, &Qj);
|
|
|
|
|
secp256k1_pubkey_save(pubnonce, &Q);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-15 20:58:01 +00:00
|
|
|
int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32, const unsigned char *tag, size_t taglen, const unsigned char *msg, size_t msglen) {
|
|
|
|
|
secp256k1_sha256 sha;
|
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
|
|
|
ARG_CHECK(hash32 != NULL);
|
|
|
|
|
ARG_CHECK(tag != NULL);
|
|
|
|
|
ARG_CHECK(msg != NULL);
|
|
|
|
|
|
2025-12-17 11:15:33 -05:00
|
|
|
secp256k1_sha256_initialize_tagged(secp256k1_get_hash_context(ctx), &sha, tag, taglen);
|
|
|
|
|
secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &sha, msg, msglen);
|
|
|
|
|
secp256k1_sha256_finalize(secp256k1_get_hash_context(ctx), &sha, hash32);
|
2020-04-27 18:55:36 +02:00
|
|
|
secp256k1_sha256_clear(&sha);
|
2021-01-15 20:58:01 +00:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 11:26:44 +00:00
|
|
|
/* Outputs 33 zero bytes if the given group element is the point at infinity and
|
|
|
|
|
* otherwise outputs the compressed serialization */
|
|
|
|
|
static void secp256k1_ge_serialize_ext(unsigned char *out33, secp256k1_ge* ge) {
|
|
|
|
|
if (secp256k1_ge_is_infinity(ge)) {
|
|
|
|
|
memset(out33, 0, 33);
|
|
|
|
|
} else {
|
2026-03-02 16:40:12 +02:00
|
|
|
secp256k1_eckey_pubkey_serialize33(ge, out33);
|
2023-04-19 11:26:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Outputs the point at infinity if the given byte array is all zero, otherwise
|
|
|
|
|
* attempts to parse compressed point serialization. */
|
|
|
|
|
static int secp256k1_ge_parse_ext(secp256k1_ge* ge, const unsigned char *in33) {
|
|
|
|
|
unsigned char zeros[33] = { 0 };
|
|
|
|
|
|
2023-10-12 11:18:21 +00:00
|
|
|
if (secp256k1_memcmp_var(in33, zeros, sizeof(zeros)) == 0) {
|
2023-04-19 11:26:44 +00:00
|
|
|
secp256k1_ge_set_infinity(ge);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return secp256k1_eckey_pubkey_parse(ge, in33, 33);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-06 13:53:02 -08:00
|
|
|
#ifdef ENABLE_MODULE_BPPP
|
|
|
|
|
# include "modules/bppp/main_impl.h"
|
2022-08-27 15:02:44 +00:00
|
|
|
#endif
|
|
|
|
|
|
2015-06-29 15:06:28 -05:00
|
|
|
#ifdef ENABLE_MODULE_ECDH
|
|
|
|
|
# include "modules/ecdh/main_impl.h"
|
|
|
|
|
#endif
|
2015-07-24 15:44:49 +02:00
|
|
|
|
2015-08-27 03:42:57 +02:00
|
|
|
#ifdef ENABLE_MODULE_RECOVERY
|
|
|
|
|
# include "modules/recovery/main_impl.h"
|
|
|
|
|
#endif
|
2020-05-12 13:58:47 +00:00
|
|
|
|
|
|
|
|
#ifdef ENABLE_MODULE_EXTRAKEYS
|
|
|
|
|
# include "modules/extrakeys/main_impl.h"
|
|
|
|
|
#endif
|
2020-05-12 21:19:03 +00:00
|
|
|
|
|
|
|
|
#ifdef ENABLE_MODULE_SCHNORRSIG
|
|
|
|
|
# include "modules/schnorrsig/main_impl.h"
|
|
|
|
|
#endif
|
2022-11-04 16:18:40 -04:00
|
|
|
|
2024-01-06 19:31:18 +00:00
|
|
|
#ifdef ENABLE_MODULE_MUSIG
|
|
|
|
|
# include "modules/musig/main_impl.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-11-26 16:44:23 +01:00
|
|
|
#ifdef ENABLE_MODULE_SCHNORRSIG_HALFAGG
|
|
|
|
|
# include "modules/schnorrsig_halfagg/main_impl.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-11-04 16:18:40 -04:00
|
|
|
#ifdef ENABLE_MODULE_ELLSWIFT
|
|
|
|
|
# include "modules/ellswift/main_impl.h"
|
|
|
|
|
#endif
|
2023-07-26 15:19:08 +00:00
|
|
|
|
2020-12-05 23:18:54 +00:00
|
|
|
#ifdef ENABLE_MODULE_ECDSA_S2C
|
|
|
|
|
# include "modules/ecdsa_s2c/main_impl.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-03-04 23:38:48 -08:00
|
|
|
#ifdef ENABLE_MODULE_ECDSA_ADAPTOR
|
|
|
|
|
# include "modules/ecdsa_adaptor/main_impl.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-07-07 00:47:41 +02:00
|
|
|
#ifdef ENABLE_MODULE_GENERATOR
|
|
|
|
|
# include "modules/generator/main_impl.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
Pedersen commitments, borromean ring signatures, and ZK range proofs.
This commit adds three new cryptosystems to libsecp256k1:
Pedersen commitments are a system for making blinded commitments
to a value. Functionally they work like:
commit_b,v = H(blind_b || value_v),
except they are additively homorphic, e.g.
C(b1, v1) - C(b2, v2) = C(b1 - b2, v1 - v2) and
C(b1, v1) - C(b1, v1) = 0, etc.
The commitments themselves are EC points, serialized as 33 bytes.
In addition to the commit function this implementation includes
utility functions for verifying that a set of commitments sums
to zero, and for picking blinding factors that sum to zero.
If the blinding factors are uniformly random, pedersen commitments
have information theoretic privacy.
Borromean ring signatures are a novel efficient ring signature
construction for AND/OR admissions policies (the code here implements
an AND of ORs, each of any size). This construction requires
32 bytes of signature per pubkey used plus 32 bytes of constant
overhead. With these you can construct signatures like "Given pubkeys
A B C D E F G, the signer knows the discrete logs
satisifying (A || B) & (C || D || E) & (F || G)".
ZK range proofs allow someone to prove a pedersen commitment is in
a particular range (e.g. [0..2^64)) without revealing the specific
value. The construction here is based on the above borromean
ring signature and uses a radix-4 encoding and other optimizations
to maximize efficiency. It also supports encoding proofs with a
non-private base-10 exponent and minimum-value to allow trading
off secrecy for size and speed (or just avoiding wasting space
keeping data private that was already public due to external
constraints).
A proof for a 32-bit mantissa takes 2564 bytes, but 2048 bytes of
this can be used to communicate a private message to a receiver
who shares a secret random seed with the prover.
Also: get rid of precomputed H tables (Pieter Wuille)
2015-08-05 19:04:14 +02:00
|
|
|
#ifdef ENABLE_MODULE_RANGEPROOF
|
|
|
|
|
# include "modules/rangeproof/main_impl.h"
|
|
|
|
|
#endif
|
2016-04-21 22:22:39 +00:00
|
|
|
|
|
|
|
|
#ifdef ENABLE_MODULE_WHITELIST
|
|
|
|
|
# include "modules/whitelist/main_impl.h"
|
|
|
|
|
#endif
|
2016-07-01 15:51:07 +00:00
|
|
|
|
|
|
|
|
#ifdef ENABLE_MODULE_SURJECTIONPROOF
|
|
|
|
|
# include "modules/surjection/main_impl.h"
|
|
|
|
|
#endif
|
2026-08-31 00:05:16 +02:00
|
|
|
|
|
|
|
|
#ifdef ENABLE_MODULE_FROST
|
|
|
|
|
# include "modules/frost/main_impl.h"
|
|
|
|
|
#endif
|
chilldkg: Phase 0 - module scaffolding and build wiring
Add an empty, experimental `chilldkg` module as the foundation for a
ChillDKG implementation (distributed key generation for FROST) per the
bip-frost-dkg BIP draft (v0.3.0-dev):
https://github.com/BlockstreamResearch/bip-frost-dkg
The module lives in src/modules/chilldkg/ (separate from the frost
module, per the implementation plan in .idea/docs/
chilldkg-implementation-plan.md: FROST signing (BIP 445) and ChillDKG
are separate BIPs with separate reference repos, test vectors and
review cycles; the dependency between them is one-way bytes).
New files:
- include/secp256k1_chilldkg.h: public header skeleton with the same
"EXTREMELY DANGEROUS / work in progress" warning style as
secp256k1_frost.h, plus a note that the BIP is a draft and tagged
hashes/wire formats may change. No API yet (Phase 3+).
- src/modules/chilldkg/main_impl.h: implementation skeleton including
the public header.
- src/modules/chilldkg/tests_impl.h: trivial scaffolding unit test
(chilldkg_scaffolding_test) registered via the tests_chilldkg[]
CASE1 array used by this repo's unit-test framework.
- src/modules/chilldkg/Makefile.am.include: autotools file list,
mirroring the frost module's.
- src/modules/chilldkg/chilldkg.md: module doc stub (purpose, draft
status, dependency on the schnorrsig and ecdh modules).
Build wiring (mirrors the frost module exactly):
- configure.ac: --enable-module-chilldkg (default no, experimental
gate), dependency errors when schnorrsig or ecdh are explicitly
disabled, AM_CONDITIONAL(ENABLE_MODULE_CHILLDKG), summary line.
- Makefile.am: include src/modules/chilldkg/Makefile.am.include under
ENABLE_MODULE_CHILLDKG.
- src/secp256k1.c: guarded include of modules/chilldkg/main_impl.h
after the frost module.
- src/tests.c: guarded include of tests_impl.h and
MAKE_TEST_MODULE(chilldkg) registration.
- CMakeLists.txt: SECP256K1_ENABLE_MODULE_CHILLDKG option (OFF) +
summary line.
- src/CMakeLists.txt: dependency checks on
SECP256K1_ENABLE_MODULE_SCHNORRSIG and SECP256K1_ENABLE_MODULE_ECDH,
ENABLE_MODULE_CHILLDKG=1 compile definition, public header export.
Verified:
- ./autogen.sh && ./configure --enable-experimental
--enable-module-chilldkg --enable-module-schnorrsig
--enable-module-ecdh && make check: PASS 3/3 (tests, noverify_tests,
exhaustive_tests).
- configure fails with a clear error when schnorrsig or ecdh are
disabled, or when experimental is not enabled.
- CMake build with SECP256K1_ENABLE_MODULE_CHILLDKG=ON: ctest 345/345
passed; dependency errors fire correctly when schnorrsig/ecdh OFF.
2026-08-31 01:37:22 +02:00
|
|
|
|
|
|
|
|
#ifdef ENABLE_MODULE_CHILLDKG
|
|
|
|
|
# include "modules/chilldkg/main_impl.h"
|
|
|
|
|
#endif
|
iceberg: add the Iceberg threshold-MuSig module
Port the experimental Iceberg module from the benchmark-iceberg tree
(github.com/furszy/benchmark-iceberg, sources/secp256k1-kmp/native/
secp256k1) into this repo.
Iceberg is a threshold scheme that lets a group of parties stand in
for a single MuSig2 (BIP 327) participant: the group produces one
ordinary MuSig2 public nonce and one ordinary MuSig2 partial
signature, so cosigners cannot tell a group is involved and need no
changes. Nonces are derived from a caller-chosen per-session label
(sid32) rather than stored, so no signer holds a secret nonce between
rounds; labels are public but must never be reused. A quorum of 2t-1
members (of whom up to t-1 may be corrupt) is needed in each round,
so the threshold is at most half the group rounded up; combined with
the scheme's other constraints the smallest usable group is 2-of-4.
See doc/iceberg.md and the module header for the full usage notes.
Module layout (src/modules/iceberg/, layered bottom-up, each layer
may only use the ones above it -- that ordering is also the
constant-time story):
- scalar_poly.{h,_impl.h}: secret-carrying polynomial arithmetic,
keeping secrets away from inversions (documented in the header).
- rss.{h,_impl.h}: replicated secret sharing evaluation.
- vpss.{h,_impl.h}: verifiable public shares; variable-time by
design, sees only participant indices and published points.
- keygen_impl.h: distributed key generation producing one share per
member.
- session_impl.h: nonce_gen/nonce_agg and partial_sign/
partial_sig_agg producing plain MuSig2 objects.
- tests_impl.h: 28 tests including the shipped vectors.h vector
suite and dealer known-answer tests.
- bench_impl.h: benchmark definitions (wired in a follow-up commit).
Public headers: include/secp256k1_iceberg.h (installed) and
include/secp256k1_iceberg_dealer.h (in-tree only: a trusted dealer is
not part of the shipped API, but tests, benchmarks and the example
need to deal shares).
Content adaptations relative to the source tree (the only changes to
the ported code): three secp256k1_musig_nonce_process call sites in
tests_impl.h gained a NULL adaptor argument, because this repo's
musig is the zkp variant whose public nonce_process takes an optional
adaptor point. All musig internals the module uses (ge_parse_ext,
ge_serialize_ext, keyaggcoef, aggnonce_load, pubnonce_save,
partial_sig_save, nonce_process_internal) are identical in both
trees, as are all core headers the module touches; nothing else
needed adaptation.
Build wiring mirrors the chilldkg module:
- configure.ac: --enable-module-iceberg (default no, experimental
gate), hard dependency on the musig module with a configure error
if musig is explicitly disabled (musig itself pulls in schnorrsig),
AM_CONDITIONAL(ENABLE_MODULE_ICEBERG), summary line.
- Makefile.am: include src/modules/iceberg/Makefile.am.include under
the conditional.
- src/secp256k1.c: guarded include of modules/iceberg/main_impl.h
after the chilldkg block (musig is included earlier, so its
internals are in scope).
- src/tests.c: module test registration via MAKE_TEST_MODULE(iceberg).
- CMakeLists.txt / src/CMakeLists.txt: SECP256K1_ENABLE_MODULE_ICEBERG
option (OFF) with a dependency check on SECP256K1_ENABLE_MODULE_MUSIG
(placed before the musig block so the force-enable takes effect),
ENABLE_MODULE_ICEBERG=1 compile definition, public header export,
summary line.
Verified: ./configure --enable-experimental --enable-module-iceberg
&& make check passes; ./tests --target=iceberg runs the full module
suite (28/28); CMake build + ctest pass; the musig dependency error
fires correctly in both build systems.
2026-08-31 12:24:48 +02:00
|
|
|
|
prefractal: add the nested FROST+MuSig2 module (API, implementation, wiring)
Adds `prefractal`, an experimental module that lets a FROST t-of-n group
occupy ONE participant slot of an ordinary MuSig2 (BIP 327) session. Each
member computes
s_i = k1_i + b_frost*b_musig*k2_i + e*a*lambda_i*g*gacc*d_i
and the group publishes one ordinary MuSig2 public nonce and one ordinary
MuSig2 partial signature, so cosigners need no support for it and cannot tell
a group is involved.
Four public functions, all sessionless (every call takes its session
parameters explicitly, so there are no new opaque types, magics or *_SIZE
constants to keep synchronised):
secp256k1_prefractal_nonce_agg group wire nonce + unscaled aggnonce
secp256k1_prefractal_sign one member's partial signature
secp256k1_prefractal_partial_sig_verify identifiable abort
secp256k1_prefractal_partial_sig_agg sum -> musig partial signature
Three deliberate deviations from BIP 445, all documented in the public header:
1. b_frost does not commit to the message. The target protocols publish the
group's wire nonce before the message exists, so a message-committing
coefficient could not be computed in round one and rebuilt later. The outer
b_musig does commit to the message and multiplies this one, so the product
still binds it. Same trade the iceberg module makes, for the same reason.
The preimage is BIP 445's with the message dropped and the group key
carried in full rather than x-only, since it is used as a full point
downstream.
2. There is NO g_frost factor. Stock FROST normalises its threshold key to
even Y (g_times_gacc_parity = gacc_parity ^ pk_odd, frost/session_impl.h
:664) because it produces a BIP 340 x-only signature. Here the threshold
key is an inner participant of the outer key aggregation and is used as a
full point, so all key-side parity normalisation happens once, at the
aggregate level, off the OUTER keyagg cache. Note this is NOT implied by
the tweak cache being the identity: with an identity cache g_frost is still
-1 for every odd-Y group key, i.e. about half of them. Importing frost's
key-side parity here would yield a signer that works for even-Y groups and
fails for odd-Y ones.
3. The FROST tweak cache must be the identity (tacc == 0, gacc_parity == 0).
Checked in sign and partial_sig_verify, not only in partial_sig_agg, so the
key a member signs under is tied to the cache that was validated; sign and
verify additionally require thresh_pk to equal the cache's own key so the
two arguments cannot disagree.
The verification equation lives in one helper used both by sign's BIP 445
self-check and by partial_sig_verify, so the two cannot drift apart.
Build wiring. Three files order their module blocks differently and the
constraints point in opposite directions:
- src/secp256k1.c: the include goes AFTER frost and musig, because the
module calls their static internals.
- src/CMakeLists.txt: the block goes BEFORE both, because its set() calls
are only observed by blocks that run later.
- configure.ac: the block likewise goes before the musig block, NOT at
iceberg's position further down. configure.ac orders musig and frost ahead
of iceberg, and iceberg's late enable_module_musig=yes is harmless only
because musig defaults to yes. frost defaults to no, so a late
force-enable would leave -DENABLE_MODULE_FROST=1 unemitted while
AM_CONDITIONAL still observed the mutation - a library whose secp256k1.c
never included frost, built alongside frost's own sources.
frost is also the first default-OFF module anything depends on, which breaks
the dependency-guard idiom used everywhere else in both build systems: the
existing "DEFINED X AND NOT X" (CMake) and "x$X = xno" (autotools) tests read
as "the user disabled it explicitly" only for default-ON modules, and are true
by default for a default-OFF one. Since neither build system can distinguish
an explicit disable from the default once both are in the cache, enabling
prefractal simply implies frost; the guard is kept for musig, where it still
means what it says. The CMake block additionally lifts both dependencies into
the parent scope so the top-level configuration summary reports what was
actually built rather than printing "frost OFF" while compiling frost in.
Verified on both build systems:
cmake -B build -DSECP256K1_ENABLE_MODULE_PREFRACTAL=ON -DSECP256K1_BUILD_TESTS=ON
-> musig/frost/prefractal all ON, tests pass, 4 prefractal symbols exported
cmake -B build -DSECP256K1_BUILD_TESTS=ON
-> prefractal OFF, default build unchanged, tests pass
./configure --enable-experimental --enable-module-prefractal && make && make check
-> frost=yes forced on, -DENABLE_MODULE_FROST=1 emitted, 3/3 pass
./configure --enable-module-prefractal
-> correctly refused: "Prefractal module is experimental"
tests_impl.h is a placeholder here so the module links; the real suite lands
next.
2026-09-04 00:44:43 +02:00
|
|
|
#ifdef ENABLE_MODULE_PREFRACTAL
|
|
|
|
|
# include "modules/prefractal/main_impl.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
build: wire the frost_enrollment module into both build systems
Second of six commits adding the frost_enrollment module. This one is
scaffolding only: the five entry points are stubs that validate their
pointer arguments, zero their outputs and return 0. What is being
verified here is that the module configures, compiles, links, exports
its symbols and registers its test module in both build systems -- so
that the next commit changes nothing but arithmetic.
Ordering is the one thing in this commit that can go silently wrong, and
it goes wrong in opposite directions in the two build systems:
- configure.ac executes its `if` blocks in file order, and
enable_module_frost defaults to no (configure.ac:243). A block placed
after the frost block at :601 that sets enable_module_frost=yes flips
the variable too late: AM_CONDITIONAL goes true, so the header is
installed and the Makefile fragment is pulled in, but
-DENABLE_MODULE_FROST=1 is never appended, so src/secp256k1.c never
includes frost's implementation and every secp256k1_frost_* symbol
fails to link. The new block therefore goes ahead of both the frost
block and prefractal's, which documents the same trap.
- src/CMakeLists.txt processes dependents FIRST, so the same block goes
above the FROST block there, beside prefractal's.
Verified rather than assumed: configuring with ONLY
--enable-module-frost-enrollment emits -DENABLE_MODULE_FROST=1
alongside -DENABLE_MODULE_FROST_ENROLLMENT=1, and the CMake summary
prints "frost ON" for the same configuration -- the latter is what the
PARENT_SCOPE lift buys, since the summary runs after
add_subdirectory(src) and would otherwise report a module it is
compiling in as OFF.
The dependency guard is prefractal's implies-frost idiom, copied
verbatim along with its reasoning. frost is default-OFF, so the
`test x"$enable_module_frost" = x"no"` / `DEFINED X AND NOT X` guard
every other module uses -- which reads as "the user disabled it
explicitly" for a default-ON dependency -- is true by default here and
cannot tell an explicit --disable-module-frost from the default once
both are in the cache. Enabling frost-enrollment simply implies frost,
with no error.
The one frost-module change in the whole series is in this commit:
src/modules/frost/session.h gains a declaration for
secp256k1_frost_sort_ids, which is defined at session_impl.h:517 and
declared nowhere. The params hash needs it to canonicalize identifier
order. Prefractal reaches frost's statics through translation-unit
ordering alone; rather than inherit reuse-by-link-order, this declares
the function where keygen.h:48 already declares derive_pubshare_at, so
the reuse goes through an interface. No behavior change: it is a
declaration for an existing static definition in the same TU.
CI wiring is two files, and skipping either half fails quietly:
- ci/ci.sh gets FROST_ENROLLMENT in the reproduction header's variable
list and --enable-module-frost-enrollment="$FROST_ENROLLMENT" after
the prefractal line.
- .github/workflows/ci.yml gets FROST_ENROLLMENT at every PREFRACTAL
site: the global default, 11 inline matrix entries and 10 job-level
env blocks. Without the default, ci.sh runs under set -eux with an
empty $FROST_ENROLLMENT, passes --enable-module-frost-enrollment="",
`test x"" = x"yes"` is false, and the module is off in all of CI while
ci.sh visibly has the plumbing.
Verified programmatically over the parsed workflow: across the 106
effective job contexts, PREFRACTAL and FROST_ENROLLMENT now agree in
every single one (45 set to yes, no mismatches), no context sets
FROST_ENROLLMENT without FROST or without EXPERIMENTAL, and no context
leaves it undefined. ci.sh passes sh -n.
The stub test is not a placeholder that has to be deleted later: every
entry point must reject an empty helper set and leave its output zeroed,
which is true of the stubs and stays true of the finished
implementation, so it doubles as the check that all five symbols are
reachable from the test binary.
Verification. Autotools: ./autogen.sh, then a frost-enrollment-only
configure and a full configure with frost, chilldkg, iceberg, prefractal
and frost-enrollment all on -- both build with zero warnings under the
project's -Werror-grade flag set, ./tests and ./exhaustive_tests exit 0,
and `./tests -l` lists the frost_enrollment module. CMake: configure with
-DSECP256K1_EXPERIMENTAL=ON -DSECP256K1_ENABLE_MODULE_FROST_ENROLLMENT=ON
builds clean and ctest passes 391 tests. nm shows the five new symbols
exported from libsecp256k1.so; tools/symbol-check.py could not be run
here because python3-lief is not installed in this environment, but all
five carry the required secp256k1_ prefix. make dist succeeds and the
tarball carries src/modules/frost_enrollment/frost_enrollment.md
alongside the other module documents.
One unrelated observation from this build: a stale
src/ctime_tests-ctime_tests.o left over from an earlier configure with a
different module set will fail to link, because automake does not track
CPPFLAGS changes across reconfigures. make clean between configurations
with different module sets, not a fault in this change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 03:53:03 +02:00
|
|
|
/* Must follow the frost include above: this module calls frost's static
|
|
|
|
|
* internals in place rather than duplicating them. */
|
|
|
|
|
#ifdef ENABLE_MODULE_FROST_ENROLLMENT
|
|
|
|
|
# include "modules/frost_enrollment/main_impl.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
iceberg: add the Iceberg threshold-MuSig module
Port the experimental Iceberg module from the benchmark-iceberg tree
(github.com/furszy/benchmark-iceberg, sources/secp256k1-kmp/native/
secp256k1) into this repo.
Iceberg is a threshold scheme that lets a group of parties stand in
for a single MuSig2 (BIP 327) participant: the group produces one
ordinary MuSig2 public nonce and one ordinary MuSig2 partial
signature, so cosigners cannot tell a group is involved and need no
changes. Nonces are derived from a caller-chosen per-session label
(sid32) rather than stored, so no signer holds a secret nonce between
rounds; labels are public but must never be reused. A quorum of 2t-1
members (of whom up to t-1 may be corrupt) is needed in each round,
so the threshold is at most half the group rounded up; combined with
the scheme's other constraints the smallest usable group is 2-of-4.
See doc/iceberg.md and the module header for the full usage notes.
Module layout (src/modules/iceberg/, layered bottom-up, each layer
may only use the ones above it -- that ordering is also the
constant-time story):
- scalar_poly.{h,_impl.h}: secret-carrying polynomial arithmetic,
keeping secrets away from inversions (documented in the header).
- rss.{h,_impl.h}: replicated secret sharing evaluation.
- vpss.{h,_impl.h}: verifiable public shares; variable-time by
design, sees only participant indices and published points.
- keygen_impl.h: distributed key generation producing one share per
member.
- session_impl.h: nonce_gen/nonce_agg and partial_sign/
partial_sig_agg producing plain MuSig2 objects.
- tests_impl.h: 28 tests including the shipped vectors.h vector
suite and dealer known-answer tests.
- bench_impl.h: benchmark definitions (wired in a follow-up commit).
Public headers: include/secp256k1_iceberg.h (installed) and
include/secp256k1_iceberg_dealer.h (in-tree only: a trusted dealer is
not part of the shipped API, but tests, benchmarks and the example
need to deal shares).
Content adaptations relative to the source tree (the only changes to
the ported code): three secp256k1_musig_nonce_process call sites in
tests_impl.h gained a NULL adaptor argument, because this repo's
musig is the zkp variant whose public nonce_process takes an optional
adaptor point. All musig internals the module uses (ge_parse_ext,
ge_serialize_ext, keyaggcoef, aggnonce_load, pubnonce_save,
partial_sig_save, nonce_process_internal) are identical in both
trees, as are all core headers the module touches; nothing else
needed adaptation.
Build wiring mirrors the chilldkg module:
- configure.ac: --enable-module-iceberg (default no, experimental
gate), hard dependency on the musig module with a configure error
if musig is explicitly disabled (musig itself pulls in schnorrsig),
AM_CONDITIONAL(ENABLE_MODULE_ICEBERG), summary line.
- Makefile.am: include src/modules/iceberg/Makefile.am.include under
the conditional.
- src/secp256k1.c: guarded include of modules/iceberg/main_impl.h
after the chilldkg block (musig is included earlier, so its
internals are in scope).
- src/tests.c: module test registration via MAKE_TEST_MODULE(iceberg).
- CMakeLists.txt / src/CMakeLists.txt: SECP256K1_ENABLE_MODULE_ICEBERG
option (OFF) with a dependency check on SECP256K1_ENABLE_MODULE_MUSIG
(placed before the musig block so the force-enable takes effect),
ENABLE_MODULE_ICEBERG=1 compile definition, public header export,
summary line.
Verified: ./configure --enable-experimental --enable-module-iceberg
&& make check passes; ./tests --target=iceberg runs the full module
suite (28/28); CMake build + ctest pass; the musig dependency error
fires correctly in both build systems.
2026-08-31 12:24:48 +02:00
|
|
|
#ifdef ENABLE_MODULE_ICEBERG
|
|
|
|
|
# include "modules/iceberg/main_impl.h"
|
|
|
|
|
#endif
|