Skip to content

6502 probes: every prior Elite number was measured on ciphertext - #108

Merged
AdaWorldAPI merged 5 commits into
mainfrom
claude/c64-6502-falsifier-shztkk
Aug 26, 2026
Merged

AdaWorldAPI merged 5 commits into
mainfrom
claude/c64-6502-falsifier-shztkk

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

Correction PR. #106 and #107 are on main with numbers measured on encrypted bytes. This decrypts the corpus, re-runs all three probes, and changes three verdicts — one of them from a negative to a positive.

The corpus was encrypted, and Elite documents it

gma4/5/6 are ciphertext. The algorithm is in the game's own elite-checksum.asm — titled "COMMODORE 64 ELITE ENCRYPTION SOURCE": a running-sum chain c[i] = p[i] + p[i+1] walked upward with the seed at the top, KEY1=$36 LOCODE / KEY2=$49 HICODE / KEY3=$8E COMLOD, plus trailing unencrypted padding (3/9/5 bytes) and, for LOCODE, a start offset at G%−B% = 129.

Inverting it reproduces LOCODE.unprot.bin and HICODE.unprot.bin byte-for-byte, 100.00%. COMLOD reaches 23% — it carries a second layer, being the loader itself; not chased.

Not compression: payload sizes are identical (8661/8661, 25312/25312), which is what ruled a packer out.

Scale of the correction

ciphertext plaintext factor
harvested 5,198 108,479 20.9×
classified 1,456 34,186 23.5×
calls 8 1,697 212×
returns 14 414 29.6×
decode error (LOCODE) 37.7% 2.2% —
reached% (code) 0.5–1.1% 29.9–59.9% —

1,697 call sites against the source's 1,087 JSR statements — finally the right order of magnitude.

Three verdicts change

  1. Reachability SEPARATES — CODE [29.9 .. 59.9] vs DATA [0.0 .. 0.9], ranges disjoint, 33× gap, and it does not trip the pre-registered ≥95% kill condition. Code is what a call graph reaches; data is what is only ever loaded from. The prior OVERLAPS was ciphertext.
  2. Content statistics still lose, now for the right reason — decode-error rises to 87.6% balanced accuracy while control-flow density falls to 60.8% (was 77.0%). Real code's cf density (p50 22.8) sits on top of data's (26.6).
  3. A "counterintuitive keeper" is retracted — data does not show higher control-flow density than code. That was ciphertext throughout.

The tell was present and misread

A 38% decode-error rate on supposedly-good code, explained away as "6502 has many undefined opcodes" instead of treated as a question about what the file was. On plaintext LOCODE it's 2.2%. Entropy plus a byte histogram is a two-second corpus check that would have caught this before any probe was written — packed/encrypted data flattens the histogram ($85/$20/$a5 at 5/4/3% collapse to 1/1/1%) and pushes entropy from 7.0 toward 7.9.

Contents: adds examples/reachability_probe.rs; repoints harvest_6502 and slag_partition at the decrypted files; refreshes every stale ciphertext-derived number in the doc comments (zero remaining references to 3742 / 72.1 / 36% pure data).

Gates: clippy --examples -- -D warnings clean, fmt clean, all three probes run end-to-end.


Generated by Claude Code

claude added 3 commits August 25, 2026 21:47
…my own claim

Built to test whether harvest_6502's 3742 residual rows split into
'opcode not yet classified' vs 'data lifted as code'. Uses a CONTROL
GROUP rather than a heuristic: Elite ships known-pure-data binaries
(SHIPS/WORDS/LODATA/IANTOK/SPRITE) beside known-pure-code (LOCODE/
HICODE), both from one build, both given identical treatment.

Negative 1 — the premise was false, and the probe is what showed it.
Elite keeps data in a SEPARATE source file (elite-data.asm -> SHIPS.bin
et al); the harvest corpus gma4/5/6 = COMLOD/LOCODE/HICODE is code. The
blueprints were never lifted as opcodes. Corroborated independently by
the probe's own per-file numbers: both code files sit inside the CODE
range on both metrics. Some tables ARE embedded (QQ23 market prices
lives in elite-source.asm), so contamination is non-zero, but it is not
the bulk of the slag. The reframing that claimed otherwise was wrong.

Negative 2 — content statistics do not partition. Over 208 windows of
256 bytes (>=16 instructions each): decode-error rate reaches 72.1%
balanced accuracy, control-flow density 77.0%. Neither is usable alone.
Direction is counterintuitive and worth keeping: DATA shows HIGHER
control-flow density (p50 26.6 vs 10.6) because random bytes decode into
branch opcodes.

Measured at WINDOW granularity after a correction. The first version
reported whole-file furnace stats and produced two exact duplicate pairs
across unrelated files of different sizes (SPRITE==gma5, SHIPS==gma6):
it handed every sweep block to ONE FunctionBehavior, and CFG::from_blocks
keeps only the component reachable from blocks[0], so those columns
measured a tiny entry-reachable fragment rather than the file. Removed
rather than reported. Remaining metrics come straight off the sweep and
need no SSA.

