Lexiverse
Lexiverse - AI contextual reading engine for English learners. Your next article is your next review.
Differential privacy in the browser — the Laplace and Gaussian mechanisms, composition, and the ε-δ definition, with exact discrete samplers.
Translation pending
EducationTypeScript · HTMLGitHub @systemslibrarianOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Browser-based differential privacy lab — exact discrete Laplace, discrete Gaussian, and textbook float Laplace side by side over a twelve-person payroll, with a likelihood ratio that hits the ±ε rails, a differencing attack that recovers a salary to the dollar, and a fail-closed budget ledger that refuses the averaging attack
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗Differential privacy · ε-δ · Laplace mechanism — runs the real Laplace and Gaussian mechanisms over a twelve-person payroll so you can watch what DP actually promises about two databases that differ by one person. Not that they become impossible to tell apart: that an attacker's odds of telling them apart move by at most a factor of e^ε. The advantage is bounded, never eliminated — the optimal attacker still succeeds with probability (1 + tanh(ε/2))/2, and the page shows that number next to the bound. Then watch even that guarantee evaporate when the budget is spent.
Live demo: https://systemslibrarian.github.io/crypto-lab-dp-noise/ Teaching with it: TEACHING.md — prerequisites, 15/30/60-minute routes, discussion prompts, expected misconceptions, and which interactions are stochastic.
Differential privacy (Dwork, McSherry, Nissim & Smith, TCC 2006) is a promise about a computation, not about a released table: for every pair of databases differing in one person's record, and every possible output x,
Pr[M(D) = x] ≤ e^ε · Pr[M(D′) = x]
Everything else follows from that inequality. Bayes turns it into a bound on belief — an observer who thought it an even chance you were in the data cannot end up more than e^ε/(1+e^ε) sure — and that is the sentence ε actually buys.
This page implements the mechanisms rather than describing them:
b·ln(u) over a double is what nearly every tutorial does, and it is what Mironov (CCS 2012) turned into a recovery attack.All live randomness comes from crypto.getRandomValues. The payroll mechanisms use exact rational ε and exact rational Bernoulli comparisons. The geo exhibit is intentionally different and says so wherever it runs: it samples the ideal planar density with 53-bit IEEE-754 uniforms, so it is a bounded teaching implementation, not the paper's finite-precision digital mechanism and not an exact discrete sampler.
The location lesson was checked against Andrés, Bordenabe, Chatzikokolakis and Palamidessi, Geo-Indistinguishability: Differential Privacy for Location-Based Systems, CCS 2013 / arXiv:1212.1984: Definition 3.1 and §§3–5.3. The ideal planar mechanism comes from §§4.1–4.2; the radial utility calculation follows Observation 5.1 and Proposition 5.2; the repeated/correlated-location limits follow §§3.3 and 5.3. The 7 × 7 normalised exponential grid is this lab's separate bounded counterexample/control, not a reproduction of the paper's finite-precision calibration.
Security model: a statistical guarantee against an adversary with unlimited computing power and unlimited side knowledge, bounding what can be concluded about any one individual. It is not a cryptographic primitive; nothing here is encrypted. This is not production code — it is a teaching demo.
The page is a lesson with a reference inside it, and it opens as the lesson.
src/ui/curriculum.ts) drives three things that used to be three parallel lists able to drift apart: the objectives stated up front, the core path's four steps, and the exit challenge's four questions. An objective with no interaction behind it, or an interaction nothing tests, is now not expressible.b = Δ/ε at the current values, what an attacker's belief could reach, and what one release would cost the session ledger. Unlink it to park two exhibits at different ε.order, so reading and focus order stay in step with the visual order.See TEACHING.md for lesson routes and debrief answers.
Σₓ (Pr[M(D)=x] − e^ε·Pr[M(D′)=x])₊ — that the failure costs. The panel also prints two numbers that turn out to be identical, and explains why: the total variation distance between two discrete Laplace distributions one step apart is exactly tanh(ε/2), so the optimal attacker's success rate (1 + tanh(ε/2))/2 is exactly the belief bound e^ε/(1 + e^ε). The mechanism is tight in both senses at once, and the suite asserts the equality at every stop on the ladder.A second expert card in Exhibit 1 implements the two repairs to k-anonymity and then shows a repeated-release disclosure that neither single-table criterion rules out. It is on the Explore everything route only; the guided route and the four core steps are unchanged by it, and nothing on it marks a core step established.
Both terms name a family, and this page implements one member of each and says so everywhere it appears.
| Implemented here | Stated as | NOT implemented |
|---|---|---|
| distinct ℓ-diversity — every equivalence class contains at least ℓ distinct sensitive values | Li, Li & Venkatasubramanian, ICDE 2007, §2, item 1, attributed there to Machanavajjhala et al. | entropy ℓ-diversity (Machanavajjhala et al. Definition 4.1) and recursive (c, ℓ)-diversity (Definition 4.2), both strictly stronger |
ordered t-closeness — every class's distribution is within Earth Mover distance t of the whole released table's, under the ordered ground distance |i − j|/(m − 1) | Li et al. Definition 2 (the t-closeness principle) with §5.1 (numerical attributes) | the equal and hierarchical ground distances of §5.2, and every other distance the principle admits |
A note on attribution that matters: the ICDE 2006 ℓ-diversity paper this lab read does not define "distinct ℓ-diversity" as a definition of its own. It states the ℓ-diversity principle ("at least ℓ well-represented values") and instantiates it as entropy and recursive diversity, observing only that entropy ℓ-diversity implies at least ℓ distinct values. The name "distinct ℓ-diversity" is Li et al.'s, in §2, where it arrives with its own warning: "Distinct ℓ-diversity does not prevent probabilistic inference attacks." This page uses that name and that warning.
Primary texts checked: Machanavajjhala et al., ICDE 2006, Li et al., ICDE 2007, and Ganta et al., KDD 2008.
Li et al. §5.1 derive, for r_i = p_i − q_i:
D[P, Q] = (1/(m − 1)) · ( |r₁| + |r₁+r₂| + … + |r₁+…+r_{m−1}| )
Their second form sums i from 1 to m; the two agree because the final partial sum is zero. This lab sums all m terms and asserts the final term is zero at every class of every release, so the identity is checked rather than assumed.
Nothing is computed in floating point. With c_i the cumulative count in the class, C the class size, g_i the cumulative count in the table and N the table size:
D = ( Σᵢ |N·c_i − C·g_i| ) / ( (m−1)·C·N )
— a BigInt numerator over a BigInt denominator. The verdict D ≤ t is a cross-multiplication, numerator · t.d ≤ t.n · denominator, so no rounding can decide a pass. The declared t = 9/64 is exactly the largest class distance in all three releases that pass, which puts the "no more than t" boundary on screen instead of in a sentence.
Sixteen synthetic records, one per (ZIP prefix, age decade) cell, with an ordered five-band sensitive domain. Its b3/b4 edge matches the lab's integer-dollar query exactly: b3 includes $100,000 and b4 begins at $100,001, because the query asks for salaries more than $100,000. Global distribution (4, 3, 3, 4, 2)/16.
| Release | k | distinct ℓ | max class EMD | Meets k ≥ 4, ℓ ≥ 3, t = 9/64 |
|---|---|---|---|---|
| ZIP to 3 digits + age to 20-year bands | 2 | 1 | 29/64 | no — one class is unanimous (b1 twice): the homogeneity attack |
| Age to 10-year bands | 4 | 3 | 17/64 | no — the 30–39 class holds {b1, b2, b3}, three distinct bands all below $100,000: the similarity attack |
| ZIP to 3 digits | 4 | 3 | 9/64 | yes, at equality |
| Age split at 30 | 4 | 3 | 9/64 | yes, at equality — the independently compliant age release used below |
| Age to 20-year bands | 8 | 4 | 9/64 | yes, at equality — the repaired release |
Every one of those numbers is recomputed from the rendered rows by a browser claim test that implements the EMD itself and never reads a verdict label.
The utility metric is one declared query, not a score: "how many people are in their thirties?" A record is certain when its published age range lies entirely inside the question and merely possible when the ranges overlap without containment, so a release answers with an interval and the number reported is its width.
[4, 4], ambiguity 0.[0, 8], ambiguity 8, against a true answer of 4.That is the trade, derived from the rows of each release. Li et al. say the same thing about their own criterion: t-closeness "limits the amount of useful information that is released, as it limits information about the correlation between quasi-identifier attributes and sensitive attributes. However, this is precisely what one needs to limit."
The attack is a bounded adaptation of the intersection attack in Ganta, Kasiviswanathan and Smith, KDD 2008 (arXiv:0803.0032), §1.1.1. Alongside two linked releases of the same population and the stated target background, it makes explicit the two properties the paper highlights: exact sensitive value disclosure ("the sensitive value corresponding to each member of the group is published exactly") and locatability ("given any individual's non-sensitive values ... one can locate the group in which individual has been put in").
In this bounded adaptation the declared sensitive value is the salary band, not the raw dollar salary. Each published class exposes its exact band multiset (the counts shown above), from which the attacker obtains the candidate-band set. The result below therefore establishes disclosure of one exact published band; it does not claim recovery of the underlying salary.
Two releases of the same sixteen people, published independently, each meeting the full declared policy — 4-anonymous, distinct 3-diverse and 9/64-close:
{b2, b3, b4};{b1, b4, b5}.This is a bounded constructed counterexample. The unequal age partition (four records under 30, twelve records 30 and over) is declared up front and chosen to make both individual releases satisfy the policy; it is not presented as output from Mondrian, Incognito or an optimisation algorithm. What the run establishes is existence: satisfying these three single-table criteria does not make this pair compose safely.
Neither reveals the target's exact band or high-earner predicate on its own: each release still narrows the target to three bands, and each candidate set straddles the $100,000 boundary. Intersected, they leave {b4} — the exact band, and with it the same secret the counting query in Exhibit 2 exists to protect.
The raw registry printed on the page is explicitly labelled omniscient teaching ground truth, not an attacker-visible release. Before the attack runs, publishRelease removes record ids, names, exact ages and salaries. The attacker receives only the two published class views plus explicit background observations — ZIP prefix 981** and “under 30” — and is never passed the target record or real band. The truth is compared with the result afterwards; tests assert that the public projection contains no target identity or salary and move the target between bands to confirm the attack follows the published values rather than retained truth.
This is residual disclosure, not unique identification — the attacker never learns which row is the target — and one constructed counterexample is not a composition theorem. The cited paper measured the effect across two census datasets; that is a different claim and is not reproduced here.
The repaired release is a deterministic function of the table. Take the output event "the serialised release equals the exact string produced on the database that contains the record". On the registry that event has probability 1; on the neighbouring registry with the target removed, the serialisation differs, so it has probability 0. ε-DP would require 1 ≤ e^ε · 0, and no finite ε satisfies that. The two serialisations are computed and compared on every run; the flag is withTarget !== withoutTarget and both branches of that comparison are tested.
The scope is kept narrow, on the page and here:
k-anonymity vs distinct ℓ-diversity · distinct vs entropy vs recursive ℓ-diversity · similarity and skewness attacks vs homogeneity · class distribution vs whole-table distribution · a release criterion vs a randomised neighbouring-world mechanism · one release vs linked repeated releases · what record linkage assumes vs what the table shows outright · residual disclosure vs unique identification · synthetic teaching data vs production de-identification.
Increasing k, raising ℓ or tightening t does not buy a monotonically increasing amount of privacy, and the page shows why rather than saying so: raising k above leaves the homogeneity disclosure untouched, a distinct 3-diverse class still discloses which end of the scale someone is on, and two releases that each meet every displayed criterion still reveal an exact band when combined. Li et al. say of their own measure that "the relationship between the value t and information gain is unclear", and quote the pair (0.01, 0.99) vs (0.11, 0.89) sitting at the same EMD as (0.4, 0.6) vs (0.5, 0.5).
The twelve-person payroll could not carry this lesson, and the reason is recorded rather than papered over. Salary tracks department there almost exactly, so every generalisation that separates the target from the low-paid support staff leaves them a unanimous class, and every generalisation that does not leaves the target's candidate set unchanged. No pair of independent releases of those twelve rows both satisfies a stated k/ℓ/t policy and intersects to something new about one person. Rather than weaken a release until an attack appeared, this exhibit declares a second sixteen-row synthetic registry built for the job. Nothing in src/dp/database.ts is touched, and a unit test asserts the payroll's k, its homogeneity leak and its record count are exactly what they were.
| Claim on the page | Code | Test |
|---|---|---|
| every record is in exactly one class, at every release | describeRelease via analyse in kanon.ts | partitions the registry at every release |
| measured k and distinct ℓ per release | describeRelease, distinctBands | %s is %s-anonymous and distinct %s-diverse |
| the class and whole-table band counts | countBands | computes the exact counts the README prints; uses the WHOLE table as the reference distribution |
| the exact EMD and its normalisation | orderedEmd | hand calculations on two- and three-point domains; has a final cumulative term of exactly zero; normalises by (m−1)·C·N |
| the t verdict, including equality | meetsThreshold | passes below t, passes AT t, and fails above it; is met at equality by all three passing releases |
| distinct ℓ passes where t fails | ClassReport.noneAboveThreshold | finds a distinct 3-diverse class whose values are all below the threshold |
| the repaired release meets all three | describeRelease | is repaired by a release that meets k, ℓ and t together |
| the utility interval and its width | answerAgeQuery | derives the truth from the actual rows, at every release |
| each release meets its stated criteria alone | describeRelease | publishes two releases that each satisfy the stated k, ℓ and t on their own |
| the attacker gets no hidden record state | publishRelease | removes identities and raw salaries before the attacker runs |
| the intersection, from attacker-visible rows only | intersectReleases | narrows five bands to one, and the one is right; reads the published rows, and tracks them when they change; follows the target's own band when that band changes |
| this event rules out finite ε for the deterministic release |
Malformed inputs fail explicitly rather than returning a number: an empty class, an empty table, a mismatched or one-value domain, negative/fractional/inconsistent counts, a zero denominator or negative value in either side of the threshold comparison, an unreadable published age range, a backwards query range, missing or ambiguous attacker observations, an unknown release id, and a neighbouring-world request for a record that is not in the table.
b·ln(u) over a double-precision uniform does not have the Laplace distribution — it has one with gaps and duplicated masses whose low-order bits depend on the true answer. Mironov (CCS 2012) recovers the answer from them. Exhibit 4 offers this mode, labelled; the page's default draws only exact rational Bernoullis.ε/(gridSteps + 1), not ε/gridSteps).Ledger.request does — it returns null, and the caller is required to treat that as "no answer exists".ε = 0.5 in Exhibit 7 means 0.5 km⁻¹ on a local Euclidean plane. Changing kilometres to metres without changing ε changes the guarantee by a factor of one thousand.https://systemslibrarian.github.io/crypto-lab-dp-noise/
Run the differencing attack and recover a salary. Drag ε and watch two distributions merge. Declare a salary bound, then meet the person who does not fit it. Run the averaging attack and take the true payroll back, then spend a budget until the mechanism refuses to answer. Four ideas, about fifteen minutes, and a navigator that tells you which one you are on.
Then switch to Explore everything for the rest: play twelve rounds of the guessing game, watch the Gaussian sail through the ±ε rails, compare deployed ε values, and run the planar location mechanism through its exact metric bound, sampled utility, finite-map failure and repeated-release transcript.
| Deployment | Model | ε | Provenance |
|---|---|---|---|
| Apple — keyboard and emoji telemetry | Local | ≈ 16/day | Measured by outside researchers (Tang et al. 2017) |
| Google RAPPOR — Chrome telemetry | Local | ε∞ ≈ 2.04 | Derived from the Chrome parameters in the paper's §5.4, f = 0.75 with h = 2 hash functions (Erlingsson et al. 2014) |
| US Census 2020 — redistricting file | Global | 17.14 at δ = 10⁻¹⁰ | Published; budgeted as ρ = 2.63 in zCDP |
The 2020 Census is the largest deployment of differential privacy ever attempted and the one with the most at stake — the PL 94-171 file draws voting districts.
npm install
npm run dev # http://localhost:5173/crypto-lab-dp-noise/
npm test # current unit suite; prints the live test/file totals
npm run build # typecheck + production build
npm run test:a11y # accessibility/reflow gates in the pinned dark theme (needs a build first)
npm run test:mutations # clean baseline, then 22 focused source mutations (8 geo, 14 release-criteria)
npm run test:a11y runs two suites. e2e/a11y.spec.ts is the axe conformance sweep — every exhibit driven through its states on both routes, in the lab's pinned dark theme at desktop and phone width. e2e/task.spec.ts is the one that asks whether the lesson can actually be completed: the whole core path with a keyboard alone, the same path at 375 × 667 asserting no horizontal overflow with every disclosure open, and every core conclusion read out of the data tables with the SVGs removed from the document. Automated WCAG checks are necessary and they do not establish that a dense mathematical interaction is operable.
The current Vitest suite is executed in CI before deploy; npm test prints its live test and file totals. What it actually pins down:
bernoulliExpNeg is checked against e^−γ at five values of γ — the CKS20 parity is easy to transcribe inverted, which silently yields Bernoulli(1 − e^−γ), a sampler that looks right and is exactly wrong. uniformBelow is χ²-tested for modulo bias. The discrete Laplace's sampled PMF, mean and variance are checked against the closed form; the discrete Gaussian's mean and variance against σ.e^ε to six digits — attained, not merely respected — and needs a δ below 1e-12. Asserted twice: once over a comfortable range, and once over the range Exhibit 2 actually examines, which is about fifteen times wider. That second assertion exists because the first one passed while the page disagreed with it — out past roughly 75 lattice steps both PMFs underflow to zero in a double, so a ratio taken as the quotient a/b returned Infinity and the bound was reported as broken at ε = 7 and ε = 10 for a mechanism that meets it exactly. The ratio is now taken from the closed-form log ratio, which never underflows.e^ε, not on which mechanism is selected; Exhibit 4b's refusal branches on isPrivateCalibration applied to where that choice's Δ came from, not on the option's name; and Exhibit 1 derives "recovered exactly" from recovered === truth. A banner that cannot come out the other way establishes nothing, so none of these is written as a literal.h. Theorem 1 of Erlingsson et al. is ε∞ = 2h·ln((1 − f/2)/(f/2)), where h is the number of Bloom-filter hash functions — an easy factor to drop, because it sits outside the logarithm, and dropping it reports a guarantee twice as strong as the paper proves for Chrome's h = 2. A test asserts the linear scaling in h and pins the Chrome parameters (f = 0.75, h = 2, §5.4) to ε∞ ≈ 2.043.Statistical assertions run on a seeded generator, so a failure means the sampler is wrong rather than that a coin landed badly. The page itself uses crypto.getRandomValues and never Math.random().
Accessibility gates, both blocking the Pages deploy:
@axe-core/playwright scans the production build for zero WCAG 2.1 A/AA violations in the lab's pinned dark theme across the complete state drive — every exhibit, both routes, sampled and refusal states, all disclosures, desktop and phone reflow. Exhibit 7 adds its idle, invalid, sampled-utility, four-release and twelve-release states to that same gate.The exact samplers are the expensive part, and deliberately so. A discrete Laplace draw costs about 1/γ geometric trials, so the 4,000 draws behind Exhibit 3's histograms run in a few hundred milliseconds at ε = 1 and are chunked across animation frames — the motion on this page is the computation, never decoration. Queries with a large Δ are released on a coarse lattice for the same reason: an exact integer sampler at Δ = $250,000 would need minutes per draw. Readers who ask for reduced motion get the same work done in one pass.
Part of 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
b√2/√n curve until the true payroll is recovered — from answers that were each, individually, differentially private.ε·distance; samples the polar mechanism and compares current-run error with the exact radial CDF and mean; measures whether a noisy point still selects the nearest service; and lets an observer compare two candidate paths from the released transcript alone. A separate 7 × 7 grid shows that directly truncating and renormalising exp(−εd) at a border can exceed the requested bound, while a half-rate control stays within it. That grid is a separate teaching construction, not the finite-precision mechanism of the paper.neighbourContrast, separatesWorlds |
| computes the two neighbouring releases rather than asserting the conclusion; distinguishes a separating event from an event that establishes nothing |
| the payroll results are unchanged | — | leaves the payroll table and every result computed from it untouched |
b√2/√n. k is measured at every generalisation level, and the homogeneity leak is asserted at k = 3 and k = 6.expand — the option the page refuses — is asserted to give different sensitivities for neighbouring databases, which is the leak stated as a test. The bias/noise trade is asserted to run in opposite directions across the offered bounds, and the best bound is asserted to depend on ε rather than on the data alone, because an exercise whose answer never changes is not a decision.update never touches the completion set, and the store opens on the guided route with cryptographic randomness — a default that silently flipped to seeded would make every "this is the real mechanism" claim on the page false.npm run test:mutations first requires every owning suite to pass unmodified, then makes twenty-two concrete source edits — eight covering geo density normalisation, likelihood orientation, radial CDF/sampling, finite-grid normalisation/audit and transcript accounting, and fourteen covering distinct-value counting, the reference distribution, the EMD normalisation factor, a dropped and a reversed cumulative term, ≤ versus < at the threshold, a scenario label standing in for the computed verdict, the age-partition boundary, secret-bearing fields in the public projection, a dropped release in the intersection, ground truth leaked into the attacker, an inverted deterministic-release event check, a stale utility truth and a collapsed query interval. Every edit must fail its named owning test; the runner restores and hashes the sources, then reruns the clean baseline before accepting the run.