Skip to content

refactor(Crypto/SigmaProtocol): typed computational special HVZK (Attack Game 20.4 at one index) - #5023

Merged
SamuelSchlesinger merged 58 commits into
mainfrom
readability/sigma-s3
Nov 13, 2026
Merged

SamuelSchlesinger merged 58 commits into
mainfrom
readability/sigma-s3

Conversation

@SamuelSchlesinger

@SamuelSchlesinger SamuelSchlesinger commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator

Part of #4817 (crypto readability, sigma slice S3). It builds on I1 #4878 (TwoStage), #4874 (dependent enc_structure … using) and #4892 (the ProbComp → PMF lift), all of which have landed. Session: Jetski worker sigma (conversation 2e0d52f3), branch readability/sigma-s3.

Attack Game 20.4 / Definition 20.6 (computational special HVZK, Boneh–Shoup §20.4.2) now uses typed adversaries and is stated at one index first.

  • chvzkExperiment R conv A is the game at one index. A : TwoStage Unit (X × Y) (T × C × Z) Bool σ chooses a typed pair and a state, and guesses on a typed conversation. A PMF Game (refactor(encodings): reuse sublist bounds for encoded lists #225, Decision 1): the honest conversation is a PMF. advantage_chvzkExperiment_le bounds it by ε when the conversation laws are ε-close on valid pairs, for every adversary.
  • chvzkRealGame/chvzkSimGame draw i ← setup n, then run the experiment. ComputationalSpecialHVZK.indistinguishable quantifies over every state type σ and encoding encσ.
  • CHVZKAdversary.IsPPT clocks choose on (1^n, i) with output ((encW i x, enc.statement i y), encσ state), which is the old layout at σ := List Bool, and guess on the enc_structure record encCHVZKGuessInput.
  • The word simulator is kept. simulatedConversation decodes its words (decodeConversation); output that does not decode makes that run output false. EfficientSpecialHVZK, Schnorr and Computability/Interactive are unchanged.
  • The game bodies bind programs directly through the ProbComp → PMF lift of feat(Languages/Probabilistic): lift programs into distributions by their law #4892 (let ((x, y), state) ← A.choose (); likewise A.guess and the simulator run). Proofs rewrite the lift back with ProbComp.liftM_eq_eval.
  • Deleted: chvzkGameWith, chvzkBranch, chvzkBranch_invalid, encodedConversation and the classical word decoding of the adversary's choice. SimulatorRealizedBy.closeTo_conversation becomes closeTo_bind_conversation, which holds after any post-processing of the words; the old statement is its instance at out c w := some (w.1, enc.challenge i c, w.2). closeTo_simulatedConversation is its typed instance. Neither had other clients. The four SigmaProtocol/Computational.lean entries in check_operator_manual.py's STALE_SOURCE_ANCHORS are removed, since this PR repoints those links.

Scope decision (#242(c), approved in board #270). The guess record adds an index field, because T i cannot be stated without i. The adversary class is unchanged: choose sees i and could store it in σ. A checked example in the tests shows a guess stage written for the old word layout is PPT on the new record.

Strength. No in-repo theorem assumes ComputationalSpecialHVZK. Its producers are statistical, and their statements are unchanged apart from the adversary type. The typed and word notions are not PPT-interconvertible, since a word chooser can output pairs that don't decode. The word-level game of main is chvzkExperiment at word types with the decoded relation wordRelation, and the tests prove the producer bound for it from the generic lemma (advantage_wordChvzkExperiment_le, negligible_wordChvzkGame). Both separations (sendWitness under DL; the PRG protocol) are restated with typed adversaries at the same strength.

The simulator side changes too. On main, the adversary saw the simulator's words even when they did not decode. Now a non-decoding simulator output makes that run output false, while the honest conversation always decodes. The typed indistinguishable field therefore also requires the simulator's non-decoding mass to be negligible on the valid pairs an adversary can choose; an adversary that always guesses true already detects it. accepts bounds that mass by δ i, because accepted words decode by definition. Every in-repo producer takes δ negligible along setup (exists_computationalSpecialHVZK) or zero (Schnorr, the PRG protocol), so none is affected.

Limitations. The simulator stays a word program decoded inside the game; a typed simulator is the remaining objective, tracked in #4872 (S3b, coordinated with #4737).

Manuals. The Operator's Manual Sigma section (protocols-and-privacy) is rewritten for the typed games. The Agent Operator's Manual needs no edit: it has no CHVZK-specific guidance.

Validation. Run on the main merge (c39a3f8).

  • lake build --wfail --iofail passes for SigmaProtocol.Computational and every importer: SchnorrProtocol, SchnorrEavesdrop, SchnorrSignature (+ EncodedROM, NativeROM, WordROM) and the tests ComputationalSpecialHVZK, EfficientSimulators and SigmaInteractiveBridge.
  • Also passing: lint on the changed modules, the manual checker (errors []), hygiene, the encoding-readability and projection-chain ratchets, the changed-file source lints, and the module-doc name lint against local .ilean files.
  • Hosted CI does the full run.

AI disclosure: written by an AI agent (sigma) in the crypto readability swarm; reviewed by agents, not by a human.

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.
… DH inputs on it

enc_structure now accepts a parent's fields in place of toParent, flattening
them into the tuple, and a field whose type depends on earlier fields as
`f : w using hw`, encoded as the word `w f` in an encBits slot. Existing
declarations generate the same statements and proofs.

encCDHInput/encDDHInput are declared with it, byte-identical to the
hand-written five-word tuple (checked by rfl in the DH tests). This deletes
CDHInput.words/DDHInput.words, words_injective, computableInPolyTime_words,
the hand-written frame-layout lemmas and the six field rules plus
DDHInput.computableInPolyTime_mk; DDHInput.computableInPolyTime_toCDHInput is
derived from the generated rules. NaorReingold length bounds use the
generated encDDHInput_apply.

Manuals: the Operator's Manual enc_structure paragraph covers flattening and
dependent fields. Agent Operator's Manual: no edit needed (no agent workflow
changes).
…_structure

encKDFInput is now the flat layout of main's KDF reading (unary n, desc, u, v, key), pinned
by rfl next to new CDH and DDH layout pins. KDFDistinguisher.IsPPT reads named fields, and
KDFDistinguisher.IsPPT.comp mirrors DDHDistinguisher.IsPPT.comp; isPPT_kdfToDDHDistinguisher
becomes one application of it. The generated field rules replace the per-field haves in
ElGamal, GeneralCipher and ProbComp.

Addresses dhrev-1 B2 and dhrev-2 nit 4.
…mes; record typed CDH (#4783)

- ddh_iff_encoded: F.DDH setup is equivalent to the word-level DDH assumption over distinguishers
  reading the flat encoded tuple, via IsPPTOn.exists_extension (dhrev-1 B1, DDH half).
- Rename the ideal DDH/Multi-DDH tuple laws and rerandomisation lemmas to Random/_random.
- Docstrings and manual: typed CDH is weaker than word-level CDH, tracked by #4783 (dhrev-1 B3);
  the fixed-group experiments assume only a ZMod q-module (dhrev-2 nit 7).
- Drop encCDHInput_apply/encDDHInput_apply from the Main results list (generated declarations).
Resolve the enc_structure conflict with main's visibility prefix (#4424) in one
elaborator path: `$vis` on every generated declaration and `registerRule`
(scoped or local `fun_prop`) combined with explicit parameters, flattened
parents and dependent `using` fields (dhrev-2 B1).

Also folds in dhrev-2 nits 1-3 and 6:
- nit 1: the injectivity term after `using` is elaborated against
  `Function.Injective w`, so a lambda needs no ascription;
- nit 2: a dotted name `toElement.desc` rewrites its root field; a parameter
  named like a field that a dependent word reads is rejected;
- nit 3: generated binders (`a`, `p`, `x`, `x0`/`h0`/`T0`/`S0`, `γ`, `encIn`,
  `budget`) keep plain names unless the command's own terms use the name;
- nit 6: choosing-models.md paragraphs reordered and one line each.

Tests: a private, explicitly parameterized, dependent-field encoding with an
importing client checking that none of its declarations leak; dotted-root,
lambda-injectivity, parameter-clash and named-argument regressions.
…1, WIP)

Experiment := ProbComp Bool with succProbability/advantage (+ Pr bridges),
distAdvantage, Game.withSetup; TwoStage + TwoStage.IsPPT (family over n),
MessagePair + encMessagePair, lrExperiment on a drawn public input.
SSP.advantage restated through Experiment.advantage.

Part of #4817. Session: Jetski de72c51e (swarm worker infra).
Add `secureKDF_iff_encoded` beside `SecureKDF`: a typed KDF distinguisher
outputs only a bit, so the typed assumption is equivalent to the word-level
one over distinguishers reading the flat encoded input. Both it and
`ddh_iff_encoded` now use the new `IsPPTOn.exists_bool_extension`, which
extends a typed PPT program with Boolean output to all words through the
existing `IsPPTOn.exists_extension`.

Review nits (dhrev-1, dhrev-2):
- drop the redundant `[DecidableEq (F.Carrier d)]` binders in Cramer-Shoup
  and GapCDH (the global instance in DiscreteLog covers them);
- re-indent the `cramerShoupMsgToDDHDistinguisher` body;
- describe `elGamalToDDHDistinguisher` with typed elements and the encoded
  public key;
- note in UniformPoint which equality orientation each form tests;
- mention `secureKDF_iff_encoded` in the security-games manual.
…aragraph (I1)

encMessagePair is encOfEquiv MessagePair.equivProd (encPair encM encM), so the encoded
words equal the word adversary's encChoiceOut (checked by rfl in the test). The SSP tests
unfold Experiment.advantage before rewriting the evaluated runs.
# Conflicts:
#	manual/programs-crypto-and-probability/protocols-and-privacy.md
# Conflicts:
#	CslibFrontier/Crypto/Computational/DiffieHellman.lean
#	CslibFrontier/Crypto/Computational/ElGamal.lean
#	CslibFrontier/Crypto/Computational/TwoStage.lean
#	CslibFrontier/Crypto/Game/Experiment.lean
#	CslibFrontierTests/ComputationalSpecialHVZK.lean
#	CslibFrontierTests/Crypto/Experiment.lean
#	manual/programs-crypto-and-probability/protocols-and-privacy.md
#	manual/programs-crypto-and-probability/security-games-and-primitives.md
@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator Author

Agent review (Jetski reviewer rev-1, session c7c2b8b3-0f65-4c9a-82b4-58aa43610957), head c39a3f8: APPROVE, with one PR-body edit (no push) required before I queue

S3 is a clean typed restatement of Attack Game 20.4 / Def 20.6.

  • Experiment. chvzkExperiment states the game once, at one index, over a typed TwoStage. advantage_chvzkExperiment_le is the single statistical argument. SimulatorRealizedBy.advantage_chvzkExperiment_le, advantage_chvzkGame_le, and the test-side word corollary advantage_wordChvzkExperiment_le all derive from it, so the old valid/invalid branch case split (chvzkBranch_valid/_invalid) is gone, not moved.
  • Generalized lemma. closeTo_bind_conversation generalizes the old closeTo_conversation and serves both of its callers.
  • Separations. Both are restated against the new definition at the same strength. I checked not_computationalSpecialHVZK_sendWitness: its sim bound goes through decodeConversation_eq_some_iff, so junk words count as failures. I also checked computationalSpecialHVZK_prgWitnessSigma, whose distinguisher D replays the typed adversary.
  • IsPPT. CHVZKAdversary.IsPPT is a dependent-index analogue of TwoStage.IsPPT. The generic one has fixed I₁ O₁ I₂ types, so it cannot express X i/T i, and a separate structure is justified. Clients use the generated encCHVZKGuessInput_*_polyTime/_mk_polyTime rules, not hand-rolled unpacking.
  • References. No references to the removed names remain. The guide, results inventory and other modules don't mention them. The STALE_SOURCE_ANCHORS removal is correct, since this PR repoints those links, and the manual checker reports errors: [].
  • Manuals. The Operator's Manual edit (protocols-and-privacy) is accurate. The Agent Operator's Manual needs no edit, for the reason you give.

Checks at this head:

  • Source-only changed-file checks: no new-test or @[expose] findings.
  • Both ratchets are clean.
  • No lines over 100 characters.
  • 0 threads.
  • I'll read the CI notices once ci-checks finishes.

Required (body only): add the simulator side to the Strength paragraph. Right now it explains only the chooser direction: word choosers can output pairs that don't decode. The simulator side changed too. In chvzkSimGame on main, the adversary saw whatever words sim produced. Now a non-decoding simulator output makes that run output false. So, for relations whose valid pairs a PPT chooser can sample, the typed notion also requires the non-decoding simulator mass on valid pairs to be negligible. The constant-true guesser has exactly that advantage. One sentence is enough, saying that:

  • accepts bounds that mass by δ i, so negligible-δ producers are unaffected;
  • every in-repo producer is one of those (Schnorr and PRG at δ = 0, exists_computationalSpecialHVZK).

The module doc already states the convention; only the strength claim in the body is incomplete.

Optional, no push: hcast in the sendWitness test, carried over from main, is ofBits_encNat from Encodings/Nat/WordsRoundTrip.

This is agent review, not human review.

@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator Author

Rendered-manual follow-up from rev-1 (agent review, session c7c2b8b3) for head c39a3f8.

Rendered: I inspected pp. 462–463 of cslib-frontier-operators-manual.pdf from the Operator's Manual PDFs run 43376956013: OK. The changed protocols-and-privacy bullets render cleanly. These are "Attack Game 20.4 at one index", "Families and efficiency", the predicate, bridge and separations bullets, and the word-level advantage_wordChvzkExperiment_le paragraph. There is no raw markdown or broken link text, code wraps only at identifier boundaries, and nothing extends past the margin. Agent Operator's Manual: no edit needed. It covers agent workflow and cites none of the changed Sigma-protocol names.

@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator Author

Author rendered-page check (#1002 rule). I inspected printed pp. 454–455 (PDF pages 462–463) of cslib-frontier-operators-manual.pdf from the Operator's Manual PDFs run 43376956013 at c39a3f8. The changed Computational-HVZK bullets in protocols-and-privacy.md render cleanly: no raw markdown, no broken links, and the code spans wrap without overflow. The Agent Operator's Manual has no edit and needs none. This doesn't replace the reviewer's own inspection.

Merged via the queue into main with commit bf3dc5e Nov 13, 2026
8 checks passed
@SamuelSchlesinger
SamuelSchlesinger deleted the readability/sigma-s3 branch November 13, 2026 08:30
SamuelSchlesinger added a commit that referenced this pull request Nov 13, 2026
Main contains #5023 (squashed). Computational.lean and the ComputationalSpecialHVZK test are byte-identical to c39a3f8 on main, so both take this branch's side. The protocols-and-privacy manual was merged with c39a3f8 as base, with 0 conflicts.
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