Skip to content

refactor(Crypto/LWE): typed Module-LWE games; ML-KEM and ML-DSA share them - #5097

Queued
SamuelSchlesinger wants to merge 83 commits into
mainfrom
readability/lattice-L3m
Queued

SamuelSchlesinger wants to merge 83 commits into
mainfrom
readability/lattice-L3m

Conversation

@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator

Part of #4817 (lattice slice, L3m). It builds on #4889 (negacyclic ring, L3a) and #5017 (L3, typed decision LWE), both on main.

Module-LWE now has the same shape as DecisionLWE. It has one set of games, and the ML-KEM and ML-DSA bounds are stated with them instead of their own copies.

  • New LWE/Module.lean. The Module-LWE part of SIS/Module.lean (sample, flattenPolyVec_sample, encodeSample, sampleLaw, the encoded ensembles) moves here unchanged. The file adds:
    • the fixed-instance experiments ModuleLWE.realExperiment s e D and randomExperiment D, with @[simp] eval_* lemmas;
    • the games ModuleLWE.realGame secretLaw errorLaw D and randomGame D, and ModuleLWE.advantage, the distance between them;
    • realGame_eq_uniform_bind (matrix drawn first) and randomGame_eq (one uniform pair), the orders the scheme proofs use.
  • Bridge to LWE. ModuleLWE.advantage_eq_lweAdvantage: the Module-LWE advantage is the LWE advantage over the ring Negacyclic (ZMod q) n for the coefficientwise images of the laws.
  • Typed assumption. DecisionModuleLWE is Game.Indistinguishable over typed distinguishers, with ModuleLWE.Input, encInput and Distinguisher.IsPPT. decisionModuleLWE_iff_encoded proves it equivalent to the previous word-level statement, so its strength is unchanged; the encoded words are the same (encInput_apply, checked by rfl). Word-level clients use DecisionModuleLWE.encoded. In-tree that is one site, publicKey_indistinguishable_of_decisionModuleLWE, plus the ModuleSIS nonvacuity test.
  • ML-KEM (SIS/MLKEM/Security.lean). mlweRealGame, mlweIdealGame and mlweAdvantage are deleted. advantage_indCpa_uniform_le and indCpaAdvantage_le bound the same quantities by ModuleLWE.advantage with centered-binomial laws. mlweKeyReduction and mlweReduction are now curried typed distinguishers A b ↦ ….
  • ML-DSA (MLDSA/KeyOnly.lean). keyDistinguishGame and koaGame_eq_keyDistinguishGame are deleted. koaGame_keyLaw and koaGame_uniformKeyLaw identify the key-only game with ModuleLWE.realGame for the short laws and with randomGame. succProbability_koaGame_le is stated with ModuleLWE.advantage.

SIS/Module.lean is now Module-SIS only, and its header points to LWE/Module.lean. SIS/Module/ApproximateSampling.lean now imports Probability.Product directly; it had been getting PMF.pi through SIS/Module's LWE.Basic import.

Removed or changed public names.

  • Removed: MLKEM.mlweRealGame, mlweIdealGame, mlweAdvantage. Use ModuleLWE.realGame, randomGame and advantage instead; they give the same games by definition.
  • Renamed: MLKEM.eval_mlweIdealGame_mlweKeyReduction and eval_mlweIdealGame_mlweReduction are now randomGame_mlweKeyReduction and randomGame_mlweReduction.
  • Removed: MLDSA.keyDistinguishGame and koaGame_eq_keyDistinguishGame. Use koaGame_keyLaw and koaGame_uniformKeyLaw instead.
  • Curried signatures: MLKEM.mlweKeyReduction, MLKEM.mlweReduction and MLDSA.forgeryDistinguisher now take the sample components A b (respectively M w, A t) instead of a pair or public key.
  • DecisionModuleLWE is now typed. The word-level form is DecisionModuleLWE.encoded, equivalent by decisionModuleLWE_iff_encoded.
  • ModuleLWE.sample, flattenPolyVec_sample, encodeSample, sampleLaw, realEnsemble and uniformEnsemble keep their names and statements. They move from SIS/Module.lean to LWE/Module.lean, so importers of SIS/Module that use them need the new import.

Tests. New CslibFrontierTests/Crypto/DecisionModuleLWE.lean contains:

  • a concrete sample over ℤ_5[X]/(X^2+1);
  • the rfl word layout;
  • zero advantage for a constant distinguisher;
  • the LWE bridge in use;
  • both directions of the iff.

ModuleSIS.lean uses h.encoded.

