{
 "number": 36475,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/36475",
 "title": "bench: add BIP-352 pubkey extraction benchmarks (standard + P2PKH worst-case)",
 "author": "theStack",
 "author_association": "MEMBER",
 "created_at": "2026-10-08T14:30:11Z",
 "updated_at": "2026-10-21T07:37:27Z",
 "description_hash": "d14d4db9ff29cef7",
 "age_days": 24,
 "draft": false,
 "labels": [
  "Tests"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "56c0f168d1a81b19e4cd71ef81e7ce2d9c1624e3",
 "head_ref": "bip352-bench-pubkey_extraction",
 "head_repo": "theStack/bitcoin",
 "head_history": [
  {
   "t": "2026-10-08T14:36:13Z",
   "sha": "747514aeb45271219e38ef0e091fe9a3300b4a0e"
  },
  {
   "t": "2026-10-10T16:17:17Z",
   "sha": "d14be50b1140cb7df7745048a3fe0f826be6a37b"
  },
  {
   "t": "2026-10-10T16:25:31Z",
   "sha": "457bb990c52e70b07ced2e3476573f8532911d6b"
  },
  {
   "t": "2026-10-10T16:34:14Z",
   "sha": "56c0f168d1a81b19e4cd71ef81e7ce2d9c1624e3"
  }
 ],
 "additions": 112,
 "deletions": 0,
 "changed_files": 2,
 "commit_count": 2,
 "size_bucket": "M",
 "mergeable_state": "unknown",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "ack": [
     {
      "login": "Yudis-bit",
      "url": "https://github.com/bitcoin/bitcoin/pull/36475#issuecomment-6233551410"
     },
     {
      "login": "fametrano",
      "url": "https://github.com/bitcoin/bitcoin/pull/36475#issuecomment-6310687100"
     }
    ],
    "concept_ack": [
     {
      "login": "w0xlt",
      "url": "https://github.com/bitcoin/bitcoin/pull/36475#issuecomment-6065831573"
     }
    ]
   },
   "conflicts": []
  }
 },
 "acks_parsed": {
  "w0xlt": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-10-08T17:52:20Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 1,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "Yudis-bit",
   "fametrano",
   "w0xlt"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "unknown",
  "last_author_activity": "2026-10-10T17:07:26Z",
  "last_reviewer_activity": "2026-10-21T07:37:23Z",
  "last_reviewer": "fametrano",
  "author_silent_days": 22,
  "waiting_on_author_days": 11,
  "days_since_update": 11
 },
 "refs": {
  "mentioned": [
   36338,
   36417
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 36338,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-10-07",
    "title": "BIP-352: fix P2PKH pubkey extraction from malleated scriptSig"
   },
   {
    "number": 36417,
    "type": "pull",
    "state": "closed",
    "merged": false,
    "merged_at": null,
    "title": "bip352: verify redeem script and pubkey hash in GetPubKeyFromInput"
   }
  ],
  "conflicts": []
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [],
 "body": "As there are ongoing changes to the Silent Payments public key extraction function `GetPubKeyFromInput` (see recently merged #36338, upcoming #36417), it seems reasonable to add benchmarks for it. The first commit covers the standard shape of each eligible input type (P2PKH, P2SH-P2WPKH, P2WPKH and P2TR script-path spend; see [BIP-352](https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#user-content-Inputs_For_Shared_Secret_Derivation)). The second adds a worst-case P2PKH input with a maximally malleated scriptSig, where every push has to be hashed during the scan.\n\nResults on my arm64 machine (as per `$ ./build/bin/bench_bitcoin -filter='BIP352_.*'`):\n\n|            ns/input |             input/s |    err% |     total | benchmark\n|--------------------:|--------------------:|--------:|----------:|:----------\n|            3,034.12 |          329,584.35 |    0.2% |      0.01 | `BIP352_GetPubKey_P2PKH`\n|           69,868.20 |           14,312.66 |    0.1% |      0.01 | `BIP352_GetPubKey_P2PKH_WorstCase`\n|            2,841.35 |          351,945.44 |    0.1% |      0.01 | `BIP352_GetPubKey_P2SH_P2WPKH`\n|            2,768.00 |          361,272.01 |    0.1% |      0.01 | `BIP352_GetPubKey_P2TR`\n|            2,757.57 |          362,637.66 |    0.0% |      0.01 | `BIP352_GetPubKey_P2WPKH`",
 "commits": [
  {
   "sha": "d71bc7127f0ce06da96476456160799e817f0a14",
   "date": "2026-10-09T17:38:13Z",
   "message": "bench: add benchmarks for BIP-352 pubkey extraction (standard inputs)\n\nBenchmark the public key extraction (`GetPubKeyFromInput`) for the\nstandard shape of each Silent Payments eligible input type, i.e.\nP2PKH, P2SH-P2WPKH, P2WPKH and P2TR. For P2TR, a script-path spend is\nused, as it runs all of the key-path extraction logic plus the control\nblock checks and the NUMS-H internal key comparison."
  },
  {
   "sha": "56c0f168d1a81b19e4cd71ef81e7ce2d9c1624e3",
   "date": "2026-10-10T16:33:55Z",
   "message": "bench: add worst-case P2PKH benchmark for BIP-352 pubkey extraction\n\nAdd a P2PKH input with a malleated scriptSig that prepends as many\n33-byte pushes as the consensus scriptSig size limit (MAX_SCRIPT_SIZE)\nallows, each of which has to be hashed during the scan, followed by the\nactual signature and public key. The input respects all other consensus\nlimits (data pushes don't count towards MAX_OPS_PER_SCRIPT, the stack\nstays below MAX_STACK_SIZE), but is non-standard as it exceeds\nMAX_STANDARD_SCRIPTSIG_SIZE.\n\nResults on my arm64 machine:\n```\n$ ./build/bin/bench_bitcoin -filter='BIP352_.*'\n[...]\n\n|            ns/input |             input/s |    err% |     total | benchmark\n|--------------------:|--------------------:|--------:|----------:|:----------\n|            3,021.72 |          330,937.16 |    0.1% |      0.01 | `BIP352_GetPubKey_P2PKH`\n|           69,754.07 |           14,336.08 |    0.1% |      0.01 | `BIP352_GetPubKey_P2PKH_WorstCase`\n|            2,839.92 |          352,122.64 |    0.2% |      0.01 | `BIP352_GetPubKey_P2SH_P2WPKH`\n|            2,756.93 |          362,722.60 |    0.1% |      0.01 | `BIP352_GetPubKey_P2TR`\n|            2,752.45 |          363,312.34 |    0.0% |      0.01 | `BIP352_GetPubKey_P2WPKH`\n\n```"
  }
 ],
 "timeline": [
  {
   "t": "2026-10-08T14:36:13Z",
   "kind": "force_push",
   "who": "theStack",
   "commit": "747514aeb45271219e38ef0e091fe9a3300b4a0e",
   "id": "push:747514aeb45271219e38ef0e091fe9a3300b4a0e"
  },
  {
   "t": "2026-10-08T17:52:20Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "Concept ACK",
   "id": "c:6065831573",
   "url": "https://github.com/bitcoin/bitcoin/pull/36475#issuecomment-6065831573",
   "hash": "e8334cc43879b73c",
   "edited": null
  },
  {
   "t": "2026-10-09T02:53:47Z",
   "kind": "comment",
   "who": "Yudis-bit",
   "assoc": "NONE",
   "text": "Concept and approach ACK.\n\nNumbers make sense given that `IsFullyValid()` point validation dominates the standard paths. In `P2PKH_WorstCase`, hoisting `pubkey_candidate` outside the while loop in `GetPubKeyFromInput` would save ~290 heap reallocations across the dummy pushes.\n\nIt might also be worth adding `P2TR_ScriptPath` and `P2TR_ScriptPath_NUMS` to benchmark the control-block validation and the early rejection path.",
   "id": "c:6073283486",
   "url": "https://github.com/bitcoin/bitcoin/pull/36475#issuecomment-6073283486",
   "hash": "9e14cfbf47fb6ced",
   "edited": "2026-10-09T03:07:49Z"
  },
  {
   "t": "2026-10-10T16:17:17Z",
   "kind": "force_push",
   "who": "theStack",
   "commit": "d14be50b1140cb7df7745048a3fe0f826be6a37b",
   "id": "push:d14be50b1140cb7df7745048a3fe0f826be6a37b"
  },
  {
   "t": "2026-10-10T16:25:31Z",
   "kind": "force_push",
   "who": "theStack",
   "commit": "457bb990c52e70b07ced2e3476573f8532911d6b",
   "id": "push:457bb990c52e70b07ced2e3476573f8532911d6b"
  },
  {
   "t": "2026-10-10T16:34:14Z",
   "kind": "force_push",
   "who": "theStack",
   "commit": "56c0f168d1a81b19e4cd71ef81e7ce2d9c1624e3",
   "id": "push:56c0f168d1a81b19e4cd71ef81e7ce2d9c1624e3"
  },
  {
   "t": "2026-10-10T17:07:26Z",
   "kind": "comment",
   "who": "theStack",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nDue to the strong similarity I think it's fine to have only a single representative P2TR benchmark, but I switched the one from key-path to script-path spending as the pubkey extraction contains (slightly) more logic. Also fixed the IWYU CI error. Thanks for the review!",
   "id": "c:6100051112",
   "url": "https://github.com/bitcoin/bitcoin/pull/36475#issuecomment-6100051112",
   "hash": "0a28be284cbfde7f",
   "edited": "2026-10-10T17:18:17Z"
  },
  {
   "t": "2026-10-17T11:51:23Z",
   "kind": "comment",
   "who": "Yudis-bit",
   "assoc": "NONE",
   "text": "re-tACK 56c0f168d1\n\nMakes sense to stick to one P2TR case. Windows numbers:\n\n|            ns/input |             input/s |    err% |     total | benchmark\n|--------------------:|--------------------:|--------:|----------:|:----------\n|            4,660.44 |          214,571.81 |    0.2% |      0.01 | `BIP352_GetPubKey_P2PKH`\n|           81,266.67 |           12,305.17 |    0.2% |      0.01 | `BIP352_GetPubKey_P2PKH_WorstCase`\n|            4,624.56 |          216,236.72 |    0.4% |      0.01 | `BIP352_GetPubKey_P2SH_P2WPKH`\n|            4,330.00 |          230,946.88 |    0.6% |      0.01 | `BIP352_GetPubKey_P2TR`\n|            4,335.53 |          230,652.50 |    0.2% |      0.01 | `BIP352_GetPubKey_P2WPKH`",
   "id": "c:6233551410",
   "url": "https://github.com/bitcoin/bitcoin/pull/36475#issuecomment-6233551410",
   "hash": "73844640dee4809c",
   "edited": null
  },
  {
   "t": "2026-10-21T07:37:23Z",
   "kind": "comment",
   "who": "fametrano",
   "assoc": "CONTRIBUTOR",
   "text": "tACK 56c0f168d1\n\nThe five benchmarks build and run on an Apple M5 (Release build, `bench_bitcoin -filter='BIP352_.*' -min-time=2000`, three runs). The four standard inputs take 2.2-2.6 \u00b5s each. The worst case, a 10,000-byte P2PKH scriptSig with 291 dummy pushes, takes 39-43 \u00b5s. I also rebuilt the five input shapes independently. A separate BIP352 implementation (btclib-wallet) extracts the expected key from each.",
   "id": "c:6310687100",
   "url": "https://github.com/bitcoin/bitcoin/pull/36475#issuecomment-6310687100",
   "hash": "9ef116da8389680b",
   "edited": null
  }
 ],
 "labels_log": [
  {
   "t": "2026-10-08T14:30:16Z",
   "action": "labeled",
   "label": "Tests",
   "who": "DrahtBot"
  },
  {
   "t": "2026-10-08T14:37:12Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-10-10T17:32:31Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 4897,
 "text_tokens_estimate": 1224,
 "changed_paths": [
  "src/bench/CMakeLists.txt",
  "src/bench/bip352.cpp"
 ],
 "files": [
  {
   "path": "src/bench/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/bench/bip352.cpp",
   "add": 111,
   "del": 0
  }
 ],
 "test_lines": 112,
 "git": {
  "head": "56c0f168d1a81b19e4cd71ef81e7ce2d9c1624e3",
  "head_matches_backup": true,
  "base": "8406af1c0d69fa3ad4d50abb5d329354ad81445b",
  "patch_id": "d854c47c109ed677",
  "commits": [
   {
    "sha": "d71bc7127f",
    "subject": "bench: add benchmarks for BIP-352 pubkey extraction (standard inputs)",
    "files": 2,
    "add": 86,
    "del": 0
   },
   {
    "sha": "56c0f168d1",
    "subject": "bench: add worst-case P2PKH benchmark for BIP-352 pubkey extraction",
    "files": 1,
    "add": 26,
    "del": 0
   }
  ],
  "patch_truncated": false
 },
 "patch_id": "d854c47c109ed677",
 "input_hash": "b8f54b0e1219e41a",
 "extracted_at": "2026-11-02T01:09:49+00:00"
}