{
 "number": 36188,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/36188",
 "title": "crypto: plug hardware optimized SHA256 into libsecp256k1's context",
 "author": "furszy",
 "author_association": "MEMBER",
 "created_at": "2026-09-07T20:28:23Z",
 "updated_at": "2026-09-15T03:40:24Z",
 "age_days": 9,
 "draft": false,
 "labels": [
  "Utils/log/libs"
 ],
 "milestone": "33.0",
 "base": "master",
 "head_sha": "1c216a069bfebcb5219ff7d7216a4175af83621a",
 "head_ref": "2026_secp_pluggable_sha",
 "head_repo": "furszy/bitcoin-core",
 "head_history": [
  {
   "t": "2026-09-07T23:06:29Z",
   "sha": "1c216a069bfebcb5219ff7d7216a4175af83621a"
  }
 ],
 "additions": 452,
 "deletions": 151,
 "changed_files": 43,
 "commit_count": 11,
 "size_bucket": "L",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "w0xlt",
      "url": "https://github.com/bitcoin/bitcoin/pull/36188#issuecomment-5580711356"
     },
     {
      "login": "fjahr",
      "url": "https://github.com/bitcoin/bitcoin/pull/36188#issuecomment-5580993855"
     },
     {
      "login": "sedited",
      "url": "https://github.com/bitcoin/bitcoin/pull/36188#issuecomment-5581070938"
     },
     {
      "login": "ismaelsadeeq",
      "url": "https://github.com/bitcoin/bitcoin/pull/36188#issuecomment-5582747055"
     },
     {
      "login": "theStack",
      "url": "https://github.com/bitcoin/bitcoin/pull/36188#issuecomment-5588784156"
     },
     {
      "login": "hebasto",
      "url": "https://github.com/bitcoin/bitcoin/pull/36188#pullrequestreview-5168598520"
     }
    ]
   },
   "conflicts": [
    {
     "number": 35675,
     "title": "mining: add block template manager",
     "author": "ismaelsadeeq"
    },
    {
     "number": 35646,
     "title": "RFC: Separate out runtime errors from BlockValidationState using `util::Expected`",
     "author": "yuvicc"
    },
    {
     "number": 35581,
     "title": "node: add block template manager and track waitNext fee inflow",
     "author": "ismaelsadeeq"
    },
    {
     "number": 35511,
     "title": "RFC: consensus: Make `CAmount` a class",
     "author": "hodlinator"
    },
    {
     "number": 33922,
     "title": "mining: add getMemoryLoad() and track template non-mempool memory footprint",
     "author": "Sjors"
    },
    {
     "number": 29700,
     "title": "kernel, refactor: return error status on all fatal errors",
     "author": "ryanofsky"
    },
    {
     "number": 28690,
     "title": "build: Introduce internal kernel library",
     "author": "sedited"
    },
    {
     "number": 19461,
     "title": "multiprocess: Add bitcoin-gui -ipcconnect option",
     "author": "ryanofsky"
    },
    {
     "number": 19460,
     "title": "multiprocess: Add bitcoin-wallet -ipcconnect option",
     "author": "ryanofsky"
    }
   ]
  }
 },
 "acks_parsed": {
  "w0xlt": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-09-08T07:00:28Z",
   "stale": false
  },
  "fjahr": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-09-08T07:23:32Z",
   "stale": false
  },
  "hebasto": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-09-10T14:48:12Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 3,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "fanquake",
   "fjahr",
   "hebasto",
   "ismaelsadeeq",
   "sedited",
   "theStack",
   "w0xlt"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-09-07T23:06:29Z",
  "last_reviewer_activity": "2026-09-10T14:48:12Z",
  "last_reviewer": "hebasto",
  "author_silent_days": 9,
  "waiting_on_author_days": 7,
  "days_since_update": 2
 },
 "refs": {
  "mentioned": [],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [],
  "conflicts": [
   35675,
   35646,
   35581,
   35511,
   33922,
   29700,
   28690,
   19461,
   19460
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [],
 "body": "Since https://github.com/bitcoin-core/secp256k1/pull//1777 , libsecp256k1 allows an externally provided SHA256 compression function. This PR plug ours in, so it runs on our SHA-NI/ARMv8/SSE4 hardware optimized implementation instead of the libsecp bare internal one.\n\nThe biggest gains are at the signing side, not at the verification side.\n\nThe first commits restructure how the libsecp context is encapsulated and initialized. `ECC_Context` now properly handles the libsecp context lifecycle and fully behaves as a singleton, getting decoupled from the `key.h/cpp` primitive (which is no longer accessed by upper layers just to init ECC), allowing us to introduce a verification context within the same object, and moving the singleton initialization to `ecc_init.h` which simplifies usage to a single entry point for all users.\n\nBenchmarks at the bench introduction commit (43c9bdbf8ada1b581b5ab1f0a102517c243a60da) and at the tip:\n\nOn ARM64, `arm_shani` implementation\n\n| benchmark | before | after | change |\n|---|---|---|---|\n| `ECDSASign` | 79.2 \u00b5s | 69.3 \u00b5s | -13% |\n| `SchnorrSign` | 39.9 \u00b5s | 37.1 \u00b5s | -7% |\n| `ECDSAVerify` | 27.4 \u00b5s | 27.3 \u00b5s | -0% |\n| `SchnorrVerify` | 28.1 \u00b5s | 27.8 \u00b5s | -1% |\n| `EllSwiftCreate` | 29.8 \u00b5s | 28.8 \u00b5s | -3% |\n| `BIP324_ECDH` | 30.4 \u00b5s | 30.1 \u00b5s | -1% |",
 "commits": [
  {
   "sha": "0a0ab6816025af44b84f3985cac7d8caab6117c3",
   "date": "2026-09-07T18:39:07Z",
   "message": "libsecp: generalize context setup and teardown\n\nNo behavior change.\n\nFirst step toward an ECC_Context that owns the lifecycle of both\nlibsecp contexts, signing and verification.\n\nECC_Start receives the rng seed, so a verification context can be\ncreated without one. Blinding is not needed for public data.\n\nAlso disallow copying ECC_Context, two copies would destroy the\nsame context."
  },
  {
   "sha": "1253e64d63ae127e3bb5f5fc7e1283f101bcce46",
   "date": "2026-09-07T18:39:32Z",
   "message": "libsecp: encapsulate signing context inside ECC_Context\n\nNo behavior change.\n\nThe signing context belongs to the ECC_Context that creates and\ndestroys it. Only one instance may exist at a time, and the\ngetter reads from it."
  },
  {
   "sha": "1fda5a0740b390f2f7904d0c37daa65677c49030",
   "date": "2026-09-07T18:40:50Z",
   "message": "init: decouple ECC init from primitives\n\nNo behavior change.\n\nOne entry point for ECC initialization, which will soon be moved to\nthe consensus library, and set up a verification context.\n\nThe goal is to decouple context handling from the primitive key.h/cpp\nand pubkey.h/cpp, which shouldn't be accessed by the upper layers."
  },
  {
   "sha": "fa2e2dc69f457b23ca525e253e060e1d45159105",
   "date": "2026-09-07T18:41:42Z",
   "message": "libsecp: ECC_Context takes the blinding seed\n\nNo behavior change.\n\nLast ECC_Context dependency on the RNG before the move to\nthe consensus library."
  },
  {
   "sha": "b44f0da9b2115e1e733ad01be9a875a94427d788",
   "date": "2026-09-07T18:42:41Z",
   "message": "refactor: move ECC_Context to ecc_context.{h,cpp}\n\nNo behavior change.\n\nECC_Context now lives in the consensus library, so it can\nhold the libsecp verification context next."
  },
  {
   "sha": "ee77338bbdf2b9dd51b7c0b1ce9f657aeb9b5baf",
   "date": "2026-09-07T18:42:54Z",
   "message": "test: add ECC_Context lifecycle coverage"
  },
  {
   "sha": "f61a8a95949d9692b7c5f74fe855d96836f5e26c",
   "date": "2026-09-07T23:06:03Z",
   "message": "bench: ECDSA and Schnorr signing and verification\n\nLow-level signature creation and validation benchmarks."
  },
  {
   "sha": "5fb21ed98671bf702b574ff540f7cf8162a6677c",
   "date": "2026-09-07T23:06:04Z",
   "message": "libsecp: plug our hardware optimized SHA256 into libsecp256k1 ctx\n\nlibsecp256k1 lets a context use an external SHA256 compression\nfunction. With ours, ECDSA signing gets ~15% faster on CPUs with\nSHA extensions, Schnorr signing ~3%."
  },
  {
   "sha": "99a29f69fd004518afa5dbcabe6e5e080087ab21",
   "date": "2026-09-07T23:06:04Z",
   "message": "libsecp: introduce verification context to ECC_Context\n\nVerification uses secp256k1_context_static, which can't take our\noptimized SHA256 compression function. Rather than reusing the signing\ncontext, which blinds certain calculations, for no benefit to public\ndata, verification gets its own context, owned by ECC_Context along\nwith the signing one.\n\nAround 1% faster Schnorr signature verification. ECDSA remains equal\nas hashing is done outside libsecp."
  },
  {
   "sha": "e0d46a42e0c568978a90fd3fcffc9c9d9b604409",
   "date": "2026-09-07T23:06:04Z",
   "message": "scripted-diff: use verification context in pubkey.cpp\n\nEvery use of secp256k1_context_static in pubkey.cpp uses public\ndata, so all of them can use the verification  context, which\ncontains our optimized SHA256 compression plugged in.\n\n-BEGIN VERIFY SCRIPT-\nsed -i -e '/\\/\\*/! s/secp256k1_context_static/GetSecp256k1VerifyContext()/g' -e 's|^#include <hash.h>$|#include <ecc_context.h>\\n#include <hash.h>|' src/pubkey.cpp\n-END VERIFY SCRIPT-"
  },
  {
   "sha": "1c216a069bfebcb5219ff7d7216a4175af83621a",
   "date": "2026-09-07T23:06:04Z",
   "message": "fuzz: use libsecp verification context\n\nMake fuzz tests use the verification context instead of the\nstatic one provided by libsecp.\n\nAlso, introduces a simple unit test validating VerifySchnorr\nprovides the correct context to libsecp."
  }
 ],
 "timeline": [
  {
   "t": "2026-09-07T23:06:29Z",
   "kind": "force_push",
   "who": "furszy",
   "commit": "1c216a069bfebcb5219ff7d7216a4175af83621a"
  },
  {
   "t": "2026-09-08T07:00:28Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "Concept ACK"
  },
  {
   "t": "2026-09-08T07:23:32Z",
   "kind": "comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "text": "Concept ACK"
  },
  {
   "t": "2026-09-08T07:30:06Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "Finally! Concept ACK"
  },
  {
   "t": "2026-09-08T09:32:32Z",
   "kind": "comment",
   "who": "ismaelsadeeq",
   "assoc": "MEMBER",
   "text": "Awesome Concept ACK"
  },
  {
   "t": "2026-09-08T16:55:02Z",
   "kind": "comment",
   "who": "theStack",
   "assoc": "MEMBER",
   "text": "Splendid Concept ACK"
  },
  {
   "t": "2026-09-09T10:51:52Z",
   "kind": "comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "text": "cc @real-or-random"
  },
  {
   "t": "2026-09-10T14:48:12Z",
   "kind": "review",
   "who": "hebasto",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "1c216a069bfebcb5219ff7d7216a4175af83621a",
   "text": "Concept ACK."
  }
 ],
 "labels_log": [
  {
   "t": "2026-09-07T20:28:26Z",
   "action": "labeled",
   "label": "Utils/log/libs",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-07T21:39:37Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-08T00:17:41Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2026-09-09T10:51:40Z",
   "kind": "milestoned",
   "who": "fanquake"
  }
 ],
 "text_chars": 4255,
 "text_tokens_estimate": 1063,
 "changed_paths": [
  "src/CMakeLists.txt",
  "src/bench/CMakeLists.txt",
  "src/bench/bip324_ecdh.cpp",
  "src/bench/ccoins_caching.cpp",
  "src/bench/checkqueue.cpp",
  "src/bench/descriptors.cpp",
  "src/bench/ecc_sign_verify.cpp",
  "src/bench/ellswift.cpp",
  "src/bench/sign_transaction.cpp",
  "src/bench/verify_script.cpp",
  "src/bitcoin-tx.cpp",
  "src/bitcoin-wallet.cpp",
  "src/bitcoind.cpp",
  "src/common/ecc_init.cpp",
  "src/common/ecc_init.h",
  "src/crypto/sha256.cpp",
  "src/crypto/sha256.h",
  "src/ecc_context.cpp",
  "src/ecc_context.h",
  "src/init.cpp",
  "src/kernel/CMakeLists.txt",
  "src/key.cpp",
  "src/key.h",
  "src/musig.cpp",
  "src/node/context.cpp",
  "src/node/context.h",
  "src/node/interfaces.cpp",
  "src/pubkey.cpp",
  "src/test/CMakeLists.txt",
  "src/test/ecc_context_tests.cpp",
  "src/test/fuzz/bip324.cpp",
  "src/test/fuzz/descriptor_parse.cpp",
  "src/test/fuzz/key.cpp",
  "src/test/fuzz/key_io.cpp",
  "src/test/fuzz/message.cpp",
  "src/test/fuzz/miniscript.cpp",
  "src/test/fuzz/p2p_transport_serialization.cpp",
  "src/test/fuzz/script_assets_test_minimizer.cpp",
  "src/test/fuzz/script_flags.cpp",
  "src/test/fuzz/script_sign.cpp",
  "src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp",
  "src/test/sanity_tests.cpp",
  "src/test/util/setup_common.cpp"
 ],
 "files": [
  {
   "path": "src/CMakeLists.txt",
   "add": 2,
   "del": 0
  },
  {
   "path": "src/bench/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/bench/bip324_ecdh.cpp",
   "add": 2,
   "del": 1
  },
  {
   "path": "src/bench/ccoins_caching.cpp",
   "add": 2,
   "del": 2
  },
  {
   "path": "src/bench/checkqueue.cpp",
   "add": 2,
   "del": 2
  },
  {
   "path": "src/bench/descriptors.cpp",
   "add": 2,
   "del": 2
  },
  {
   "path": "src/bench/ecc_sign_verify.cpp",
   "add": 118,
   "del": 0
  },
  {
   "path": "src/bench/ellswift.cpp",
   "add": 2,
   "del": 1
  },
  {
   "path": "src/bench/sign_transaction.cpp",
   "add": 3,
   "del": 2
  },
  {
   "path": "src/bench/verify_script.cpp",
   "add": 2,
   "del": 1
  },
  {
   "path": "src/bitcoin-tx.cpp",
   "add": 4,
   "del": 4
  },
  {
   "path": "src/bitcoin-wallet.cpp",
   "add": 2,
   "del": 2
  },
  {
   "path": "src/bitcoind.cpp",
   "add": 2,
   "del": 1
  },
  {
   "path": "src/common/ecc_init.cpp",
   "add": 35,
   "del": 0
  },
  {
   "path": "src/common/ecc_init.h",
   "add": 21,
   "del": 0
  },
  {
   "path": "src/crypto/sha256.cpp",
   "add": 5,
   "del": 0
  },
  {
   "path": "src/crypto/sha256.h",
   "add": 3,
   "del": 0
  },
  {
   "path": "src/ecc_context.cpp",
   "add": 58,
   "del": 0
  },
  {
   "path": "src/ecc_context.h",
   "add": 41,
   "del": 0
  },
  {
   "path": "src/init.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/kernel/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/key.cpp",
   "add": 14,
   "del": 63
  },
  {
   "path": "src/key.h",
   "add": 0,
   "del": 23
  },
  {
   "path": "src/musig.cpp",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/node/context.cpp",
   "add": 0,
   "del": 1
  },
  {
   "path": "src/node/context.h",
   "add": 2,
   "del": 2
  },
  {
   "path": "src/node/interfaces.cpp",
   "add": 2,
   "del": 2
  },
  {
   "path": "src/pubkey.cpp",
   "add": 28,
   "del": 27
  },
  {
   "path": "src/test/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/test/ecc_context_tests.cpp",
   "add": 62,
   "del": 0
  },
  {
   "path": "src/test/fuzz/bip324.cpp",
   "add": 2,
   "del": 1
  },
  {
   "path": "src/test/fuzz/descriptor_parse.cpp",
   "add": 2,
   "del": 1
  },
  {
   "path": "src/test/fuzz/key.cpp",
   "add": 2,
   "del": 1
  },
  {
   "path": "src/test/fuzz/key_io.cpp",
   "add": 2,
   "del": 1
  },
  {
   "path": "src/test/fuzz/message.cpp",
   "add": 2,
   "del": 1
  },
  {
   "path": "src/test/fuzz/miniscript.cpp",
   "add": 2,
   "del": 1
  },
  {
   "path": "src/test/fuzz/p2p_transport_serialization.cpp",
   "add": 2,
   "del": 1
  },
  {
   "path": "src/test/fuzz/script_assets_test_minimizer.cpp",
   "add": 5,
   "del": 1
  },
  {
   "path": "src/test/fuzz/script_flags.cpp",
   "add": 7,
   "del": 1
  },
  {
   "path": "src/test/fuzz/script_sign.cpp",
   "add": 2,
   "del": 1
  },
  {
   "path": "src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp",
   "add": 2,
   "del": 2
  },
  {
   "path": "src/test/sanity_tests.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/test/util/setup_common.cpp",
   "add": 2,
   "del": 1
  }
 ],
 "test_lines": 255,
 "git": {
  "head": "1c216a069bfebcb5219ff7d7216a4175af83621a",
  "head_matches_backup": true,
  "base": "4519933391dd23dbf1a4eceec6dd53d2e9e71cc3",
  "commits": [
   {
    "sha": "0a0ab68160",
    "subject": "libsecp: generalize context setup and teardown",
    "files": 2,
    "add": 20,
    "del": 18
   },
   {
    "sha": "1253e64d63",
    "subject": "libsecp: encapsulate signing context inside ECC_Context",
    "files": 2,
    "add": 23,
    "del": 20
   },
   {
    "sha": "1fda5a0740",
    "subject": "init: decouple ECC init from primitives",
    "files": 30,
    "add": 94,
    "del": 45
   },
   {
    "sha": "fa2e2dc69f",
    "subject": "libsecp: ECC_Context takes the blinding seed",
    "files": 3,
    "add": 15,
    "del": 11
   },
   {
    "sha": "b44f0da9b2",
    "subject": "refactor: move ECC_Context to ecc_context.{h,cpp}",
    "files": 8,
    "add": 87,
    "del": 62
   },
   {
    "sha": "ee77338bbd",
    "subject": "test: add ECC_Context lifecycle coverage",
    "files": 2,
    "add": 31,
    "del": 0
   },
   {
    "sha": "f61a8a9594",
    "subject": "bench: ECDSA and Schnorr signing and verification",
    "files": 2,
    "add": 119,
    "del": 0
   },
   {
    "sha": "5fb21ed986",
    "subject": "libsecp: plug our hardware optimized SHA256 into libsecp256k1 ctx",
    "files": 3,
    "add": 12,
    "del": 0
   },
   {
    "sha": "99a29f69fd",
    "subject": "libsecp: introduce verification context to ECC_Context",
    "files": 4,
    "add": 23,
    "del": 3
   },
   {
    "sha": "e0d46a42e0",
    "subject": "scripted-diff: use verification context in pubkey.cpp",
    "files": 1,
    "add": 28,
    "del": 27
   },
   {
    "sha": "1c216a069b",
    "subject": "fuzz: use libsecp verification context",
    "files": 3,
    "add": 37,
    "del": 2
   }
  ],
  "patch_truncated": true
 },
 "input_hash": "beed4435f38d8b82",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}