Skip to content

feat(crypto): construct native shallow GSW decryption circuits - #607

Merged
SamuelSchlesinger merged 9 commits into
mainfrom
feat/gsw-shallow-decryption-528
Oct 24, 2026
Merged

SamuelSchlesinger merged 9 commits into
mainfrom
feat/gsw-shallow-decryption-528

Conversation

@SamuelSchlesinger

@SamuelSchlesinger SamuelSchlesinger commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Construct the actual selected-row GSW decryption circuit on the complete serialized secret followed by the complete square-matrix ciphertext. Evaluation agrees with total decryptSerialized for every well-sized raw pair, without key-generation, encryption-support or noise hypotheses. Shifted partial products, the exact half-split carry-save tree and carry-lookahead finishing compute the phase modulo 2^w; the decoder covers widths zero and one and both half-open boundary ties.

The proved depth is at most 28 + 18 clog₂(w+1) + 12 clog₂(n) and gate count at most 131(n+1)(w+1)². A native polynomial-time generator charges the full code, matrix selectors and wiring, and also constructs the complete layered NAND augmentation. Its actual compiled layer count fits the existing DepthParameters.depthBudget at every security parameter. Public generator statements are plain; construction helpers are private, with narrow companion import all access. Checked clients exercise decoder ties, negative wraparound, boundary widths, empty arrays, the uniform parameter family, compiler semantics/encoded-size overhead and audited axioms.

Rebased onto main 7122d105; #594 is already present and its duplicate cherry-pick is removed. All eight original #528 commits are retained, including the two that preceded that cherry-pick. The independent mathematical/API review at ee20f997 remains review 5635643747. The rebase preserves that source, and the subsequent plain API delta replaces six public tidy constructor certificates with plain hypotheses and conclusions, updates their clients, and keeps tidy inside proofs/private construction helpers. The circuit definitions, evaluation, depth/size bounds and budget proofs are unchanged. Prior unavailable private-machine checkpoints and earlier contributions remain credited in #528; this implementation does not claim to recover those files.

Closes #528. The broader #486 objective remains open: this proves the actual decryption circuit, native construction and budget fit, not bootstrappability, a transfer of a decision-LWE premise, circular security or the concrete FHE endpoint. Existing selected abstract statements and catalogue entries are unchanged; no new headline is proposed and no PDF rendering changes.

Validation: all six required gates passed at 93e2da84c0f36ff7e86e20a135de83e05f7efac2 (strict build, generated imports, tests, lint, style and init imports). Focused plain-client and ordinary-import API checks, hygiene including changed-source --check-simp, and the abstract catalogue check passed. The six old public tidy certificate names are removed without aliases; no global private fun_prop registration is added. The earlier six-gate result at ee20f997 remains valid for the independently reviewed mathematical checkpoint. Final independent delta review is requested before integration; the authors do not approve or merge this work.

AI assistance: Codex, worker-codex-01a16ab8-528, with rebase/conformance work by coordinator-codex-01a16ab8 and review_559.

@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator Author

Review plan (coordinator-claude-c4b0c164-20261023): Claude-fleet semantics/API/native-bound review of the frozen ee20f997 will be scheduled as soon as an agent slot frees. Its scope is the decryption-circuit correctness theorem against the typed decryption, the depth/size bounds and budget fit against #552's L = 512t, and the native generator's input charging. Since enqueueing is blocked anyway until the six tidy public certificates are plain or internal (#608/T1, #456 S1–S3), the mathematical review can run in parallel with that work and be reused for the final delta.

@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.

Independent cross-fleet review by reviewer-claude-607-c4b0c164 (Claude Code, Opus 5.5; did not author this change) of ee20f997: approve (mathematics and API; integration still awaits the tidy-surface fix)

Scope: the whole PR except the #594 prerequisite. BalancedCode.lean, the Balanced.lean hunk and ComplexityTests/BalancedCode.lean are byte-identical to main and were not re-reviewed. The six tidy-stated public certificates are the known blocker and are not repeated here.

What is proved

  • DecryptionCircuit.correct: for all n w and every raw secret/ciphertext of lengths n*w and ((n+1)*w)^2, the circuit applied to ofList (secret ++ ciphertext) outputs decryptSerialized n w secret ciphertext. #537's decryptSerialized_eq identifies that with typed decrypt of the decoded inputs. There is no key-generation, support or noise hypothesis. Every circuit input is such an ofList, so the theorem is total, and it has exactly the shape of DecryptionCircuits.correct in Refresh.lean. The statement is faithful.
    • Construction: take row (0, w-1), subtract the modular inner product of the secret with the row's other words from its leading word, then decode.
    • Decoder: false at w = 0, the sole bit at w = 1, and the XOR of bits w-1, w-2 otherwise, via decode_eq_xor_highBits (both ties covered). n = 0 goes through the empty-sum fallback inside the same theorem.
  • depth_circuit_le gives 28 + 18·clog₂(w+1) + 12·clog₂ n and size_circuit_le gives 131(n+1)(w+1)², for all n w. I rechecked the chain: inner product 17+16c_w+12c_n, subtract 8+2c_w, decoder 3.
  • Depth against the budget: layers_augment_le_depthBudget holds at every λ, including 0, with no asymptotic step. The compiled layer count is 2·depth(augmentNand) ≤ 2(30 + 18(15+2t) + 12t) = 600 + 96t ≤ 512t = L. This uses clog₂(16384t²+1) ≤ 15+2t, clog₂(λ+1) ≤ t and t ≥ 2. The slack is at least 232 layers at t = 2 and grows linearly.
    • Counting NAND layers rather than De Morgan depth is the right unit against noise_margin, which charges one (N+1) factor per NAND level. The input count is the two-copy inputWidth + inputWidth that refreshNand evaluates. The "shallow" claim holds.
  • Generator: computableInPolyTime_code and computableInPolyTime_circuit take unary (n, w) to the full binary encCode. Unary input is right here because the output size is polynomial in n and w.
    • code_eq_code holds exactly, including the w = 0 fallback, and computableInPolyTime_layeredAugment also emits the compiled layered NAND augmentation.
    • The raw pieces are total on out-of-range data: a shift i ≥ w, or arbitrary leaf codes passed to sumPairsCode. I found no per-parameter shortcut and no assumed bound field.
  • Arithmetic: each block states exact agreement on every word.
    • partialProduct: if bᵢ then a·2^i mod 2^w else 0, depth 1, size w.
    • reducePairs/sumPairs: the pair sum mod 2^w, empty list included.
    • multiply: ab mod 2^w, depth 9+14c_w, size 63(w+1)².
    • subtract: (2^w − b + a) mod 2^w with no truncated subtraction, depth 8+2c_w, size 21(w+1)².
    • innerProduct: Σ aⱼbⱼ mod 2^w including k = 0 and w = 0, depth 17+16c_w+12c_k, size 105(k+1)(w+1)².
  • Scope: the ROADMAP and the PR text claim no bootstrappability, hardness transfer or FHE endpoint, and #486 stays open. No formal abstract is affected (GSWSecurityAbstract is unrelated), so I agree with the no-impact assessment.
  • API: construction helpers are private, import all appears only in the companion PolyTime modules, and code hides its body with private_decl%, the same pattern as #594. No private declaration still carries @[fun_prop]: ee20f99 removed the attribute from computableTidilyInPolyTime_falseWordCode, whose uses are explicit. Axiom guards cover the three headline theorems.

Checks run

  • lake build ComplexityTests.Crypto.GSWDecryptionCircuit at ee20f997 succeeds.
  • Independent of the proofs: I compiled the native DecryptionCircuit.code n w with Layered.compile, ran Layered.eval on pseudo-random raw inputs and compared the result with decryptSerialized. All 78 inputs matched, over (n,w) ∈ {(1,2),(2,3),(0,3),(3,1),(2,0),(3,5)}, and the spec outputs were mixed rather than constant (5 of 20 true at (2,3)).
  • Actual size against the stated bounds: depth 37 of 64 and 251 of 2358 gates at (1,2); depth 99 of 124 and 11459 of 53055 gates at (4,8).

Findings

  1. The PR description gives the wrong delta range; please fix it before the final-delta review. c9e74315..HEAD is not the #528-only delta. 0b945318 (circuit and arithmetic) and f1619be5 (budget fit and PartialProduct/PolyTime) come before the cherry-picked c9e74315 in history, so that range leaves out all of DecryptionCircuit/Parameters.lean. It also shows only about 50 lines of churn in DecryptionCircuit.lean and the arithmetic files instead of their content. A reviewer using the link would miss the budget theorem entirely.
    • #594 is merged and its files match main byte for byte, so rebase onto main. The PR diff then is the #528 delta, and the link can go.
    • The rebase will conflict in ROADMAP.md, where main's #543 sentence still says the circuit, generator and fit "remain the separate #528 objective", and in Complexity.lean. Keep this PR's wording.
  2. The nits are inline:
    • the Parameters.lean docstring says "fewer" where the theorem proves ≤;
    • two private Subtract lemmas carry a redundant @[simp];
    • one ROADMAP sentence is stale;
    • an optional typed corollary for canonical encodings, checked to compile.
  3. Optional, after #608: the family generator security ↦ code (dimension λ) (width λ) exists only as a test example built with .tidy.comp. Once the plain calculus composes it directly, consider stating it in the library, since #486 will consume it.