Manuals. I updated the Operator's Manual (security-games-and-primitives):

  • the lattice table row (new file; DecisionModuleLWE moved);
  • the LWE paragraph (typed Module-LWE games, the bridge and the iff);
  • the ML-DSA bound;
  • the ML-KEM paragraph, which replaces mlweAdvantage.

The Agent Operator's Manual needs no edit, because this PR adds no workflow or tooling. results/ and ROADMAP.md have no entries for these declarations.

Limitations.

  • DecisionModuleLWE fixes a uniform secret, so it still does not bound the ML-KEM and ML-DSA terms, whose secrets are short. This was already true; the docs now say it at each bound.
  • ModuleEncryption Part 4 (advantage_realEncryptionView_uniform_le, …_msg_le) bounds Game-valued distinguishers over sampleLaw. Moving it onto ModuleLWE.advantage would change those statements, so it is left as is.
  • The ~15-line typed↔word iff proof now appears for DH, ElGamal, LWE and Module-LWE. A shared lemma is proposed on plan(crypto-readability): textbook-shaped experiments and typed adversaries across Crypto (Jetski coordinator 6c737eaa) #4817; it would touch DH/ElGamal, which other lanes own.
  • No relation between DecisionModuleLWE and DecisionLWE at modulus 2 ^ w is proved. The bridge relates the games over the negacyclic ring, not the assumptions.

Validation. lake build --wfail --iofail passed on the 78 affected targets: every importer of SIS/Module, LWE/Module, ModuleEncryption, ML-KEM and ML-DSA, the LWE/Basic closure (Regev, DualRegev, GSW) and their tests. Also clean: mk_all --check, lake lint on the changed modules, the changed-file source lints, hygiene, the ratchets and the manual checker. CI provides the full run.

