Files
secp256k1-zkp/CMakeLists.txt

394 lines
19 KiB
CMake
Raw Normal View History

cmake_minimum_required(VERSION 3.22)
#=============================
# Project / Package metadata
#=============================
project(libsecp256k1
# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of
# the API. All changes in experimental modules are treated as
# backwards-compatible and therefore at most increase the minor version.
VERSION 0.7.2
DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1."
HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1"
LANGUAGES C
)
enable_testing()
include(CTestUseLaunchers) # Allow users to set CTEST_USE_LAUNCHERS in custom `ctest -S` scripts.
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
# The library version is based on libtool versioning of the ABI. The set of
# rules for updating the version can be found here:
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
# All changes in experimental modules are treated as if they don't affect the
# interface and therefore only increase the revision.
2025-07-21 16:21:31 +02:00
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 6)
set(${PROJECT_NAME}_LIB_VERSION_REVISION 2)
2024-11-04 13:45:03 +00:00
set(${PROJECT_NAME}_LIB_VERSION_AGE 0)
#=============================
# Language setup
#=============================
set(CMAKE_C_STANDARD 90)
set(CMAKE_C_EXTENSIONS OFF)
#=============================
# Configurable options
#=============================
if(libsecp256k1_IS_TOP_LEVEL)
option(BUILD_SHARED_LIBS "Build shared libraries." ON)
endif()
option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL})
option(SECP256K1_ENABLE_API_VISIBILITY_ATTRIBUTES "Enable visibility attributes in the API." ON)
## Modules
# We declare all options before processing them, to make sure we can express
# dependencies while processing.
option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON)
option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON)
option(SECP256K1_ENABLE_MODULE_MUSIG "Enable musig module." ON)
2026-08-31 00:05:16 +02:00
option(SECP256K1_ENABLE_MODULE_FROST "Enable FROST module (experimental)." OFF)
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
option(SECP256K1_ENABLE_MODULE_CHILLDKG "Enable ChillDKG module (experimental)." OFF)
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
option(SECP256K1_ENABLE_MODULE_ICEBERG "Enable Iceberg threshold-MuSig module (experimental)." OFF)
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
option(SECP256K1_ENABLE_MODULE_PREFRACTAL "Enable Prefractal nested FROST+MuSig2 module (experimental)." OFF)
option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON)
option(SECP256K1_ENABLE_MODULE_GENERATOR "Enable NUMS generator module." ON)
option(SECP256K1_ENABLE_MODULE_RANGEPROOF "Enable Range proof module." ON)
option(SECP256K1_ENABLE_MODULE_SURJECTIONPROOF "Enable Surjection proof module." ON)
option(SECP256K1_ENABLE_MODULE_WHITELIST "Enable key whitelist module." ON)
option(SECP256K1_ENABLE_MODULE_ECDSA_ADAPTOR "Enable ecdsa adaptor signatures module." ON)
option(SECP256K1_ENABLE_MODULE_ECDSA_S2C "Enable ECDSA sign-to-contract module." ON)
option(SECP256K1_ENABLE_MODULE_BPPP "Enable Bulletproofs++ module." ON)
option(SECP256K1_ENABLE_MODULE_SCHNORRSIG_HALFAGG "Enable schnorrsig half-aggregation module." ON)
option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF)
if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS)
add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1)
endif()
set(SECP256K1_ECMULT_WINDOW_SIZE 15 CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. The default value is a reasonable setting for desktop machines (currently 15). [default=15]")
set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24)
include(CheckStringOptionValue)
check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE)
add_compile_definitions(ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE})
set(SECP256K1_ECMULT_GEN_KB 86 CACHE STRING "The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms). Larger values result in possibly better signing or key generation performance at the cost of a larger table. Valid choices are 2, 22, 86. The default value is a reasonable setting for desktop machines (currently 86). [default=86]")
set_property(CACHE SECP256K1_ECMULT_GEN_KB PROPERTY STRINGS 2 22 86)
check_string_option_value(SECP256K1_ECMULT_GEN_KB)
if(SECP256K1_ECMULT_GEN_KB EQUAL 2)
add_compile_definitions(COMB_BLOCKS=2)
add_compile_definitions(COMB_TEETH=5)
elseif(SECP256K1_ECMULT_GEN_KB EQUAL 22)
add_compile_definitions(COMB_BLOCKS=11)
add_compile_definitions(COMB_TEETH=6)
elseif(SECP256K1_ECMULT_GEN_KB EQUAL 86)
add_compile_definitions(COMB_BLOCKS=43)
add_compile_definitions(COMB_TEETH=6)
endif()
set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]")
set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64")
check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value)
add_compile_definitions(USE_FORCE_WIDEMUL_${widemul_upper_value}=1)
endif()
mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]")
2023-05-11 10:03:23 +01:00
set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32")
check_string_option_value(SECP256K1_ASM)
2023-05-11 10:03:23 +01:00
if(SECP256K1_ASM STREQUAL "arm32")
enable_language(ASM)
include(CheckArm32Assembly)
check_arm32_assembly()
if(HAVE_ARM32_ASM)
add_compile_definitions(USE_EXTERNAL_ASM=1)
else()
message(FATAL_ERROR "ARM32 assembly requested but not available.")
endif()
elseif(SECP256K1_ASM)
2023-05-12 10:50:18 +01:00
include(CheckX86_64Assembly)
check_x86_64_assembly()
if(HAVE_X86_64_ASM)
set(SECP256K1_ASM "x86_64")
add_compile_definitions(USE_ASM_X86_64=1)
elseif(SECP256K1_ASM STREQUAL "AUTO")
set(SECP256K1_ASM "OFF")
else()
message(FATAL_ERROR "x86_64 assembly requested but not available.")
endif()
endif()
option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF)
if(NOT SECP256K1_EXPERIMENTAL)
2023-05-11 10:03:23 +01:00
if(SECP256K1_ASM STREQUAL "arm32")
message(FATAL_ERROR "ARM32 assembly is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
endif()
endif()
set(SECP256K1_VALGRIND "AUTO" CACHE STRING "Build with extra checks for running inside Valgrind. [default=AUTO]")
set_property(CACHE SECP256K1_VALGRIND PROPERTY STRINGS "AUTO" "OFF" "ON")
check_string_option_value(SECP256K1_VALGRIND)
if(SECP256K1_VALGRIND)
find_package(Valgrind MODULE)
if(Valgrind_FOUND)
set(SECP256K1_VALGRIND ON)
include_directories(${Valgrind_INCLUDE_DIR})
add_compile_definitions(VALGRIND)
elseif(SECP256K1_VALGRIND STREQUAL "AUTO")
set(SECP256K1_VALGRIND OFF)
else()
message(FATAL_ERROR "Valgrind support requested but valgrind/memcheck.h header not available.")
endif()
endif()
option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." ON)
option(SECP256K1_BUILD_TESTS "Build tests." ON)
option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." ON)
option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." ${SECP256K1_VALGRIND})
option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF)
# Redefine configuration flags.
# We leave assertions on, because they are only used in the examples, and we want them always on there.
if(MSVC)
string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
# Match GCC/Clang's size-optimization macro for the inline guard
add_compile_definitions($<$<CONFIG:MinSizeRel>:__OPTIMIZE_SIZE__=1>)
else()
string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
# Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.)
2024-06-27 11:46:48 -03:00
string(REGEX REPLACE "-O3( |$)" "-O2\\1" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
endif()
# Define custom "Coverage" build type.
set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage" CACHE STRING
"Flags used by the C compiler during \"Coverage\" builds."
FORCE
)
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING
"Flags used for linking binaries during \"Coverage\" builds."
FORCE
)
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING
"Flags used by the shared libraries linker during \"Coverage\" builds."
FORCE
)
mark_as_advanced(
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE
)
if(PROJECT_IS_TOP_LEVEL)
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
set(default_build_type "RelWithDebInfo")
if(is_multi_config)
set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING
"Supported configuration types."
FORCE
)
else()
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage"
)
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "Setting build type to \"${default_build_type}\" as none was specified")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING
"Choose the type of build."
FORCE
)
endif()
endif()
endif()
include(TryAppendCFlags)
if(MSVC)
# For both cl and clang-cl compilers.
2023-05-24 16:57:32 +01:00
try_append_c_flags(/W3) # Production quality warning level.
# Eliminate deprecation warnings for the older, less secure functions.
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
else()
try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers.
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
# Keep the following commands ordered lexicographically.
2023-03-22 10:37:16 +00:00
try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
2023-05-24 16:57:32 +01:00
try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data".
try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data".
else()
2023-03-22 10:37:16 +00:00
# Keep the following commands ordered lexicographically.
try_append_c_flags(-pedantic)
2023-03-22 10:37:16 +00:00
try_append_c_flags(-Wcast-align) # GCC >= 2.95.
try_append_c_flags(-Wcast-align=strict) # GCC >= 8.0.
try_append_c_flags(-Wconditional-uninitialized) # Clang >= 3.0 only.
try_append_c_flags(-Wextra) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
try_append_c_flags(-Wleading-whitespace=spaces) # GCC >= 15.0
try_append_c_flags(-Wnested-externs)
2023-03-22 10:37:16 +00:00
try_append_c_flags(-Wno-long-long) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
try_append_c_flags(-Wno-overlength-strings) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
try_append_c_flags(-Wno-unused-function) # GCC >= 3.0, -Wunused-function is implied by -Wall.
try_append_c_flags(-Wreserved-identifier) # Clang >= 13.0 only.
try_append_c_flags(-Wshadow)
try_append_c_flags(-Wstrict-prototypes)
try_append_c_flags(-Wtrailing-whitespace=any) # GCC >= 15.0
try_append_c_flags(-Wundef)
endif()
set(print_msan_notice)
if(SECP256K1_BUILD_CTIME_TESTS)
include(CheckMemorySanitizer)
check_memory_sanitizer(msan_enabled)
if(msan_enabled)
try_append_c_flags(-fno-sanitize-memory-param-retval)
set(print_msan_notice YES)
endif()
unset(msan_enabled)
endif()
set(SECP256K1_APPEND_CFLAGS "" CACHE STRING "Compiler flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.")
if(SECP256K1_APPEND_CFLAGS)
# Appending to this low-level rule variable is the only way to
# guarantee that the flags appear at the end of the command line.
string(APPEND CMAKE_C_COMPILE_OBJECT " ${SECP256K1_APPEND_CFLAGS}")
endif()
set(SECP256K1_APPEND_LDFLAGS "" CACHE STRING "Linker flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.")
if(SECP256K1_APPEND_LDFLAGS)
# Appending to this low-level rule variable is the only way to
# guarantee that the flags appear at the end of the command line.
string(APPEND CMAKE_C_CREATE_SHARED_LIBRARY " ${SECP256K1_APPEND_LDFLAGS}")
string(APPEND CMAKE_C_LINK_EXECUTABLE " ${SECP256K1_APPEND_LDFLAGS}")
endif()
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
endif()
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
endif()
if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
endif()
add_subdirectory(src)
if(SECP256K1_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
message("\n")
message("secp256k1 configure summary")
message("===========================")
message("Build artifacts:")
if(BUILD_SHARED_LIBS)
set(library_type "Shared")
else()
set(library_type "Static")
endif()
message(" library type ........................ ${library_type}")
message("Optional modules:")
message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}")
message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}")
message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}")
message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}")
message(" musig ............................... ${SECP256K1_ENABLE_MODULE_MUSIG}")
2026-08-31 00:05:16 +02:00
message(" frost ............................... ${SECP256K1_ENABLE_MODULE_FROST}")
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
message(" chilldkg ............................ ${SECP256K1_ENABLE_MODULE_CHILLDKG}")
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
message(" iceberg ............................. ${SECP256K1_ENABLE_MODULE_ICEBERG}")
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
message(" prefractal .......................... ${SECP256K1_ENABLE_MODULE_PREFRACTAL}")
message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}")
message(" generator ........................... ${SECP256K1_ENABLE_MODULE_GENERATOR}")
message(" rangeproof .......................... ${SECP256K1_ENABLE_MODULE_RANGEPROOF}")
message(" surjectionproof ..................... ${SECP256K1_ENABLE_MODULE_SURJECTIONPROOF}")
message(" whitelist ........................... ${SECP256K1_ENABLE_MODULE_WHITELIST}")
message(" ecdsa-s2c ........................... ${SECP256K1_ENABLE_MODULE_ECDSA_S2C}")
message(" ecdsa-adaptor ....................... ${SECP256K1_ENABLE_MODULE_ECDSA_ADAPTOR}")
message(" bppp ................................ ${SECP256K1_ENABLE_MODULE_BPPP}")
message(" schnorrsig-halfagg .................. ${SECP256K1_ENABLE_MODULE_SCHNORRSIG_HALFAGG}")
message("Parameters:")
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
message(" ecmult gen table size ............... ${SECP256K1_ECMULT_GEN_KB} KiB")
message("Optional features:")
message(" assembly ............................ ${SECP256K1_ASM}")
message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}")
if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}")
endif()
message("Optional binaries:")
message(" benchmark ........................... ${SECP256K1_BUILD_BENCHMARK}")
message(" noverify_tests ...................... ${SECP256K1_BUILD_TESTS}")
set(tests_status "${SECP256K1_BUILD_TESTS}")
if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
set(tests_status OFF)
endif()
message(" tests ............................... ${tests_status}")
message(" exhaustive tests .................... ${SECP256K1_BUILD_EXHAUSTIVE_TESTS}")
message(" ctime_tests ......................... ${SECP256K1_BUILD_CTIME_TESTS}")
message(" examples ............................ ${SECP256K1_BUILD_EXAMPLES}")
message("")
if(CMAKE_CROSSCOMPILING)
set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}")
else()
set(cross_status "FALSE")
endif()
message("Cross compiling ....................... ${cross_status}")
message("API visibility attributes ............. ${SECP256K1_ENABLE_API_VISIBILITY_ATTRIBUTES}")
message("Valgrind .............................. ${SECP256K1_VALGRIND}")
get_directory_property(definitions COMPILE_DEFINITIONS)
string(REPLACE ";" " " definitions "${definitions}")
message("Preprocessor defined macros ........... ${definitions}")
message("C compiler ............................ ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}, ${CMAKE_C_COMPILER}")
message("CFLAGS ................................ ${CMAKE_C_FLAGS}")
get_directory_property(compile_options COMPILE_OPTIONS)
string(REPLACE ";" " " compile_options "${compile_options}")
message("Compile options ....................... " ${compile_options})
if(NOT is_multi_config)
message("Build type:")
message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}")
string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type)
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${build_type}}")
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}")
else()
message("Supported configurations .............. ${CMAKE_CONFIGURATION_TYPES}")
message("RelWithDebInfo configuration:")
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
message("Debug configuration:")
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_DEBUG}")
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}")
endif()
if(SECP256K1_APPEND_CFLAGS)
message("SECP256K1_APPEND_CFLAGS ............... ${SECP256K1_APPEND_CFLAGS}")
endif()
if(SECP256K1_APPEND_LDFLAGS)
message("SECP256K1_APPEND_LDFLAGS .............. ${SECP256K1_APPEND_LDFLAGS}")
endif()
message("")
if(print_msan_notice)
message(
"Note:\n"
" MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to compile options\n"
" to avoid false positives in ctime_tests. Pass -DSECP256K1_BUILD_CTIME_TESTS=OFF to avoid this.\n"
)
endif()
if(SECP256K1_EXPERIMENTAL)
message(
" ******\n"
" WARNING: experimental build\n"
" Experimental features do not have stable APIs or properties, and may not be safe for production use.\n"
" ******\n"
)
endif()