All notable user-visible changes to this plugin are documented here. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
1.9.1 - 2026-05-30
- Signature output now labels addresses with the containing function name.
GeneratedSignature.display,XrefGeneratedSignature.display, and the function-signature action append(funcname)to printed addresses when the address lies in a named function, falling back to the bare address otherwise. The address is always kept, so distinct anchors in the same function stay distinguishable. (#47)
1.9.0 - 2026-05-30
Find shortest unique signature for current functionworst case drops from ~12 s to ~1 s on large databases. Profiling on 200 MB+ modules found the remaining cost was not the index or the refinement kernel but two leftovers, both now fixed: the seed-candidate map ran in a pure-Python loop over the whole seed bucket, and patterns whose seedable prefix was all wildcards fell back to a full-buffer scan. (#45)
- New
seed_offsetsCython kernel maps a seed bucket to the candidate start array (thep - sshift, the fit guard, the n-1 boundary) undernogil, the same pattern asrefine_offsets. This was the lastO(C0)loop left in Python; moving it to C cut the worst observed function search from ~12 s to ~1 s. (#45) - Seeding is deferred for all-wildcard prefixes instead of running an
O(N)masked scan when no exact byte is available to key the index. (#45) - Adversarial refinement microbenchmark (
tests/perf/adversarial_refine.py, with a--checkregression guard) plus cross-check tests pinning the Cython kernels to their Python fallbacks. Block refinement and sorted-bucket spaced-seed intersection were measured and shelved. (#45) - Signatures produced are byte-identical to 1.8.0; only the speed of finding them changed. (#45)
ALGORITHM.mdgains a table of contents, a "Rejected optimizations" section explaining why the two upgrades above were shelved, and notes on theseed_offsetskernel and deferred seeding. (#45)
1.8.0 - 2026-05-29
Find shortest unique signature for current functionis faster again on large databases, and the gap widens as the database grows. The per-starting-point seed scan is replaced by a two-byte position index built once per search, so each starting point is seeded from the rarest byte run in its pattern in time proportional to that run's frequency, not the database size. About 2.48x over 1.7.3 on a 16 MB module. (#35)- The seed is now chosen from the most selective run, one byte or two. A single rare byte can be more selective than a common two-byte pair, so the search picks whichever run has the smallest index bucket. (#36)
- Two-byte bucket position index built in the Cython
_speedupsextension as anogilcounting sort; one-byte buckets telescope from it for free (a range view, no second index). (#35, #36) - Per-byte candidate refinement moved into the Cython extension (
refine_offsets): in-placenogilcompaction over a typed uint32 buffer with zero per-call allocation. Refinement on the largest function of a 16 MB module dropped from ~14 s to ~0.28 s; that function's total search fell from ~24 s to ~15.6 s. (#36) _ByteIndexis a frozen slots dataclass; the runtime array module is aliased aspy_stdlib_arr_modto keep it distinct from the cimported C-level API. (#36)- Signatures produced are byte-identical to 1.7.3; only the speed of finding them changed. (#36)
- New
ALGORITHM.mdderiving the match-set math, the counting-sort index, the selectivity proof, and what is novel about the approach. README gains a table of contents, a Performance section with benchmarks, and a library stability contract for downstream embedders. (#36)
1.7.3 - 2026-05-28
Find shortest unique signature for current functionis dramatically faster on large databases. The search now scans the database once per starting point to seed a set of candidate match offsets, then refines that set in memory as the signature grows, instead of re-scanning the whole database on every byte. A function that previously took minutes now finishes in seconds. (#33)- The live
Matches:count is back, and exact. Candidate refinement tracks the surviving match count for free at every step, so theCreate unique signaturewait box shows the real count again and the function-search wait box shows an exact inner count instead of the temporary2+placeholder. (#27, #33)
- The
Start Profiling/Stop Profilingmenu items now appear. They were attached at plugin init, before IDA builds its menus, so they silently never showed. They are now attached through the disassembly right-click popup, grouped with the main action under aSigMakersubmenu. (#33)
- New
SignatureSearcher.find_all_offsets(seed scan returning raw buffer offsets) and_refine_offsets(in-memory candidate refinement). Uniqueness checks belowMIN_USEFUL_SIG_BYTESuse a cheap early-bail probe so the enumerating seed scan is deferred until the pattern is long enough to be selective. (#33) - Cancellation polling in the scan loops is throttled (every 65536 matches) so
idaapi.user_cancelled(), which pumps the UI event loop, does not dominate a scan over a common pattern. (#33) - Signatures produced are byte-identical to 1.7.2; the change is purely how quickly they are found and that exact match counts are restored. (#33)
1.7.2 - 2026-05-28
- Live wait-box progress for the
Create unique signatureandFind shortest unique signature for current functionactions. The wait box updates as the search runs: current signature length and elapsed time for both, plus function bounds, current anchor, inner-search bounds, best size, and candidate count for the function search. (#27, #30) - Self-describing wait boxes. Every action's wait box now leads with the action name and a one-line explanation of what it is doing, so a screenshot always identifies which action produced it. (#30)
start_profiling/stop_profilinghelpers, exposed asEdit/Pluginsmenu actions, for capturing a cProfile dump of a slow run from inside IDA. (#30)
Find shortest unique signature for current functionis dramatically faster. Uniqueness checks now stop at the second match instead of enumerating every match in the database, and the segment buffer is loaded once per search instead of once per growth step. A function search that previously took minutes on a large database now completes in seconds. (#31)- Wait-box refresh throttle default is now 1 second (previously 100 ms), so the box does not repaint faster than it can be read. (#27, #30)
- The live
Matches:count is temporarily removed from theCreate unique signaturewait box. Counting every match on every growth step was the search's bottleneck; the wait box still shows the growing length and elapsed time. A future release restores an exact count cheaply via incremental candidate refinement. (#27, #30)
MinimalFunctionSignatureGeneratordecodes each function instruction once up front and grows anchors over the cached data, instead of re-decoding per anchor. (#31)SignatureSearcher.is_uniquestops at the second match;count_matchesstill enumerates fully for callers that need the exact count (such as partial-on-cancel). (#31)- The compiled
_speedupsSIMD extension now loads from a sibling directory when the package-level import resolves to a namespace package without a matching compiled build (dev and symlink layouts). (#31)
1.7.1 - 2026-05-27
- New
Find shortest unique signature for current functionaction on the main form. Iterates every instruction in the containing function as a possible start point, growing a signature from each (bounded by function end and by the current best candidate's size), and returns the smallest unique result with the fewest wildcards. Output annotates the address with an offset into the function so you can see exactly where the unique sequence sits. (#17, #26) - Automatic xref fallback for the new action. If no unique signature exists anywhere in the function body (e.g., the function is a small thunk identical to many others), the action falls back to generating signatures rooted at each code xref into the function and picks the best. Output reads
Xref signature into 0x... (from 0x...):. (#17, #26)
WildcardPolicy.for_x86()no longer wildcardso_immimmediates. An immediate like the0x13371338inmov rcx, 0x13371338is a literal value baked into the instruction encoding; it does not shift between binary builds, so wildcarding it only removed bytes that would have made the signature unique. Memory addresses (o_mem), jump/call targets (o_far,o_near), and architecture-specific register operands still get wildcarded. This is a strict improvement to every action withwildcard_operands=True, including the existingCreate unique signatureandFind shortest XREF signatureactions. (#26)GeneratedSignature.__lt__now ranks by(size, wildcards)ascending instead of just size. Same-length signatures with fewer wildcards rank first. The existingFind shortest XREF signatureaction picks this up for free, picking more specific candidates as the "best" result. (#26)- README acknowledgements clarified to better reflect the historical relationship between this plugin and the broader SigMaker ecosystem.
- New
MinimalFunctionSignatureGeneratorclass implements the function-wide search with monotonic best-size pruning and an ideal-candidate early exit (size <= 5 bytes and zero wildcards stops the outer loop). - New
Action.FIND_FUNCTION_SIG = 4enum value for the new form action. - Integration test coverage exercises both the function-search end to end and the x86 immediate preservation against the compiled test binary.
1.7.0 - 2026-05-27
- Wait-box cancel for long signature generation. A non-blocking wait box now appears while sigmaker is searching, with a Cancel button you can click at any time to stop the search cleanly. Replaces the previous default of recurring "Continue?" modal popups. Canceling produces a clean
Operation canceled by usermessage in the output log, with no traceback. (#18, #24) - Opt-in
Enable continue promptcheckbox on the main form. Ticking it restores the previous periodic prompt behavior for anyone who prefers it. Off by default. (#24) - Opt-in
Prompt intervalfield in the "Other options..." dialog. Sets how many seconds to wait before the first periodic prompt fires;-1disables the prompt entirely. Default-1. (#24) - Opt-in
Output partial signature on cancelcheckbox on the main form. When ticked, canceling a unique-signature search emits the partial signature with a match count instead of nothing. Off by default; output goes to the console only (no clipboard write) so an accidental cancel cannot clobber the clipboard. (#22, #25)
- Default cancel UX. Out of the box, a sigmaker search now shows a wait box with a Cancel button instead of firing periodic "Continue?" popups. The popup behavior is preserved as the new opt-in described above. (#18, #24)
- Canceling a unique-signature search no longer misreports as "Signature not unique".
InstructionWalkernow raises a properUserCanceledErroron cancel rather than swallowing it asStopIteration, which the generators were treating as "ran out of instructions". The user now seesOperation canceled by user, not a confusing error. (#18, #24) - Wait-box Cancel button now actually cancels.
CheckContinuePrompt.should_cancelnow pollsidaapi_user_canceled()so the wait-box Cancel propagates through the progress reporter regardless of whether the periodic prompts are enabled. Previously the button was effectively a no-op unless the modal popup was the one being dismissed. (#18, #24) - User-facing cancel message now matches the rest of the codebase. The output line on cancel is
Operation canceled by user(US English), aligning with the spelling used everywhere else in the plugin. - Partial-on-cancel match count no longer reports
0. When the user clicks Cancel mid-search, the internal match-counting also bails (it polls the same cancel flag), and would return a partial count of0. The generator now preserves the most recently completed iteration's count instead, so users see e.g.Partial signature (NOT unique, 3 matches)rather than0 matchesormatch count unavailable. (#22, #25)
- New
ActionIntEnum replaces the bare0/1/2/3magic numbers inSigMakerPlugin.run's dispatch. - New
GenerationStatusenum andGenerationPolicydataclass formalize the opt-in vocabulary for partial-on-cancel. GeneratedSignaturenow carriesstatusandmatch_countfields.SignatureSearcher.count_matchesexposes the per-iteration database scan count thatis_uniquewas already computing and discarding.InstructionWalker.end_eadefault is resolved lazily viadefault_factoryso runtime patches ofidaapi.BADADDRtake effect (testability fix).