{
 "number": 35422,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/35422",
 "title": "musig: Require generated secnonce for partial sig",
 "author": "nervana21",
 "author_association": "CONTRIBUTOR",
 "created_at": "2026-05-30T21:16:09Z",
 "updated_at": "2026-08-24T22:41:50Z",
 "age_days": 109,
 "draft": false,
 "labels": [],
 "milestone": null,
 "base": "master",
 "head_sha": "30925f10ce5034e2f1756750d83851f0d4a2c141",
 "head_ref": "reject-partial-signing",
 "head_repo": "nervana21/bitcoin",
 "head_history": [
  {
   "t": "2026-06-08T13:15:20Z",
   "sha": "42fcffb6113768c2e96cde276152b2220b9e18a9"
  },
  {
   "t": "2026-08-24T22:41:40Z",
   "sha": "30925f10ce5034e2f1756750d83851f0d4a2c141"
  }
 ],
 "additions": 50,
 "deletions": 8,
 "changed_files": 4,
 "commit_count": 1,
 "size_bucket": "S",
 "mergeable_state": "blocked",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {},
   "conflicts": []
  }
 },
 "acks_parsed": {},
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 0,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "achow101",
   "real-or-random"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "blocked",
  "last_author_activity": "2026-08-24T22:41:40Z",
  "last_reviewer_activity": "2026-06-01T09:48:59Z",
  "last_reviewer": "real-or-random",
  "author_silent_days": 23,
  "waiting_on_author_days": 0,
  "days_since_update": 23
 },
 "refs": {
  "mentioned": [],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [],
  "conflicts": []
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [],
 "body": "Previously, `MuSig2SecNonce` pre-allocated secure memory in its constructor, so `IsValid()` was true before `secp256k1_musig_nonce_gen` ran. `secp256k1_musig_partial_sign` could be reached with an uninitialized `secp256k1_musig_secnonce` causing `libsecp` to crash.\n\nThis patch defers secure allocation until `CreateMuSig2Nonce` succeeds, guards `CreateMuSig2PartialSig` when no `secnonce` was generated, and adds a unit test for the lifecycle.\n\n## Test plan\n\n`/build/bin/test_bitcoin --run_test=bip328_tests/secnonce_lifecycle`",
 "commits": [
  {
   "sha": "30925f10ce5034e2f1756750d83851f0d4a2c141",
   "date": "2026-08-24T22:39:30Z",
   "message": "musig: Require generated secnonce for partial sig\n\nDefer MuSig2SecNonce secure allocation until secp256k1_musig_nonce_gen\nsucceeds so IsValid() reflects a generated secnonce. Reject\nCreateMuSig2PartialSig when none was generated.\n\nAdd secnonce_lifecycle regression test in bip328_tests."
  }
 ],
 "timeline": [
  {
   "t": "2026-05-30T21:17:17Z",
   "kind": "comment",
   "who": "nervana21",
   "assoc": "CONTRIBUTOR",
   "text": "cc @real-or-random @jonasnick"
  },
  {
   "t": "2026-05-30T21:30:42Z",
   "kind": "comment",
   "who": "achow101",
   "assoc": "MEMBER",
   "text": "It shouldn't be possible to hit any error with this as the nonce is not stored if nonce generation fails.\n\nInstead of a bool that needs to track state, the unique ptr can be created in `CreateMuSig2Nonce` and set after the successful nonce generation."
  },
  {
   "t": "2026-06-01T09:48:59Z",
   "kind": "comment",
   "who": "real-or-random",
   "assoc": "CONTRIBUTOR",
   "text": "[quoted text omitted]\n\nI think you're confusing different abstraction levels here. `secnonce` in the BIP is a byte array of length 64. `secp256k1_musig_secnonce` is a C type. Blobs of that type need more than 64 bytes in memory. And yes, (purported) blobs of that type having an all-zero memory representation are indeed rejected by `secp256k1_musig_partial_sign` (by crashing). But this is not because they represent a `secnonce` of 64 zero bytes; it is simply because don't even represent a valid `secp256k1_musig_secnonce`. Crashing is just a courtesy of libsecp256k1 -- the library could also just invoke UB.\n\nBut none of this should matter for code in Bitcoin Core as a caller of libsecp256k1. The only thing you should make sure as a caller is to pass a `secp256k1_musig_secnonce` to `secp256k1_musig_partial_sign` only if `secp256k1_musig_nonce_gen` succeeded on it."
  },
  {
   "t": "2026-06-08T13:08:45Z",
   "kind": "comment",
   "who": "nervana21",
   "assoc": "CONTRIBUTOR",
   "text": "[quoted text omitted]\n\nThat makes sense. I wasn't able to produce this error manually. It only surfaced during fuzz testing. Would it be helpful to provide the harness that I used?\n\n[quoted text omitted]\nOkay, I've updated the code to take this approach."
  },
  {
   "t": "2026-06-08T13:12:32Z",
   "kind": "comment",
   "who": "nervana21",
   "assoc": "CONTRIBUTOR",
   "text": "[quoted text omitted]\n\nI see now. Thanks for taking the time to explain it to me. I've removed this motivation and instead will focus solely on assuring that `secnonce` generation has already succeeded."
  },
  {
   "t": "2026-06-08T13:15:20Z",
   "kind": "force_push",
   "who": "nervana21",
   "commit": "42fcffb6113768c2e96cde276152b2220b9e18a9"
  },
  {
   "t": "2026-06-08T13:17:40Z",
   "kind": "comment",
   "who": "nervana21",
   "assoc": "CONTRIBUTOR",
   "text": "Rebased off master. Changed approach to that suggested by achow101. Updated motivation to remove misleading reference to BIP327."
  },
  {
   "t": "2026-08-24T22:41:40Z",
   "kind": "force_push",
   "who": "nervana21",
   "commit": "30925f10ce5034e2f1756750d83851f0d4a2c141"
  }
 ],
 "labels_log": [],
 "state_log": [],
 "text_chars": 2609,
 "text_tokens_estimate": 652,
 "changed_paths": [
  "src/musig.cpp",
  "src/musig.h",
  "src/script/sign.cpp",
  "src/test/bip328_tests.cpp"
 ],
 "files": [
  {
   "path": "src/musig.cpp",
   "add": 13,
   "del": 5
  },
  {
   "path": "src/musig.h",
   "add": 6,
   "del": 2
  },
  {
   "path": "src/script/sign.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/test/bip328_tests.cpp",
   "add": 30,
   "del": 0
  }
 ],
 "test_lines": 30,
 "git": {
  "head": "30925f10ce5034e2f1756750d83851f0d4a2c141",
  "head_matches_backup": true,
  "base": "6a028161dafc5679085e5a039a1dc5189bb26d50",
  "commits": [
   {
    "sha": "30925f10ce",
    "subject": "musig: Require generated secnonce for partial sig",
    "files": 4,
    "add": 50,
    "del": 8
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "5641aa5a99e1e29c",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}