I fed a parser 100 files of pure random bytes, 1 MiB each. In 98 of them, it reported finding a memory training table.
Random bytes contain no training tables, obviously. The parser came from a GitHub gist that gets passed around among people unlocking ex-mining GPUs. It documents the firmware layout of a crippled mining variant of a datacenter compute card. I happen to own one; I bought it specifically to unlock its VRAM. The gist also makes a much bolder claim: the 8GB version of this card physically has only 32GB of memory. Mine runs stably with 64GB.
So the question is concrete. A writeup that looks rigorous, full of offsets and signature ranges, ships without the ROMs it analyzed, and I can't rerun the author's experiments. How do I decide which parts to believe?
If you just want the methods, sections 2 and 3 each boil down to one formula. If you want to see where I overreached myself, read section 4.
1. What the writeup looks like
Three files: 27,112 bytes of prose, an 8,805-byte shell script, and an 18,873-byte Python parser. The prose compares seven ROM images and lays out offsets, signed regions, and a guess at the encryption mode.
None of the seven ROMs are attached. No flasher logs, no disassembly, no tests.
Put simply, you get the map but not the survey notes. That's the awkward kind of document: it reads as hard evidence, and you have no direct way to check it.
But the parser is attached. Code runs. That's the way in.
2. Test one: feed it random bytes and see what it reports
The idea is crude: if a format detector frequently says "found it" on random data, its "found it" carries no information.
I generated 100 random 1 MiB files and ran each through the parser's scanners:
| Scanner | Random files where it reported a hit (out of 100) |
|---|---|
| Memory training table | 98 |
| Firmware version / ID | 63 |
| CFG1 config table | 0 |
The CFG1 scanner is clean. Zero hits. Its structural requirements are strict enough that random data can't fake it. The other two are basically fishing for patterns in noise.
That hit rate lets you back out something more useful: how many bits the matcher is actually checking.
A 1 MiB file has roughly 2²⁰ starting positions. If each position matches at random with probability p, and positions are roughly independent:
P(at least one hit per file) r ≈ 1 − e^(−N·p)
Solve for p: p ≈ −ln(1 − r) ÷ N, effective bits checked ≈ log₂(1/p)
It's one division and one log. Plug in the numbers:
- Training-table scanner, r = 0.98 → about 3.9 expected hits per file → p around 1 in 268,000 → roughly 18 bits checked
- ID scanner, r = 0.63 → about 1 expected hit per file → roughly 20 bits
For comparison, a plain 4-byte magic number is 32 bits. In 1 MiB of random data you'd expect 2²⁰ ÷ 2³² = 1/4096 hits, so across 100 files you'd most likely see none.
What does 18 bits mean in practice? A couple of bytes' worth of signature. In a real 1MB ROM, the "training table" it reports might be real, or it might be any two or three bytes that happen to fit. The output gives you no way to tell which.
One caveat: the 18 and 20 bit figures are my estimates from the formula above, which assumes independent positions and uniformly random data. Real ROMs are full of repeated structure and padding, so the false-positive rate there could be higher or lower. What this test proves is that the matcher can't tell signal from noise on random input. It doesn't give you a precise error rate on real firmware.
Reading the source turned up a few more problems you don't even need to run:
- The PCI ROM header finder returns integer
0when the header sits at offset 0, and the caller checksif result:. So the most common valid case gets treated as "not found" - When no training table is found, the early-return structure contains a Python
set, and the finaljson.dumpthrowsTypeError. The docs say every input produces JSON. In reality, a miss crashes it - The comment says it's looking for the signature
RFRD; the code compares against the reversedDRFR. Hand it a canonicalRFRDand it returns nothing - The "per-partition capacity tier table" scanner re-detects the CFG1 table it just found. In my synthetic test ROM both land at offset
0x031000 - The docs say it extracts the subsystem ID. That function's body is a single
pass, and nothing calls it
None of these are hard to fix. What they tell you is that this parser was never systematically tested, and I discount untested tools by default.
3. Test two: "physically 32GB" falls to one subtraction
The gist says the 8GB variant physically has only 32GB (four 8GB HBM stacks). If true, unlocking to 64GB can only mean address aliasing: the upper 32GB of addresses map back onto the lower 32GB, and writing to the top half silently overwrites the bottom half.
Plenty of memory tests can't detect this, and this is the main thing I want you to take away:
Fixed patterns, like all zeros, all ones, or alternating 0101, pass perfectly on aliased memory. Write 0 to address A, write 0 to its alias A', read both back, both are 0. Flawless.
To catch aliasing, the value you write has to depend on the address. My test script writes this into every 8-byte word:
value[i] = seed + i × 0x9E3779B97F4A7C15
Every location gets a different value. If physical capacity P is smaller than test size A, at least A − P bytes must be overwritten by some other address:
overwritten bytes ≥ test size − physical capacity
Plugging in my run: one single allocation, 58 GiB written and fully read back, zero errors. If the card were physically 32GB, at least 26 GiB would have read back wrong values. Zero errors means at least 58 GiB of non-overlapping real storage. The driver and kernel report 65536 MiB with a heap of 0x1000000000 (64 GiB). Since then I've run local models on it with 46.6 to 59.5 GiB resident, across several reboots, with no problems.
"Physically 32GB" is refuted by a subtraction.
4. I overreached too
Since I'm refuting someone else, I owe you one of my own.
Before reading the gist, I had confidently written in my own notes that the 8GB card was "physically 4 × 16GB." I had no evidence for that either. The test above proves exactly one thing: at least 58 GiB of non-overlapping, allocatable, usable address space. How many stacks, how tall each one is, whether some memory partitions in the package are fused off: the test tells me nothing about any of that. Answering those would take an X-ray, a decap to read the die markings, or per-partition probing.
So the accurate claim gets downgraded to: "64GB usable is a fact; the physical topology is unknown." The gist saying 32GB is wrong. Me saying 4 × 16GB is unsupported. Both of us made the same mistake: jumping from one indirect piece of evidence straight to the package layout.
5. Grading the claims you can't test directly
The parser can be run and the capacity can be measured. The rest of the prose has no raw data behind it, so all you can do is read carefully. I sort it into three layers:
Trustworthy: the VBIOS layout diagram, the signed-region boundaries, the table offsets. These come with concrete addresses and cross-ROM comparisons, and they line up with how the existing open-source unlock tool behaves. The explanation of why editing the ROM directly breaks the signature, and why every working unlock patches things at runtime instead, holds together.
Over-extrapolated:
- The headline claims "seven bytes are the complete set of limits." At most it covers the bytes the author attributed to "memory plus PCIe speed policy" in the ROMs they picked. Fuse configuration, runtime compute throttling, the coupling capacitors physically missing from the PCIe lanes, driver-side memory management: none of those are in there
- It says flipping one byte from
44to66is the 64GB unlock. Per the existing unlock tool's source, tier66corresponds to 40GB. My card actually runs stably on tier77(config value0x02779000) - It identifies the encryption as AES-ECB from three pieces of evidence and says things like "CBC can never" and "rules out CTR." All three point toward ECB, but they come from the same batch of ciphertext: three views of one observation, not three independent experiments. I believe it's probably ECB. I don't believe "can never"
Self-contradictory or unstable:
- In the gist's commit history, the known plaintext was changed from
FF×16to00×16and a key index from6to37, then reverted. A "known plaintext" that's been changed and rolled back twice goes in my unresolved pile - One paragraph mentions "16 strap states" and also says the hardware has only three pins,
STRAP0throughSTRAP2. Three bits can only encode 8 states - It mixes up 8Gb dies with 8GB stacks. An 8Gb die is 1GB; you need eight of them stacked to make 8GB
The grading itself is the method: claims with addresses, cross-checks, and agreement with an independent source get trusted; claims that leap from local evidence to global conclusions get downgraded; claims the author has flip-flopped on in their own history get parked.
6. What's wrong with these tests
- The random-input test used uniformly random bytes, which aren't distributed like a real ROM. It proves the matcher can't discriminate; it can't give you the true false-positive rate on real firmware
- Only 100 files. Ratios like 98/100 and 63/100 are plenty to make a call, but I didn't compute confidence intervals for the 18 and 20 bit estimates
- The capacity test was a single 58 GiB write-and-read pass. It rules out aliasing but says little about rare bit flips or long-term retention
- I didn't reproduce any of the claims that need a flasher and disassembly to verify. The grading above is a judgment based on readability and internal consistency, not experimental results
7. Next time you get a reverse-engineering writeup without raw data
- Find anything executable it ships: parsers, scripts, tests. Verify the runnable parts first
- Feed random bytes to every detector or scanner. If the hit rate is above a few percent, use
−ln(1−r) ÷ Nto back out how many bits it really checks. Below 32 bits, don't treat its "found it" as evidence - Read the source for edge cases: offset 0, empty results, and the return value on a miss. Those three are where bugs live
- For any capacity claim, fill memory with address-dependent values and read it back. Fixed-pattern memory tests will happily pass on aliased memory
- Sort the prose into three layers: has addresses and cross-checks; leaps from local to global; flip-flopped in its own commit history
- While refuting someone else, go back and check what your own notes say about the same thing
Nobody, me included, knows how many memory stacks are inside that card. It doesn't care, and keeps running models every day.