neuron-explorer
Qwen3.5‑4B 전용 조향형 뉴런 탐색기, 모든 MLP 뉴런을 밀어 결과를 보관·탐색
읽을 때마다 달라지는 내용을 동일한 키로 변환해 공개 도우미 데이터의 비밀 비용을 정확히 확인합니다
Turn a reading that is never the same twice into the same key every time, and see exactly how much secrecy the public helper data costs.
개발 도구TypeScript · CSSGitHub @systemslibrarian온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Browser-based fuzzy-extractor demo — turn a noisy reading that never repeats into the same key every time with a code-offset secure sketch over hand-built BCH codes and HKDF-SHA-256, and measure exactly what entropy the public helper data costs.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Turn a reading that is never the same twice into the same key every time, and see exactly how
much secrecy the public helper data costs.
An interactive lab for fuzzy extractors: the construction that turns a noisy, non-repeatable
physical measurement into a stable cryptographic key, at a cost in secrecy you can write down
before you build anything.README 전문 보기 ↗Fuzzy extractors · code-offset secure sketch · BCH · HKDF-SHA-256
Turn a reading that is never the same twice into the same key every time, and see exactly how much secrecy the public helper data costs.
An interactive lab for fuzzy extractors: the construction that turns a noisy, non-repeatable physical measurement into a stable cryptographic key, at a cost in secrecy you can write down before you build anything.
The exact primitives on the page:
c and publishes h = w XOR c. Reproduction
computes h XOR w' = c XOR e, decodes to c, and recovers w = h XOR c.The security model, stated plainly. For a binary linear [n, k] code used in the code-offset
construction, and any source W with min-entropy m, the sketch leaves
Hinf~(W | SS(W)) >= m - (n - k)
That is the average min-entropy of the source given the helper data — how hard W still is to
guess for someone holding everything that was published. It is an upper bound on the loss, not
an estimate of it, and it holds for non-uniform sources without modification.
In Dodis, Ostrovsky, Reyzin and Smith this is Theorem 5.1: an [n, k, 2t+1] code over F
gives an average-case (F^n, m, m − (n − k)f, t) secure sketch, and over the binary alphabet
f = 1. It rests on their Lemma 2.2(b) — a published value with at most 2^λ possibilities
costs at most λ bits of average min-entropy, and the syndrome has exactly 2^(n−k) of them.
Construction 2 is the code-offset construction, and the paper says outright that over the
binary alphabet it is the Juels–Wattenberg commitment SS(w) = w ⊕ C(x); Construction 3
publishes the syndrome directly, and the two are proved equivalent in both directions — which is
the equality the Enrol & Reproduce panel measures on screen. Lemma 4.1 builds the fuzzy
extractor from a sketch plus an average-case strong extractor.
These numbers were read from eprint.iacr.org/2003/235, the revision dated 20 January 2008, which is the journal version — not from the printed SIAM pages. Numbering can differ between a preprint and the copy-edited article, so every statement is given in full here and on the page as well; check those rather than the numbers if the two disagree.
Three things it is not:
n − k bits — it lowers m, so the same subtraction can leave nothing. The page shows the
residual going below zero and says there is no guarantee left, which is a different statement
from "the helper leaks more".There is no physical device in this page. A browser has no PUF and cannot acquire one, so the cell readings come from an explicit model whose parameters are on screen. Everything downstream of the readings — the error-correcting code, the helper data, the key derivation — is real.
There are two ways in. Guided tour is the default: five scenes, one thing to press at a time, each scene's result directly beneath its own action, and the whole argument in about ninety seconds. Explore freely is the six-panel lab below, with every control.
A persistent scenario bar names the settings every exhibit is reading — Healthy source,
Too noisy, Weak source, or Custom — with the code, the re-read noise, the residual bound, and
a Reset. Before it existed, pressing the weak-source button on one panel silently re-tuned the
device for every other one, and a visitor who moved between exhibits afterwards was reading a
different experiment without being told.
w, h = w ⊕ c, w', h ⊕ w', the repair, the
recovered reading, the key — ending on the two keys compared byte for byte.w, a uniformly random codeword c, the published helper h = w XOR c, a later reading w',
the offset h XOR w', the decode that finds and undoes the flips, the recovered reading, and
the key. Every point where two things should be equal is compared byte for byte on screen.
A three-column split keeps secret, public and derived apart. Push the bit-error rate past
the code's radius and the real decoder fails, naming its own failure code; choose BCH(15, 7)
and it will sometimes mis-correct instead — returning a perfectly well-formed key that is
simply the wrong one.1 − P(Binomial(n, BER) ≤ t) with no fitted parameter, with 95% intervals drawn and
decode failures and mis-corrections counted separately.m, minus n − k, equals the residual — which is
allowed to reach zero and go below it, and is drawn below zero when it does. Beside it, a
measured guessing attack that uses only public data, and a sweep across the whole bias range
showing how far apart "the bound stops promising" and "the attack starts winning" really are.
This panel holds the negative claim (below).h1 XOR h2 = c1 XOR c2, a codeword —
the reading cancels. With a noisy re-read the XOR exposes which cells flipped, not what they
hold. The "bits of the reading the second helper added" counter is counted, not asserted:
every candidate is enumerated. A deliberately broken variant — drawing the codeword from half
the code — makes that same counter move, which is what makes the zero a result.n − k bound does not
apply, because that was its hypothesis. The Enrolling Twice panel ships this as a marked, broken
variant: reproduction still works perfectly and the first helper costs 11 bits instead of 8.Every lab here declares at least one security property its construction does not provide, and backs it with a state you can reach:
Reproducing the key correctly is not evidence that any secrecy is left. This construction raises no failure code for a source that never had enough min-entropy: enrolment, decoding and reproduction behave identically whether the residual bound is 64 bits or 50 bits below zero.
The Weak-source fixture button on panel 4 drives the page into exactly that state. Every check the construction performs reports success — the decoder corrects, the codeword matches, the recovered reading matches, the key matches byte for byte, the syndrome equivalence holds — and the key has already been recovered from the published data by the attacker running beside it. The headline verdict reads KEY REPRODUCED — AND RECOVERED FROM PUBLIC DATA.
e2e/claims.spec.ts asserts all three halves of that: that the state is reachable through the UI,
that every construction check in it reports pass (swept across the page, not sampled), and that the
limitation is visible on screen in that state rather than hidden behind a disclosure.
Use a fuzzy extractor when the secret you want is a measurement rather than a stored value: an SRAM PUF device key, a ring-oscillator or arbiter PUF, a biometric template you must not store. The appeal is that between power-ups there is nothing on the chip to find.
Do NOT use one when:
n − k bound is arithmetic; m is an
empirical fact about your hardware, and the whole guarantee is their difference. A fuzzy
extractor over an uncharacterised source is a key derived from an unknown quantity.https://systemslibrarian.github.io/crypto-lab-drift-key/
Power the device up twice and see the cells disagree. Step through the enrolment one line at a time and watch the key come back byte for byte. Push the bit-error slider past the code's radius and break it. Run a few thousand reproductions and lay the measurement over the prediction. Then raise the cell skew, watch the residual bound cross zero, and run the attack that takes the key out of the public helper data.
git clone https://github.com/systemslibrarian/crypto-lab-drift-key.git
cd crypto-lab-drift-key
npm install
npm run dev # http://localhost:5173/crypto-lab-drift-key/
npm test # 175 unit tests (Vitest)
npm run build # typecheck + production build
npx playwright install chromium
npm run test:a11y # the WCAG 2.1 AA gate, desktop and 380px
npm run test:claims # 28 claims tests, incl. the negative claim and the experience assertions
205 tests, all passing: 175 unit (Vitest), 28 claims and 2 accessibility scans (Playwright).
Known-answer and exhaustive verification:
| What | Where |
|---|---|
| RFC 5869 HKDF-SHA-256 vectors A.1, A.2, A.3, through the lab's own call path | src/crypto/kdf.test.ts |
BCH (n, k) against the published parameter table, 16 codes | src/crypto/bch.test.ts |
BCH(15, 7) over its whole 2^15 space: the decoder corrects exactly the words inside a ball of radius t and fails on exactly the words outside every ball, judged by a brute-force nearest-codeword oracle that shares no arithmetic with it | src/crypto/bch.test.ts |
| Every codeword × every error of weight ≤ 2 (15,488 decodes), and every weight-3 pattern (58,240) confirming a decode past the radius never returns the sent codeword | src/crypto/bch.test.ts |
| GF(2^m) table multiplication against carry-less multiply-and-reduce, exhaustively for m = 3…8 | src/crypto/gf2m.test.ts |
syn(h) = syn(w), and that a coset has exactly 2^k members, by enumeration | src/crypto/sketch.test.ts |
| Measured reliability within four standard errors of the binomial prediction, seeded | src/model/trials.test.ts |
| The attacker module's imports, parsed from its own source (invariant I5) | src/model/attacker.test.ts |
The experience is tested too. Correctness tests could not see the defect that mattered most:
every claim in the suite passed while the strongest result in the lab rendered 1003px below the
button that produced it in a 900px viewport, with the scroll position unchanged — a visitor could
press the marquee control and watch nothing happen. So reachability is now a claim like any other.
e2e/claims.spec.ts asserts that the first action is visible without scrolling on desktop and
within 1.25 viewports at 390px; that guided mode never offers more than one primary action at a
time; that every guided action leaves its result inside the viewport; that the punchline arrives in
five primary actions; that the scenario bar names the shared state and Reset restores it; and that
colour tracks system integrity rather than the return value — the device reproducing its own key is
green, the attacker deriving that same key is an alarm, from the same component.
Accessibility. npm run build && npm run test:a11y must pass with zero violations, at
1280px and at 380px, and it gates the deploy. The gate is the honest form: it injects nothing into
the page, reveals no panel from script, asserts axe's incomplete bucket as well as violations,
and adds the three oracles axe has no rule for — arithmetic composite-aware contrast, non-text
contrast ratcheted against an empty baseline, and reflow. It found three real defects on its
first runs, each fixed in the source rather than baselined.
Mutation discipline. A green suite is not evidence until you have watched it fail. Six mutations were applied to the source, each confirmed to build cleanly and change the shipped bundle before its owning test was checked:
| Mutation | Result |
|---|---|
| Delete the negative-claim sentence | the §4.1d fixture fails on assertion 3, naming the missing text |
| Invert the byte-for-byte comparison | the fixture fails on assertion 2: key-match reports fail |
| Report the promised leak instead of the measured one in the reuse counter | THE COUNTER MOVES fails: "8 bits, not the 8 the construction promises" |
residual = m + (n − k) instead of m − (n − k) | 5 unit tests and 2 claims tests fail |
Degrade --control-border below 3:1 | the a11y gate fails naming every tab at 1.90:1 |
Degrade --text-dim below 4.5:1 | the a11y gate fails with axe violations at every driven state |
The gate went on earning its place after that. Restructuring the page into two modes moved <main>
inside the container that starts hidden, and the gate failed the arrival state on
landmark-one-main before a human would have noticed the document had no main landmark at all.
One mutation left everything green: removing the decoder's final "is the corrected word really a
codeword?" check. Under §4.1c that is evidence about the source, so it was measured rather than
explained away — across the entire 32,768-word space of BCH(15, 7) and 20,000 heavy-error decodes
over all five codes, DECODE_RESIDUAL_SYNDROME never fires; the Chien root-count test catches every
inconsistent locator first. The check stays, because it is the last thing standing between
"corrected" and a best guess, but the finding is recorded in bch.ts, asserted in bch.test.ts,
and stated on the page's own failure-code table rather than letting the lab list a code it cannot
raise.
Every trial runs the whole pipeline — enrol with a fresh random codeword, derive a real HKDF-SHA-256 key, reproduce, compare key bytes — rather than shortcutting to a Hamming-weight test that would agree with the prediction by construction. In a worker, on a laptop: about 2,700 reproductions in 210 ms on BCH(127, 64), and about 5,400 in 1.5 s on BCH(255, 131). The exhaustive BCH(15, 7) test suite decodes about 139,000 received words, cross-checking most of them against a brute-force search over all 128 codewords.
One of the browser demos in the Crypto Lab suite.
"So whether you eat or drink or whatever you do, do it all for the glory of God." — 1 Corinthians 10:31