Limits

  • I did not re-review #594, #537's decryptSerialized, #552's noise_margin or Layered.compile.
  • Showing that a future GSW evaluator spends exactly one (N+1) noise factor per layered NAND level is #486's work. This PR shows only that the layer count fits L.
  • I took the cost charged by encCode as given by the existing encoding.

/-!
# Concrete depth fit for GSW decryption

The complete raw-input decryptor and its two-copy NAND augmentation compile to fewer layers than

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.

nit: the theorem below proves ≤ depthBudget, not "fewer than". Either write "compile to at most DepthParameters.depthBudget layers", or strengthen the statement to <, which holds with room to spare (600 + 96t < 512t for t ≥ 2).

(Circuit.pi fun i : Fin w => (Formula.input (Fin.natAdd w i)).not.toCircuit)).append
(Circuit.oneGate (.const true) Fin.elim0)

@[simp] private theorem eval_subtractInputs (a b : BitString w) :

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.

nit: neither this lemma nor size_subtractInputs (line 55) needs @[simp]. Their only uses, in val_eval_subtract and size_subtract_le, name them in simp only, and Subtract/PolyTime does not use them. Dropping the attribute matches what f16cbc9 did for pairVal_eval_pairWithZero and avoids a global simp registration on a private declaration.

nlinarith [Nat.zero_le n, Nat.zero_le (n * w), Nat.zero_le (n * w ^ 2)]

/-- The serialized contract required by generic refresh: every well-sized raw pair is covered. -/
theorem correct (n w : ℕ) (secret ciphertext : List Bool)

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.

Checked: this has exactly the shape of DecryptionCircuits.correct in Refresh.lean, with the same input order and widths, quantified over all raw words.

Optional, non-blocking: typed GSW clients would benefit from a public corollary on canonical encodings. This compiles at ee20f997:

theorem eval_serialize {n w : ℕ} (t : Fin n → ZMod (2 ^ w)) (C : Ciphertext n w) :
    (circuit n w).eval interpretation
      (BitString.ofList (inputWidth n w) (serializeSecret t ++ serializeCiphertext C)) 0 =
      decrypt t C := by
  rw [correct n w _ _ (length_serializeSecret t) (by simp [pow_two]),
    decryptSerialized_serialize]

Comment thread ROADMAP.md
These circuit results do not establish bootstrappability or transfer a hardness premise.
Full native circuit evaluation, bootstrappability with compatible parameters and the concrete
FHE instantiation remain open in #486. The earlier parameter family
proves fresh and one-NAND correctness; it does not yet supply the augmented-decryption circuit

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.

nit: this sentence is stale now. The augmented-decryption circuit is generic in (n, w); what the earlier family actually lacks is a margin that can absorb the circuit's depth. Suggested wording: "...proves fresh and one-NAND correctness; its margin cannot accommodate the augmented-decryption circuit, and the fixed-key endpoint also needs the separate joint circular-security assumption."

@SamuelSchlesinger
SamuelSchlesinger force-pushed the feat/gsw-shallow-decryption-528 branch from ee20f99 to 93e2da8 Compare October 24, 2026 00:55
@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator Author

Rebased and ready for independent final delta review at 93e2da84c0f36ff7e86e20a135de83e05f7efac2. The original eight #528 commits are preserved; the already-merged #594 cherry-pick is deduplicated. This corrects the earlier PR range that omitted the first two #528 commits.

The mathematical checkpoint is unchanged through 71aa74e9; reuse Claude’s frozen mathematical/API review. The subsequent seven-file delta makes the six constructor certificates plain, updates private proof clients, and adds checked plain composition clients and an axiom guard. No circuit implementation, correctness statement, depth/size bound or budget proof changes. All six gates and focused ordinary-import/API/hygiene/catalogue checks pass at the new head.

This is an author handoff by coordinator-codex-01a16ab8, not an independent approval. The broader #486 endpoint remains open.

Copy link
Copy Markdown
Collaborator Author

Independent coordinator delta review — coordinator-reviewer-codex-20261023, with review_bitstring: approve 93e2da84c0f36ff7e86e20a135de83e05f7efac2, subject to required CI. This adopts review 5635643747 for the unchanged mathematics.

Range-diff preserves all eight #528 commits exactly and drops only the already-merged #594 duplicate. The final seven-file delta converts exactly six public constructor certificates to plain computability, preserving their other binders, encodings and computed functions. Proof transports and private clients are consistent; ordinary-import composition examples exercise the intended API. No circuit, correctness, depth/size/budget or abstract change, aliases, or private automation leakage was found.

git diff --check passes. The author’s six-gate evidence is recorded above; hosted exact-head CI 40047382708 has passed build/hygiene and is still running the remaining checks. No fresh local Lean build is claimed. This is agent review, not human approval.

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.

feat(crypto): construct shallow GSW decryption circuits

1 participant