The untested hypothesis, named rather than implied: reachability. Code is
what a call graph reaches; data is what is only ever loaded FROM. That
cannot be measured on standalone control files (no callers) and needs the
mixed-image setting.
The prek check failed because a hook MODIFIED a file: the typos
spell-checker read the loop variable `thr` as a misspelling of `the`
and rewrote all four uses, which fails prek by definition (hooks that
change files fail the run).

`threshold` is the clearer name regardless, so this takes the
spell-checker's side rather than adding an ignore entry.

Mine, and avoidable: AGENTS.md says to run
`uv run --only-group dev --locked prek` after changing files in this
repo, and I did not. Verified now — typos and rustfmt both Passed on
this file; the harvest artifacts under .claude/ are excluded from every
hook. `--locked` cannot run in this container (pyproject.toml's
`exclude-newer = "P7D"` fails to parse, so uv wants to re-lock), so the
run was unlocked and the uv.lock it touched was restored.

Probe output unchanged: 72.1% and 77.0% balanced accuracy.
Elite's gma4/5/6 images are ENCRYPTED, documented in the game's own
elite-checksum.asm ("COMMODORE 64 ELITE ENCRYPTION SOURCE"): a
running-sum chain c[i] = p[i] + p[i+1] walked upward with the seed at
the top, KEY1=$36 LOCODE / KEY2=$49 HICODE / KEY3=$8E COMLOD, plus
trailing unencrypted padding (3/9/5 bytes) and, for LOCODE, a start
offset at G%-B% = 129.

Inverting it reproduces LOCODE.unprot.bin and HICODE.unprot.bin
byte-for-byte, 100.00%. (COMLOD reaches 23% — it carries a second layer,
being the loader; not chased.) All three probes now read the plaintext.

Scale of the correction, ciphertext -> plaintext:

  harvested   5,198 -> 108,479   (20.9x)
  classified  1,456 ->  34,186   (23.5x)
  calls           8 ->   1,697   (212x)
  returns        14 ->     414
  decode err  37.7% ->    2.2%   (LOCODE)
  reached%   0.5-1.1% -> 29.9-59.9%

1,697 call sites against the source's 1,087 JSR statements is finally
the right order of magnitude.

Three verdicts change:

1. REACHABILITY SEPARATES. CODE [29.9 .. 59.9] vs DATA [0.0 .. 0.9],
   ranges disjoint, 33x gap, and it does not trip the pre-registered
   >=95% kill condition. Code is what a call graph reaches; data is what
   is only ever loaded from. The prior OVERLAPS verdict was ciphertext.

2. Content statistics still lose, now for the right reason: decode-error
   rises to 87.6% balanced accuracy, control-flow density FALLS to 60.8%
   (was 77.0%). Real code's cf density (p50 22.8) sits on top of data's
   (26.6).

3. A "counterintuitive keeper" is retracted: data does NOT show higher
   control-flow density than code. That was ciphertext throughout.

The tell was present from the first probe and misread — a 38%
decode-error rate on supposedly-good code, explained away as 6502
undefined opcodes instead of treated as a question about what the file
was. On plaintext LOCODE the rate is 2.2%. Entropy plus a byte histogram
is a two-second corpus check that would have caught it before any probe
was written.

Adds examples/reachability_probe.rs; repoints harvest_6502 and
slag_partition at the decrypted files; refreshes every stale
ciphertext-derived number in the doc comments.
@coderabbitai

coderabbitai Bot commented Aug 26, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 857738ef-7233-4d48-8833-d432fd1ff250


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cursor

cursor Bot commented Aug 26, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_3ad91662-7cc0-421b-9d06-5bf965870dc8)

claude added 2 commits August 26, 2026 06:10
…fier-shztkk

# Conflicts:
#	crates/ruff_r2il/Cargo.toml
#	crates/ruff_r2il/examples/slag_partition.rs
The pass-1 ore is one row per lifted instruction — ~34k of them, 4.5 MB, all of it
disassembly of a commercial game image. Three reasons it does not belong in ruff:

- Its own header says "evidence, never a re-ingest path. Nothing in ruff parses this
  back." A file nothing reads and a command regenerates is a build product.
- PROVENANCE.md already promises the corpus bytes are never redistributed. A complete
  instruction-level lift of those bytes sits badly beside that promise.
- The codebook side is what carries the finding, and it is small: the census (kind /
  opcode / register counts), the convention, and the slag ledger stay tracked.

`.gitignore` matches `*.ore.tsv` rather than the one filename, so a pass-2 ore is
covered without a second edit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCfrD5y19cvFc4AoyydXYv
@AdaWorldAPI
AdaWorldAPI marked this pull request as ready for review August 26, 2026 06:17
@AdaWorldAPI
AdaWorldAPI merged commit 02cac7c into main Aug 26, 2026
31 of 33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants