fix(quagmire3): default alignment to keyed alphabet's first letter - #3
Merged
Conversation
QuagmireIII.decode/encode defaulted the ACA alignment letter to a hardcoded straight-'A', which silently returned garbage for any keyed alphabet whose first letter is not 'A'. The only existing test vector (AUTOMOBILE/HIGHWAY) cannot catch this because there header[0] == 'A', so the two conventions coincide. The codebase's own solver already documents and emits the correct convention (`# Q3: ... align = first keyed letter`, keys formatted as KEYWORD/INDICATOR/<first-keyed-letter>), so decode was inconsistent with crack. Default the alignment to the keyed alphabet's first letter (header[0]) — i.e. a plain Vigenere in the keyed alphabet. AUTOMOBILE/HIGHWAY is unchanged; an explicit third key field (/A, /E, ...) still forces any alignment. Adds a regression test with a non-'A' keyword (MONARCHY) that the AUTOMOBILE vector cannot cover. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ty test Two general primitives distilled from a cryptanalysis session. ciphers/progressive_key: ProgressiveKey.crack now recovers with NO keyword hint. The progression is recovered first — undoing the per-group progression re-aligns every group onto one keyword cipher, snapping the de-drifted columns from flat back to peaked, rankable by column IoC alone (no dictionary word). The top few (period, base, progression) triples are then fully solved (keyword by per-column English fit) and scored. Previously crack returned [] blind; it now returns keyless candidates (meta.keyless=True). Reliable at adequate length (~240+ letters for period 7); returns an honest junk-scored best-of below that. Tunable via max_period / prefilter. analysis.heldout_stationarity: a held-out transfer test for whether a period-p additive key is stationary. Fit the per-coset shifts on the first half, measure how well they pool the held-out remainder, z-scored against a within-coset-shuffle null that preserves each coset's multiset (hence any flattener's marginal). This is the flattener-matched control a naive comparison lacks — without it a strong flattener alone reads as spurious non-stationarity. Power scales with length, so at short n the test is honestly inconclusive rather than false-positive. Complements ioc_decay. Tests, CHANGELOG updated; ruff + mypy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EJjjwhsWqwb5GRvD4QiA5i
…gnment c3d0f79 changed QuagmireIII's default alignment from straight-'A' to the keyed alphabet's first letter (the canonical Quagmire-III convention) but left the hand-tuned INDICATOR in test_quagmire_longkey keyed to the OLD 'A'-aligned ciphertext. Under the new (correct) alignment the resulting ciphertext differs, so the deterministic cold 1-opt -> 2-opt path traps at a near-miss instead of an exact recovery, and test_cold_one_opt_traps_but_two_opt_recovers failed in CI. The solver itself is unaffected (the dictionary-attack round-trip test still passes). Re-tune the fixture to a new random 40-letter INDICATOR that, under the current canonical alignment (no explicit third key field), still traps the cold 1-opt pass and is then recovered exactly by the 2-opt finisher -- preserving the test's intent without reverting to the non-canonical alignment. Note added so it is re-tuned if the default alignment ever changes again. Full `-m "not slow"` suite green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EJjjwhsWqwb5GRvD4QiA5i
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.