ci.yml raw

   1  name: CI
   2  on:
   3    pull_request:
   4    push:
   5      branches:
   6        - '**'
   7      tags-ignore:
   8        - '**'
   9    schedule:
  10      # Run on the default branch every Monday morning.
  11      # This also warms the Docker caches after key rotation.
  12      - cron: '22 2 * * 1'
  13  
  14  concurrency:
  15    group: ${{ github.event_name != 'pull_request' && github.run_id || github.ref }}
  16    cancel-in-progress: true
  17  
  18  env:
  19    ### compiler options
  20    HOST:
  21    WRAPPER_CMD:
  22    # Specific warnings can be disabled with -Wno-error=foo.
  23    # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual.
  24    WERROR_CFLAGS: '-Werror -pedantic-errors'
  25    MAKEFLAGS: '-j4'
  26    BUILD: 'check'
  27    ### secp256k1 config
  28    ECMULTWINDOW: 15
  29    ECMULTGENKB: 86
  30    ASM: 'no'
  31    WIDEMUL: 'auto'
  32    WITH_VALGRIND: 'yes'
  33    EXTRAFLAGS:
  34    ### secp256k1 modules
  35    EXPERIMENTAL: 'no'
  36    ECDH: 'no'
  37    RECOVERY: 'no'
  38    EXTRAKEYS: 'no'
  39    SCHNORRSIG: 'no'
  40    MUSIG: 'no'
  41    ELLSWIFT: 'no'
  42    ### test options
  43    SECP256K1_TEST_ITERS: 64
  44    BENCH: 'yes'
  45    SECP256K1_BENCH_ITERS: 2
  46    CTIMETESTS: 'yes'
  47    SYMBOL_CHECK: 'yes'
  48    # Compile and run the examples.
  49    EXAMPLES: 'yes'
  50    # Disable Docker build summary generation.
  51    # See https://github.com/docker/build-push-action/blob/master/README.md#environment-variables.
  52    DOCKER_BUILD_SUMMARY: false
  53  
  54  jobs:
  55    docker_cache:
  56      name: "Build ${{ matrix.arch }} Docker image"
  57      runs-on: ${{ matrix.runner }}
  58      outputs:
  59        cache_scope: ${{ steps.cache_timestamp.outputs.period }}
  60  
  61      strategy:
  62        fail-fast: false
  63        matrix:
  64          include:
  65            - arch: x64
  66              runner: ubuntu-latest
  67            - arch: arm64
  68              runner: ubuntu-24.04-arm
  69  
  70      steps:
  71        - name: Get cache validity period
  72          id: cache_timestamp
  73          run: echo "period=$((10#$(date +%V) / 4))" >> "$GITHUB_OUTPUT"
  74  
  75        - name: Set up Docker Buildx
  76          uses: docker/setup-buildx-action@v4
  77          with:
  78            # See: https://github.com/moby/buildkit/issues/3969.
  79            driver-opts: |
  80              network=host
  81  
  82        - name: Build container
  83          uses: docker/build-push-action@v7
  84          with:
  85            file: ./ci/linux-debian.Dockerfile
  86            cache-from: type=gha,scope=${{ runner.arch }}-${{ steps.cache_timestamp.outputs.period }}
  87            cache-to: type=gha,scope=${{ runner.arch }}-${{ steps.cache_timestamp.outputs.period }},mode=min
  88  
  89    x86_64-debian:
  90      name: "x86_64: Linux (Debian stable)"
  91      runs-on: ubuntu-latest
  92      needs: docker_cache
  93  
  94      strategy:
  95        fail-fast: false
  96        matrix:
  97          configuration:
  98            - env_vars: { WIDEMUL: 'int64',  RECOVERY: 'yes' }
  99            - env_vars: { WIDEMUL: 'int64',                   ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
 100            - env_vars: { WIDEMUL: 'int128' }
 101            - env_vars: { WIDEMUL: 'int128_struct',                                                             ELLSWIFT: 'yes' }
 102            - env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes',              EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
 103            - env_vars: { WIDEMUL: 'int128',                  ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes' }
 104            - env_vars: { WIDEMUL: 'int128', ASM: 'x86_64',                                                     ELLSWIFT: 'yes' }
 105            - env_vars: {                    RECOVERY: 'yes',              EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes' }
 106            - env_vars: { CTIMETESTS: 'no',  RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', CPPFLAGS: '-DVERIFY' }
 107            - env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' }
 108            - env_vars: { CPPFLAGS: '-DDETERMINISTIC' }
 109            - env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' }
 110            - env_vars: { CFLAGS: '-O1',     RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
 111            - env_vars: { ECMULTGENKB: 2, ECMULTWINDOW: 2 }
 112            - env_vars: { ECMULTGENKB: 86, ECMULTWINDOW: 4 }
 113          cc:
 114            - 'gcc'
 115            - 'clang'
 116            - 'gcc-snapshot'
 117            - 'clang-snapshot'
 118  
 119      env:
 120        CC: ${{ matrix.cc }}
 121  
 122      steps:
 123        - &CHECKOUT
 124          name: Checkout
 125          uses: actions/checkout@v5
 126  
 127        - &CI_SCRIPT_IN_DOCKER
 128          name: CI script
 129          env: ${{ matrix.configuration.env_vars }}
 130          uses: ./.github/actions/run-in-docker-action
 131          with:
 132            dockerfile: ./ci/linux-debian.Dockerfile
 133            scope: ${{ runner.arch }}-${{ needs.docker_cache.outputs.cache_scope }}
 134            command: ./ci/ci.sh
 135  
 136        - &PRINT_LOGS
 137          name: Print logs
 138          uses: ./.github/actions/print-logs
 139          if: ${{ !cancelled() }}
 140  
 141    i686_debian:
 142      name: "i686: Linux (Debian stable)"
 143      runs-on: ubuntu-latest
 144      needs: docker_cache
 145  
 146      strategy:
 147        fail-fast: false
 148        matrix:
 149          configuration:
 150            - env_vars: {}
 151          cc:
 152            - 'i686-linux-gnu-gcc'
 153            - 'clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include'
 154  
 155      env:
 156        HOST: 'i686-linux-gnu'
 157        ECDH: 'yes'
 158        RECOVERY: 'yes'
 159        EXTRAKEYS: 'yes'
 160        SCHNORRSIG: 'yes'
 161        MUSIG: 'yes'
 162        ELLSWIFT: 'yes'
 163        CC: ${{ matrix.cc }}
 164  
 165      steps:
 166        - *CHECKOUT
 167        - *CI_SCRIPT_IN_DOCKER
 168        - *PRINT_LOGS
 169  
 170    s390x_debian:
 171      name: "s390x (big-endian): Linux (Debian stable, QEMU)"
 172      runs-on: ubuntu-latest
 173      needs: docker_cache
 174  
 175      strategy:
 176        matrix:
 177          configuration:
 178            - env_vars: {}
 179  
 180      env:
 181        WRAPPER_CMD: 'qemu-s390x'
 182        SECP256K1_TEST_ITERS: 16
 183        HOST: 's390x-linux-gnu'
 184        WITH_VALGRIND: 'no'
 185        ECDH: 'yes'
 186        RECOVERY: 'yes'
 187        EXTRAKEYS: 'yes'
 188        SCHNORRSIG: 'yes'
 189        MUSIG: 'yes'
 190        ELLSWIFT: 'yes'
 191        CTIMETESTS: 'no'
 192  
 193      steps:
 194        - *CHECKOUT
 195        - *CI_SCRIPT_IN_DOCKER
 196        - *PRINT_LOGS
 197  
 198    arm32_debian:
 199      name: "ARM32: Linux (Debian stable, QEMU)"
 200      runs-on: ubuntu-latest
 201      needs: docker_cache
 202  
 203      strategy:
 204        fail-fast: false
 205        matrix:
 206          configuration:
 207            - env_vars: {}
 208            - env_vars: { EXPERIMENTAL: 'yes', ASM: 'arm32' }
 209  
 210      env:
 211        WRAPPER_CMD: 'qemu-arm'
 212        SECP256K1_TEST_ITERS: 16
 213        HOST: 'arm-linux-gnueabihf'
 214        WITH_VALGRIND: 'no'
 215        ECDH: 'yes'
 216        RECOVERY: 'yes'
 217        EXTRAKEYS: 'yes'
 218        SCHNORRSIG: 'yes'
 219        MUSIG: 'yes'
 220        ELLSWIFT: 'yes'
 221        CTIMETESTS: 'no'
 222  
 223      steps:
 224        - *CHECKOUT
 225        - *CI_SCRIPT_IN_DOCKER
 226        - *PRINT_LOGS
 227  
 228    arm64-debian:
 229      name: "arm64: Linux (Debian stable)"
 230      runs-on: ubuntu-24.04-arm
 231      needs: docker_cache
 232  
 233      env:
 234        SECP256K1_TEST_ITERS: 16
 235        WITH_VALGRIND: 'no'
 236        ECDH: 'yes'
 237        RECOVERY: 'yes'
 238        EXTRAKEYS: 'yes'
 239        SCHNORRSIG: 'yes'
 240        MUSIG: 'yes'
 241        ELLSWIFT: 'yes'
 242        CTIMETESTS: 'no'
 243        CC: ${{ matrix.cc }}
 244  
 245      strategy:
 246        fail-fast: false
 247        matrix:
 248          configuration:
 249            - env_vars: {}
 250          cc:
 251            - 'gcc'
 252            - 'clang'
 253            - 'gcc-snapshot'
 254            - 'clang-snapshot'
 255  
 256      steps:
 257        - *CHECKOUT
 258        - *CI_SCRIPT_IN_DOCKER
 259        - *PRINT_LOGS
 260  
 261    ppc64le_debian:
 262      name: "ppc64le: Linux (Debian stable, QEMU)"
 263      runs-on: ubuntu-latest
 264      needs: docker_cache
 265  
 266      strategy:
 267        matrix:
 268          configuration:
 269            - env_vars: {}
 270  
 271      env:
 272        WRAPPER_CMD: 'qemu-ppc64le'
 273        SECP256K1_TEST_ITERS: 16
 274        HOST: 'powerpc64le-linux-gnu'
 275        WITH_VALGRIND: 'no'
 276        ECDH: 'yes'
 277        RECOVERY: 'yes'
 278        EXTRAKEYS: 'yes'
 279        SCHNORRSIG: 'yes'
 280        MUSIG: 'yes'
 281        ELLSWIFT: 'yes'
 282        CTIMETESTS: 'no'
 283  
 284      steps:
 285        - *CHECKOUT
 286        - *CI_SCRIPT_IN_DOCKER
 287        - *PRINT_LOGS
 288  
 289    valgrind_debian:
 290      name: "Valgrind ${{ matrix.configuration.binary_arch }} (memcheck)"
 291      runs-on: ${{ matrix.configuration.runner }}
 292      needs: docker_cache
 293  
 294      strategy:
 295        fail-fast: false
 296        matrix:
 297          configuration:
 298            - runner: ubuntu-latest
 299              binary_arch: x64
 300              env_vars: { CC: 'clang',                                      ASM: 'auto' }
 301            - runner: ubuntu-latest
 302              binary_arch: i686
 303              env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' }
 304            - runner: ubuntu-24.04-arm
 305              binary_arch: arm64
 306              env_vars: { CC: 'clang',                                      ASM: 'auto' }
 307            - runner: ubuntu-latest
 308              binary_arch: x64
 309              env_vars: { CC: 'clang',                                      ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
 310            - runner: ubuntu-latest
 311              binary_arch: i686
 312              env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
 313            - runner: ubuntu-24.04-arm
 314              binary_arch: arm64
 315              env_vars: { CC: 'clang',                                      ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
 316  
 317      env:
 318        # The `--error-exitcode` is required to make the test fail if valgrind found errors,
 319        # otherwise it will return 0 (https://www.valgrind.org/docs/manual/manual-core.html).
 320        WRAPPER_CMD: 'valgrind --error-exitcode=42'
 321        ECDH: 'yes'
 322        RECOVERY: 'yes'
 323        EXTRAKEYS: 'yes'
 324        SCHNORRSIG: 'yes'
 325        MUSIG: 'yes'
 326        ELLSWIFT: 'yes'
 327        CTIMETESTS: 'no'
 328        SECP256K1_TEST_ITERS: 2
 329  
 330      steps:
 331        - *CHECKOUT
 332        - *CI_SCRIPT_IN_DOCKER
 333        - *PRINT_LOGS
 334  
 335    sanitizers_debian:
 336      name: "UBSan, ASan, LSan"
 337      runs-on: ubuntu-latest
 338      needs: docker_cache
 339  
 340      strategy:
 341        fail-fast: false
 342        matrix:
 343          configuration:
 344            - env_vars: { CC: 'clang',                                      ASM: 'auto' }
 345            - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' }
 346            - env_vars: { CC: 'clang',                                      ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
 347            - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
 348  
 349      env:
 350        ECDH: 'yes'
 351        RECOVERY: 'yes'
 352        EXTRAKEYS: 'yes'
 353        SCHNORRSIG: 'yes'
 354        MUSIG: 'yes'
 355        ELLSWIFT: 'yes'
 356        CTIMETESTS: 'no'
 357        CFLAGS: '-fsanitize=undefined,address -g'
 358        UBSAN_OPTIONS: 'print_stacktrace=1:halt_on_error=1'
 359        ASAN_OPTIONS: 'strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1'
 360        LSAN_OPTIONS: 'use_unaligned=1'
 361        SECP256K1_TEST_ITERS: 32
 362        SYMBOL_CHECK: 'no'
 363  
 364      steps:
 365        - *CHECKOUT
 366        - *CI_SCRIPT_IN_DOCKER
 367        - *PRINT_LOGS
 368  
 369    msan_debian:
 370      name: "MSan"
 371      runs-on: ubuntu-latest
 372      needs: docker_cache
 373  
 374      strategy:
 375        fail-fast: false
 376        matrix:
 377          configuration:
 378            - env_vars:
 379                CTIMETESTS: 'yes'
 380                CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g'
 381            - env_vars:
 382                ECMULTGENKB: 2
 383                ECMULTWINDOW: 2
 384                CTIMETESTS: 'yes'
 385                CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g -O3'
 386            - env_vars:
 387                # -fsanitize-memory-param-retval is clang's default, but our build system disables it
 388                # when ctime_tests when enabled.
 389                CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -fsanitize-memory-param-retval -g'
 390                CTIMETESTS: 'no'
 391          cc:
 392            - 'clang'
 393            - 'clang-snapshot'
 394  
 395      env:
 396        ECDH: 'yes'
 397        RECOVERY: 'yes'
 398        EXTRAKEYS: 'yes'
 399        SCHNORRSIG: 'yes'
 400        MUSIG: 'yes'
 401        ELLSWIFT: 'yes'
 402        CC: ${{ matrix.cc }}
 403        SECP256K1_TEST_ITERS: 32
 404        ASM: 'no'
 405        WITH_VALGRIND: 'no'
 406        SYMBOL_CHECK: 'no'
 407  
 408      steps:
 409        - *CHECKOUT
 410        - *CI_SCRIPT_IN_DOCKER
 411        - *PRINT_LOGS
 412  
 413    mingw_debian:
 414      name: ${{ matrix.configuration.job_name }}
 415      runs-on: ubuntu-latest
 416      needs: docker_cache
 417  
 418      env:
 419        WRAPPER_CMD: 'wine'
 420        WITH_VALGRIND: 'no'
 421        ECDH: 'yes'
 422        RECOVERY: 'yes'
 423        EXTRAKEYS: 'yes'
 424        SCHNORRSIG: 'yes'
 425        MUSIG: 'yes'
 426        ELLSWIFT: 'yes'
 427        CTIMETESTS: 'no'
 428  
 429      strategy:
 430        fail-fast: false
 431        matrix:
 432          configuration:
 433            - job_name: 'x86_64 (mingw32-w64): Windows (Debian stable, Wine)'
 434              env_vars:
 435                HOST: 'x86_64-w64-mingw32'
 436            - job_name: 'i686 (mingw32-w64): Windows (Debian stable, Wine)'
 437              env_vars:
 438                HOST: 'i686-w64-mingw32'
 439  
 440      steps:
 441        - *CHECKOUT
 442        - *CI_SCRIPT_IN_DOCKER
 443        - *PRINT_LOGS
 444  
 445    x86_64-macos-native:
 446      name: "x86_64: macOS Sequoia, Valgrind"
 447      runs-on: macos-15-intel
 448  
 449      env:
 450        CC: 'clang'
 451        HOMEBREW_NO_AUTO_UPDATE: 1
 452        HOMEBREW_NO_INSTALL_CLEANUP: 1
 453        SYMBOL_CHECK: 'no'
 454  
 455      strategy:
 456        fail-fast: false
 457        matrix:
 458          env_vars:
 459            - { WIDEMUL: 'int64',  RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
 460            - { WIDEMUL: 'int128_struct', ECMULTGENKB: 2, ECMULTWINDOW: 4 }
 461            - { WIDEMUL: 'int128',                  ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
 462            - { WIDEMUL: 'int128', RECOVERY: 'yes' }
 463            - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
 464            - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' }
 465            - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes',            WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
 466            - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
 467            - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' }
 468            - BUILD: 'distcheck'
 469  
 470      steps:
 471        - *CHECKOUT
 472  
 473        - name: Install Homebrew packages
 474          run: |
 475            brew install --quiet automake libtool gcc
 476            ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc
 477  
 478        - name: Install and cache Valgrind
 479          uses: ./.github/actions/install-homebrew-valgrind
 480  
 481        - &CI_SCRIPT_ON_HOST
 482          name: CI script
 483          env: ${{ matrix.env_vars }}
 484          run: ./ci/ci.sh
 485  
 486        - &SYMBOL_CHECK_MACOS
 487          name: Symbol check
 488          env:
 489            VIRTUAL_ENV: '${{ github.workspace }}/venv'
 490          run: |
 491            python3 --version
 492            python3 -m venv $VIRTUAL_ENV
 493            export PATH="$VIRTUAL_ENV/bin:$PATH"
 494            python3 -m pip install lief
 495            python3 ./tools/symbol-check.py .libs/libsecp256k1.dylib
 496  
 497        - *PRINT_LOGS
 498  
 499    arm64-macos-native:
 500      name: "ARM64: macOS Sonoma"
 501      # See: https://github.com/actions/runner-images#available-images.
 502      runs-on: macos-14
 503  
 504      env:
 505        CC: 'clang'
 506        HOMEBREW_NO_AUTO_UPDATE: 1
 507        HOMEBREW_NO_INSTALL_CLEANUP: 1
 508        WITH_VALGRIND: 'no'
 509        CTIMETESTS: 'no'
 510        SYMBOL_CHECK: 'no'
 511  
 512      strategy:
 513        fail-fast: false
 514        matrix:
 515          env_vars:
 516            - { WIDEMUL: 'int64',  RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
 517            - { WIDEMUL: 'int128_struct', ECMULTGENKB: 2, ECMULTWINDOW: 4 }
 518            - { WIDEMUL: 'int128',                  ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
 519            - { WIDEMUL: 'int128', RECOVERY: 'yes' }
 520            - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
 521            - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' }
 522            - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY' }
 523            - BUILD: 'distcheck'
 524  
 525      steps:
 526        - *CHECKOUT
 527  
 528        - name: Install Homebrew packages
 529          run: |
 530            brew install --quiet automake libtool gcc
 531            ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc
 532  
 533        - *CI_SCRIPT_ON_HOST
 534        - *SYMBOL_CHECK_MACOS
 535        - *PRINT_LOGS
 536  
 537    win64-native:
 538      name: ${{ matrix.configuration.job_name }}
 539      # See: https://github.com/actions/runner-images#available-images.
 540      runs-on: windows-2022
 541  
 542      strategy:
 543        fail-fast: false
 544        matrix:
 545          configuration:
 546            - job_name: 'x64 (MSVC): Windows (VS 2022, shared)'
 547              cmake_options: '-A x64 -DBUILD_SHARED_LIBS=ON'
 548              symbol_check: 'true'
 549            - job_name: 'x64 (MSVC): Windows (VS 2022, static)'
 550              cmake_options: '-A x64 -DBUILD_SHARED_LIBS=OFF'
 551            - job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct)'
 552              cmake_options: '-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct'
 553            - job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct with __(u)mulh)'
 554              cmake_options: '-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct'
 555              cpp_flags: '/DSECP256K1_MSVC_MULH_TEST_OVERRIDE'
 556            - job_name: 'x86 (MSVC): Windows (VS 2022)'
 557              cmake_options: '-A Win32'
 558            - job_name: 'x64 (clang-cl): Windows (VS 2022, shared)'
 559              cmake_options: '-T ClangCL -DBUILD_SHARED_LIBS=ON'
 560              symbol_check: 'true'
 561            - job_name: 'x64 (clang-cl): Windows (VS 2022, static)'
 562              cmake_options: '-T ClangCL -DBUILD_SHARED_LIBS=OFF'
 563            - job_name: 'x64 (clang-cl): Windows (VS 2022, int128_struct)'
 564              cmake_options: '-T ClangCL -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct'
 565            - job_name: 'x64 (clang-cl): Windows (VS 2022, int128_struct with __(u)mulh)'
 566              cmake_options: '-T ClangCL -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct'
 567              cpp_flags: '/DSECP256K1_MSVC_MULH_TEST_OVERRIDE'
 568  
 569      steps:
 570        - *CHECKOUT
 571  
 572        - name: Generate buildsystem
 573          run: cmake -E env CFLAGS="/WX ${{ matrix.configuration.cpp_flags }}" cmake -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON ${{ matrix.configuration.cmake_options }}
 574  
 575        - name: Build
 576          run: cmake --build build --config RelWithDebInfo -- /p:UseMultiToolTask=true /maxCpuCount
 577  
 578        - name: Binaries info
 579          # Use the bash shell included with Git for Windows.
 580          shell: bash
 581          run: |
 582            cd build/bin/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true
 583  
 584        - name: Symbol check
 585          if: ${{ matrix.configuration.symbol_check }}
 586          shell: bash
 587          run: |
 588            py -3 --version
 589            py -3 -m pip install lief
 590            py -3 ./tools/symbol-check.py build/bin/RelWithDebInfo/libsecp256k1-*.dll
 591  
 592        - name: Check
 593          run: |
 594            ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1)
 595            build\bin\RelWithDebInfo\bench_ecmult.exe
 596            build\bin\RelWithDebInfo\bench_internal.exe
 597            build\bin\RelWithDebInfo\bench.exe
 598  
 599    win64-native-headers:
 600      name: "x64 (MSVC): C++ (public headers)"
 601      # See: https://github.com/actions/runner-images#available-images.
 602      runs-on: windows-2022
 603  
 604      steps:
 605        - *CHECKOUT
 606  
 607        - name: C++ (public headers)
 608          shell: cmd
 609          run: |
 610            call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
 611            cl.exe -c -WX -TP include/*.h
 612  
 613    cxx_fpermissive_debian:
 614      name: "C++ -fpermissive (entire project)"
 615      runs-on: ubuntu-latest
 616      needs: docker_cache
 617  
 618      strategy:
 619        matrix:
 620          configuration:
 621            - env_vars: {}
 622  
 623      env:
 624        CC: 'g++'
 625        CFLAGS: '-fpermissive -g'
 626        CPPFLAGS: '-DSECP256K1_CPLUSPLUS_TEST_OVERRIDE'
 627        WERROR_CFLAGS:
 628        ECDH: 'yes'
 629        RECOVERY: 'yes'
 630        EXTRAKEYS: 'yes'
 631        SCHNORRSIG: 'yes'
 632        MUSIG: 'yes'
 633        ELLSWIFT: 'yes'
 634  
 635      steps:
 636        - *CHECKOUT
 637        - *CI_SCRIPT_IN_DOCKER
 638        - *PRINT_LOGS
 639  
 640    cxx_headers_debian:
 641      name: "C++ (public headers)"
 642      runs-on: ubuntu-latest
 643      needs: docker_cache
 644  
 645      steps:
 646        - *CHECKOUT
 647  
 648        - name: CI script
 649          uses: ./.github/actions/run-in-docker-action
 650          with:
 651            dockerfile: ./ci/linux-debian.Dockerfile
 652            scope: ${{ runner.arch }}-${{ needs.docker_cache.outputs.cache_scope }}
 653            command: |
 654              g++ -Werror include/*.h
 655              clang -Werror -x c++-header include/*.h
 656  
 657    sage:
 658      name: "SageMath prover"
 659      runs-on: ubuntu-latest
 660      container:
 661        image: sagemath/sagemath:latest
 662        options: --user root
 663  
 664      steps:
 665        - *CHECKOUT
 666  
 667        - name: CI script
 668          run: |
 669            cd sage
 670            sage prove_group_implementations.sage
 671  
 672    release:
 673      runs-on: ubuntu-latest
 674  
 675      steps:
 676        - *CHECKOUT
 677  
 678        - run: ./autogen.sh && ./configure --enable-dev-mode && make distcheck
 679  
 680        - name: Check installation with Autotools
 681          env:
 682            CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install
 683          run: |
 684            ./autogen.sh && ./configure --prefix=${{ env.CI_INSTALL }} && make clean && make install && ls -RlAh ${{ env.CI_INSTALL }}
 685            gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=${{ env.CI_INSTALL }}/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"${{ env.CI_INSTALL }}/lib" && ./ecdsa
 686  
 687        - name: Check installation with CMake
 688          env:
 689            CI_BUILD: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/build
 690            CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install
 691          run: |
 692            cmake -B ${{ env.CI_BUILD }} -DCMAKE_INSTALL_PREFIX=${{ env.CI_INSTALL }} && cmake --build ${{ env.CI_BUILD }} && cmake --install ${{ env.CI_BUILD }} && ls -RlAh ${{ env.CI_INSTALL }}
 693            gcc -o ecdsa examples/ecdsa.c -I ${{ env.CI_INSTALL }}/include -L ${{ env.CI_INSTALL }}/lib*/ -l secp256k1 -Wl,-rpath,"${{ env.CI_INSTALL }}/lib",-rpath,"${{ env.CI_INSTALL }}/lib64" && ./ecdsa
 694