AI disclosure: authored by the lattice agent (AI) in the readability swarm. Agent review: negacyclic approved 1dec3c3 locally (swarm board #1205); this is not human review.

SamuelSchlesinger and others added 30 commits November 11, 2026 18:32
Refs #4678. Exact conditional ProbComp games and named encoded inputs, with parameterized enc_structure and all clients migrated. Authored with Codex assistance for Samuel Schlesinger.
Preserve both implicit applied-structure support and explicit hygienic parameters. Retain both regression sets and manual guidance. All files outside the 18-file PR scope are identical to main.
Rename the DH challenge field to groupParameters and its type parameter to
GroupParameters throughout games, reductions, certificates and checked clients.
Explain F.Desc and Schnorr parameters (p, q, g) in source and the manual.

Preserve challenge encodings, sampling laws and resource contracts. Strict
builds of the six affected test targets, 14 scoped module lints, source hygiene,
readability ratchets, manual tooling and rendered-manual checks pass.

AI-assisted implementation by Codex under Samuel Schlesinger's direction.
State Boneh–Shoup Attack Games 10.4, 10.5 and 10.6 over a fixed
ZMod q-module G with generator g: adversaries receive and return group
elements, exponents are written a • g, and each experiment is a ProbComp
Bool program evaluated only in its advantage. Add the elementary
reductions dlToCDH and cdhToDDH.

The superseded DDH.realGame/randomGame/advantage stay until DDH-OT
migrates (#4678).

Co-authored-by: Karn Seth <karn@google.com>
dlAdvantage_le_cdhAdvantage_dlToCDH holds in every group.
cdhAdvantage_le_ddhAdvantage_cdhToDDH_add assumes c ↦ c • g injective
on ZMod q. Its one-sided parts (ddhRealExperiment_cdhToDDH and
ddhRandomExperiment_cdhToDDH_apply_true_le) are public so the family
layer can average them over setup with the PMF.bind_apply_* lemmas (#4678).
DDH-OT now uses a • g with [Module (ZMod q) G] throughout, in place of
a.val • g with the hypothesis ∀ y, q • y = 0. The private zmod_val_nsmul_*
helpers are gone; the algebraic identities close by `module`.
ddhOTReduction takes the DDH triple as three group elements.
real_receiver_eq_ddhRealExperiment and ideal_receiver_eq_ddhRandomExperiment
replace the *_ddh_realGame/randomGame lemmas, and
semiHonestAdvantage_ddhOT_receiver_eq concludes
= ddhAdvantage q g (ddhOTReduction g q x D). The sender-privacy theorems
no longer need hq. The superseded Cslib.Crypto.DDH tuple games are
removed, with no wrappers.

New CslibFrontierTests/Crypto/DiffieHellmanFinite.lean checks that the
experiments are nonvacuous:
- guessing 0 gives DL advantage 1/q;
- the identity test accepts with probability 1/q (real) and 1/q² (random),
  so its advantage in ZMod 5 is 4/25;
- a constant distinguisher has advantage 0;
- in ZMod 5, dlToCDH of the identity adversary always wins.

Refs #4678.

Co-authored-by: Karn Seth <karn@google.com>
Stage 1b of the typed Diffie–Hellman redesign. Family games now run core's
fixed-group experiments in `F.Carrier d` after an arbitrary setup draw, and
adversaries receive and return group elements:

- `CDHInput`/`DDHInput` records with `words` views; `encCDHInput`/`encDDHInput`
  are byte-identical to the previous layout (`encCDHInput_apply`,
  `encDDHInput_apply`).
- `fun_prop` rules reading fields of a computed input, including the dependent
  `F.encode x.groupParameters x.leftPublic`.
- `CDHAdversary`, `cdhGame`, `CDH`; `DDHDistinguisher`, `ddhRealGame`,
  `ddhRandomGame`, `DDH`; `cdhToDDHDistinguisher`, `dlToCDHAdversary` (from a
  word-level DL adversary via `discreteLogAdversary`).
- `CDH.discreteLog`, `DDH.cdh`, `DDH.discreteLog` derived from core's
  fixed-group bounds plus the setup average.

The record-dependent rerandomisation, worst-case and amplification sections
are removed in this commit and return, migrated, in stage 2. Clients do not
compile until stage 3.

AI-assisted (spike worker, Jetski swarm).
…oup masks

Add `Probability/PMF/UniformPoint.lean` with
`uniformOfFintype_bind_decide_eq_apply_true` (a uniform draw equals a fixed
point with probability `|α|⁻¹`) and `uniformOfFintype_bind_pure_apply_true_le`
(a test accepting at most one value accepts with probability at most `|α|⁻¹`).
They replace the private copy in EvenMansour, DDH-OT's `hunit`/`hguess`, the
card-filter argument in `ddhRandomExperiment_cdhToDDH_apply_true_le` and the
test file's `uniform_eq_apply`.

Make the fixed-group masks public in `DiffieHellman/Finite.lean`:
`uniformOfFintype_bind_smul_add` (one-time group mask, surjective `c ↦ c • g`)
and `uniformOfFintype_bind_smul` (bijective pushforward, formerly DDH-OT's
private `uniformOfFintype_zmod_bind_smul`).
`PrimeOrderGroupFamily.uniform_smul_generator_add` is now derived from the
former; its statement is unchanged.

Refs #4678
…teLog

Move the encoding-based `DecidableEq (F.Carrier d)` instance from
SchnorrProtocol.lean into DiscreteLog.lean, where every client of the family
sees it; the typed CDH/DDH layer needs it for its equality tests.

Refs #4678
Typed family-level CDH/DDH games (spike). The duplicate encoding-based
DecidableEq (F.Carrier d) instance is dropped; it now lives in DiscreteLog.lean.

Refs #4678
The key-exchange reduction now builds an F.DDHDistinguisher that encodes the
group elements at the call site. Its certificate is hA.preprocess with the
DDHInput field rules (fun_prop). The real/ideal game identities target
ddhRealGame/ddhRandomGame by unfolding the fixed-group experiments.
…istinguishers

Order.lean's identity test is now a typed F.DDHDistinguisher (decide (w = 0)),
certified through the new fun_prop rules computableInPolyTime_encode_generator
and computableInPolyTime_encode_zero in DiffieHellman.lean. Its probability
computations unfold the fixed-group experiments and use the shared
uniformOfFintype_bind_decide_eq_apply_true in place of a private copy.

AI-assisted (spike worker, Jetski swarm).
Add eval_ddhRealExperiment and eval_ddhRandomExperiment, the PMF-level
uniform-bind form that family-game clients unfold to.

Refs #4678
The ElGamal reductions are now typed DDHDistinguishers: they receive group
elements and encode them only where they build the IND-CPA adversary's
public key and ciphertext words. The IND-CPA games keep their encodings.

Key derivation gets a typed KDFDistinguisher (group elements and a key
word), read through encKDFInput = encPair encCDHInput encBits. The bridge
kdfToDDHDistinguisher H runs it on H (d, encode w); its random DDH game is
the real KDF game by unfolding (ddhRandomGame_kdfToDDHDistinguisher), and
isPPTOn_kdfToDDHDistinguisher gives its certificate once. The Hashed
ElGamal DDH reduction is the bridge applied to the KDF reduction, which
removes its separate PPT proof and the two hybrid game definitions: the
hybrids are the KDF games run on the reduction.

KDF.lean: seededDDHDistinguisher and the LHL bound take the typed
distinguishers.

Refs #4678
… KEM

kemToKDFDistinguisher is a typed KDFDistinguisher and kemToDDHDistinguisher
runs it through kdfToDDHDistinguisher, so the random-DDH/real-KDF bridge and
the DDH PPT proof come from the shared Hashed ElGamal lemmas.

Refs #4678
…hed ElGamal

The per-bit and hidden-bit KDF reductions are typed KDFDistinguishers and
the DDH reductions run them through kdfToDDHDistinguisher, so each DDH PPT
proof and random-DDH bridge comes from the shared lemmas. Game 1 is renamed
hashedElGamalCipherRandomDDHGame to match ddhRandomGame.

Refs #4678
…esc-level construction

The two Naor–Reingold DDH distinguishers repeated one body. The desc-level
construction is now public and documented with its PPT certificate, and the
OracleDistinguisher version applies it to adversary n (F.encDesc d).
Add bind_pure_decide_eq_apply_true (with ' and map_ forms) to
PMF/UniformPoint.lean, derive uniformOfFintype_bind_decide_eq_apply_true from
it, and replace the private copies in NextBit and NoCheck.
…tage

LWE.realGame and LWE.randomGame are now fixed-law games over any finite
commutative ring, and LWE.advantage is their distance. DecisionLWE
instantiates them with a uniform secret and independent errors, so
Module-LWE clients with non-uniform secrets (MLKEM, MLDSA) can share the
same games.

Part of #4817.
# Conflicts:
#	CslibFrontier/Crypto/Computational/SIS/Module.lean
…adability/lattice-L3m

# Conflicts:
#	CslibFrontier/Crypto/Computational/SIS/Module.lean
#	CslibFrontierTests/Crypto/ModuleSIS.lean
#	manual/programs-crypto-and-probability/security-games-and-primitives.md
Addresses review thread r4558456561 on #4878: the word-specialized
distinguishing game had its own copy of `Game.withSetup`'s body.

- `distinguishingGame distribution adversary := Game.withSetup distribution
  adversary`; `Computational/Basic` now imports `Crypto.Game.Experiment`
  (which imports only `Crypto.Game` and `Probabilistic.Notation`).
- `eval_bind_eq_distinguishingGame` is `Experiment.eval_bind_eq_withSetup`.
- `distinguishingGame_eq_bind` (rfl) states the sampling form. Proofs that
  unfolded `distinguishingGame` rewrite with it instead, so their simp sets
  and the resulting terms are unchanged (one-token edits, 61 sites).

Names, statements, arbitrary PMF setup laws and the whole-adversary
strict-PPT quantifiers are unchanged.
…experiment

# Conflicts:
#	CslibFrontier/Crypto/Computational/GMW/Simulator.lean
…experiment

# Conflicts:
#	manual/programs-crypto-and-probability/security-games-and-primitives.md
# Conflicts:
#	manual/programs-crypto-and-probability/protocols-and-privacy.md
#	manual/programs-crypto-and-probability/security-games-and-primitives.md
# Conflicts:
#	manual/programs-crypto-and-probability/security-games-and-primitives.md
# Conflicts:
#	CslibFrontier/Crypto/Computational/MLDSA/KeyOnly.lean
#	CslibFrontier/Crypto/Computational/SIS/Module.lean
#	CslibFrontier/Crypto/Computational/SIS/Polynomial.lean
#	CslibFrontier/Foundations/Algebra/Negacyclic.lean
#	CslibFrontierTests/Foundations/Algebra/Negacyclic.lean
#	manual/programs-crypto-and-probability/security-games-and-primitives.md
# Conflicts:
#	manual/programs-crypto-and-probability/security-games-and-primitives.md
@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator Author

Agent review claim: coordinator agy-634bba4c (session 634bba4c-9d3c-4f80-8d5b-6097f495b913) is reviewing head 1dec3c39d15a39bb6286a55fbcd4c76df084c8ce. This is agent review, not human review.

@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator Author

Agent review (negacyclic, AI; not human review): APPROVE at 1dec3c3. Local review of git diff e4f39124c 1dec3c39d before opening, per the freeze rule (board #1205).

  • Statements. DecisionModuleLWE is now typed, and decisionModuleLWE_iff_encoded proves it equivalent to the previous word-level definition, so its strength is unchanged; the word layout is pinned by rfl in the test. The ML-KEM bounds use ModuleLWE.realGame/randomGame/advantage with ProbComp.eval (sampleVecCBD …) laws, the same games as the deleted mlwe* definitions. ML-DSA's koaGame_keyLaw/koaGame_uniformKeyLaw replace keyDistinguishGame, and succProbability_koaGame_le is the same bound.
  • Reuse. Module-LWE keeps its coefficient-vector carrier and connects to the L3 games through advantage_eq_lweAdvantage (LWE over Negacyclic (ZMod q) n). It is a separate representation with a bridge, not a copy of L3's arguments.
  • Placement. Module-LWE now lives in LWE/Module.lean, and SIS/Module no longer imports LWE.Basic. ApproximateSampling's new public Probability.Product import is needed for PMF.pi in its statements. The removed and renamed names are listed in the body.
  • Manuals. Rendered: inspected pp. 436, 442–443 and 456 of cslib-frontier-operators-manual.pdf from run 43397000789. OK, no overflow. The Agent Operator's Manual needs no edit, because it describes no crypto APIs. Registry theorem names and ROADMAP.md are unaffected.
  • Merge. Clean with main e4f3912, with refactor(Crypto/LWE): Regev single-challenge game as a typed lrExperiment; drop Regev/DualRegev projection chains (readability L4a) #5099, and in order onto the current queue.

I'll queue it on green ci-checks/guide once I've checked the notices.

@SamuelSchlesinger SamuelSchlesinger left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coordinator review (coordinator agy-634bba4c, session 634bba4c-9d3c-4f80-8d5b-6097f495b913) of head 1dec3c39d15a39bb6286a55fbcd4c76df084c8ce: APPROVE.

This is agent review, not human review.

What I checked

  • Typed Module-LWE experiments, ring-LWE bridge & word-level equivalence (LWE/Module.lean, SIS/Module.lean, SIS/Module/ApproximateSampling.lean, SIS/ModuleEncryption.lean, CslibFrontierTests/Crypto/DecisionModuleLWE.lean):
    • LWE/Module.lean extracts sample, flattenPolyVec_sample, encodeSample, sampleLaw, realEnsemble, and uniformEnsemble cleanly from SIS/Module.lean (leaving SIS/Module.lean dedicated to Module-SIS) and introduces ModuleLWE.realExperiment, randomExperiment, realGame, randomGame, and advantage, matching the architecture of LWE/Basic.lean.
    • ModuleLWE.advantage_eq_lweAdvantage cleanly identifies ModuleLWE.advantage with LWE.advantage over Negacyclic (ZMod q) n via Negacyclic.coeffsEquiv.
    • DecisionModuleLWE is now Game.Indistinguishable over typed ModuleLWE.Distinguishers (ModuleLWE.Input, encInput, Distinguisher.IsPPT), with encInput_apply preserving the exact framed (1^κ, encodeSample (A, b)) layout (rfl) and decisionModuleLWE_iff_encoded / DecisionModuleLWE.encoded proving equivalence with the word-level ensemble definition.
    • Regression client CslibFrontierTests/Crypto/DecisionModuleLWE.lean exercises a concrete ℤ_5[X]/(X^2+1) evaluation, rfl input layout, zero-advantage sanity check, advantage_eq_lweAdvantage, and both directions of decisionModuleLWE_iff_encoded.
  • Client consolidation (SIS/MLKEM/Security.lean, MLDSA/KeyOnly.lean):
    • MLKEM: deletes bespoke mlweRealGame, mlweIdealGame, and mlweAdvantage, curries mlweKeyReduction and mlweReduction, and states advantage_indCpa_uniform_le and indCpaAdvantage_le directly in terms of ModuleLWE.advantage for the centered-binomial secret/error laws.
    • MLDSA: deletes bespoke keyDistinguishGame and koaGame_eq_keyDistinguishGame, curries forgeryDistinguisher, proves koaGame_keyLaw and koaGame_uniformKeyLaw, and states succProbability_koaGame_le via ModuleLWE.advantage. Both modules and the manual explicitly state that uniform-secret DecisionModuleLWE does not bound short-secret ModuleLWE.advantage.
    • Verified zero remaining references to the removed names across CslibFrontier/, CslibFrontierTests/, CslibFrontierResults/, and manual/, and CslibFrontier.lean adds LWE.Module in sorted order.
  • Local checks & rendered Operator's Manual PDF verification:
    • check_hygiene.py --check-simp, check_projection_chains.py --base e4f39124c, check_changed_files.py --source-only --base e4f39124c, and check_operator_manual.py all pass (0 errors).
    • Visually inspected rendered cslib-frontier-operators-manual.pdf (Operator's Manual PDFs run 43397000789) PDF pp. 436, 442, 443, and 456 (printed pp. 428, 434, 435, and 448) by eye: the lattice table row, ML-DSA paragraph, LWE/Module-LWE paragraph, and ML-KEM paragraph all render cleanly with no overfull boxes or broken links.

This branch has not been deployed

No deployments
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.

1 participant