Falcon faithfulness & soundness remediation — concrete keygen, verify_sign_correct, verify bridge#471
Falcon faithfulness & soundness remediation — concrete keygen, verify_sign_correct, verify bridge#471alexanderlhicks wants to merge 29 commits into
Conversation
…ed-preimage) Sound GPV hash-and-sign EUF-CMA bounds (euf_cma_split_bound / euf_cma_collision_bound / forgery_yields_collision[_or_exact_match]) reducing forgery to a collision branch + an exact-match programmed-preimage branch (factor qSign+qHash) + birthday salt term, on honestly generated keys. Plus the machine-checked non-vacuity witness Examples/GPVNonVacuity. Claude-Session: https://claude.ai/code/session_01C7GAM6ykxZoXwDXmtdLqrA
…rry/campaign narration Rewrite proof-development narration into intrinsic, accurate docstrings. Remove the false status claims (the file is sorry-free): the `reduction` "open constructor sorry" and the "single isolated sorry of this declaration" lines now describe the proven content (`reduction` is a complete def; the joint coupling is supplied by `reservoir_embed_commute_winner`). Strip round-N / banked / frontier / block-N campaign wording and de-campaign 14 section headers; keep conditional lemmas' hypothesis wording and all mathematical explanation. Comment-only: no statement, signature, or proof changed (build green, headline axioms unchanged by construction). Claude-Session: https://claude.ai/code/session_01C7GAM6ykxZoXwDXmtdLqrA
…Sign Per CONTRIBUTING attribution policy (substantial rewrites), `GPVHashAndSign.lean` grew from a 426-line stub to a ~11.8k-line proof; add the author of that material to the header alongside the original author Quang Dao. Claude-Session: https://claude.ai/code/session_01C7GAM6ykxZoXwDXmtdLqrA
Close Falcon.euf_cma_security / _bytes40 (conditional, axiom-clean): reduce Falcon EUF-CMA to NTRU-SIS + programmed-preimage + birthday + an explicit finite-precision sampler-transport term, on honest keys, via the strengthened GPV bound and the collision bridge collisionFindingAdvantage_eq_ntruPSF. Plus the non-vacuity witness Falcon/NonVacuity. Claude-Session: https://claude.ai/code/session_01C7GAM6ykxZoXwDXmtdLqrA
…n EUF-CMA security `verify_sign_correct` was unprovable as stated: its only handle on the signature was `sig ∈ support (Falcon.sign …)` with `Falcon.sign := sorry`, and any real proof additionally needs PSF correctness (`s₁ + s₂·h = c` on honest keys), which is not a `Primitives.Laws` field and routes through the opaque floating-point inverse-FFT rounding in `fromFFTPreimage`. Remove the theorem along with the `Falcon.sign` and `Falcon.keyGenFromSeed` `:= sorry` placeholders (the latter unused), keeping the sorry-free scheme defs (`signAttempt`, `verify`, the GPV bridge). `Scheme.lean` and `Security.lean` are now sorry-free in what they claim; machine-checked verification correctness is documented as future work (the float boundary). The EUF-CMA security headlines are unaffected and remain axiom-clean [propext, Classical.choice, Quot.sound]: `Falcon.euf_cma_security`, `Falcon.euf_cma_security_bytes40`, `Falcon.collisionFindingAdvantage_eq_ntruPSF`, plus the non-vacuity witness `Examples.FalconNonVacuity.falcon_eufcma_hyps_inhabited`. Claude-Session: https://claude.ai/code/session_01C7GAM6ykxZoXwDXmtdLqrA
The kernel-SIS `ntruSISProblem` required `‖(s₁,s₂)‖₂² ≤ betaSquared`, but a kernel vector obtained from a Falcon-PSF collision is the difference `x - x'` of two β-short preimages, whose squared ℓ₂ norm is at most `(‖x‖₂ + ‖x'‖₂)² ≤ (2β)² = 4·betaSquared`. The old target was too tight by a factor of 4, so a `ntruPSFCollisionProblem → ntruSISProblem` translation could not go through. Correct the bound and document that this translation is not yet formalized (the reduction in `euf_cma_security` terminates at `ntruPSFCollisionProblem`). `ntruSISProblem` is currently scaffolding for that future step and is not referenced by the headline, so no proof changes. Claude-Session: https://claude.ai/code/session_01C7GAM6ykxZoXwDXmtdLqrA
Repair the WriterT-log reconstruction proof for the new definitional appendInputLog (route the sign-body splice through an explicit congrArg step with the simp-normal handler stack), switch to the evalDist_simulateQ_run_congr name, drop the unused simp arguments flagged by CI linters, underscore now-unused coupling-lemma binders, and remove the two unconsumed declarations hashQueryBound and gpv_advantage_le_unforgeableExpNoFresh. Claude-Session: https://claude.ai/code/session_01DaNGD9nDo3Grwk58nsjS77
…ot-level names Claude-Session: https://claude.ai/code/session_01DaNGD9nDo3Grwk58nsjS77
…dules Split the single-file development into twelve modules under VCVio/CryptoFoundations/GPVHashAndSign/, one per proof phase (Basic through Security), each 200-2000 lines, chained by imports along the original order. The original module path remains as an umbrella importing all pieces, so consumers and fully-qualified names are unchanged. Claude-Session: https://claude.ai/code/session_01DaNGD9nDo3Grwk58nsjS77
🤖 PR Summary
Falcon faithfulness & soundness remediation — concrete keygen, verify_sign_correct, verify bridgeThis PR addresses a major gap in the Falcon formalization by building out the concrete correctness layer (sign, keyGenFromSeed, verify_sign_correct) and auditing byte-level faithfulness, complementing the abstract EUF-CMA proof in PR #466. Mathematical Formalization
Protocols / Soundness
Proof Completion (sorries removed)
Open / Work-in-Progress (why this is a draft)
Infrastructure / CI
Documentation
Refactoring
Critical: Sorry count — 14 (9 Falcon + 4 GPV + 1 ToMathlib/RenyiDivergence). These are enumerated explicitly in the PR body and the review doc. The The structure of the change is broad: the core mathematical changes concentrate in Statistics
Lean Declarations ✏️ Removed: 35 declaration(s)
✏️ Added: 471 declaration(s)
…and 321 more not listed. ✏️ Affected: 1 declaration(s) (line number changed)
✅ Removed: 17 `sorry`(s)
Coverage Notes
Partially Analyzed Files
📄 **Per-File Summaries**
The file also contains extensive documentation explaining why the salt-averaged telescope is necessary (the salt draws are invisible at the hash-only oracle granularity) and how the content splits into proof decomposition, salt-collision bounds, and salt-inclusive coupling primitives. There are no
The file contains no
Last updated: 2026-07-10 11:12 UTC. |
|
@alik-eth I'd started doing some work on Falcon after someone asked me about it but it didn't seem necessary in the end (cc https://github.com/kobigurk ?) so I left it unfinished; since you have an active PR looking at this, feel free to re-use anything valuable here (add me as co-author to any PR I guess). |
Build Timing Report
Incremental Rebuild Signal
This compares a clean project build against an incremental rebuild in the same CI job; it is a lightweight variability signal, not a full cross-run benchmark. Slowest Current Clean-Build FilesShowing 20 slowest current targets, with comparison against the selected baseline when available.
|
|
@alexanderlhicks This is exactly the missing half — nice catch on ENC-3, that's a genuine wire bug. Mapped the interaction with #466 precisely: Conflict surface is just two files — Proposed sequencing: #466 lands first (it's deep in review and unblocks the sorry-free GPV chain — 4 of your 14 sorries disappear on rebase), then this rebases on top and your correctness cluster slots back in additively. One suggestion for the rebase: consider landing Synergy after both land: your correctness layer is the natural discharge route for part of #466's hypothesis surface ( |
Agreed. I'll aim to rebase asap as I'll be bus with other priorities later this month and want to ensure my partial work is useful rather than a blocker.
Yep, can do.
I only have the definition, stated as I may have a bit of time to look at it further but if you don't see anything by sometime next week you can assume I've been prioritising other work and feel free to pick it up from there. (edit: started on this) |
…hfulness/soundness remediation Set up self-contained, resumable sessions for the Falcon review/remediation work: - docs/agents/falcon-review.md: canonical bootstrap doc — session protocol (start/end fresh adversarial review + document-refresh check), validated baseline (20 live sorrys; GPV chain sorrys at 270/283/332/363), critical path B1-B8, condensed findings with code refs, spec-of-record matrix. - scripts/falcon_review.mjs: re-runnable, scope-parameterized adversarial review harness (read-only; embeds validated three-baseline source briefs). - AGENTS.md: pointer under Further Reading so a fresh session discovers it. No Falcon code changed. Baseline validated 2026-06-25 against main HEAD a41b514. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Session 1 of the falcon-faithfulness-review remediation (see docs/agents/falcon-review.md). B1 — abstract sampler faithfulness: FalconTree.leaf now carries the bottom 2x2 LDL block (σ₀ σ₁ l01Re l01Im) instead of a single σ, and ffSampling's κ=0 case mirrors the concrete Falcon.Concrete.FFT.ffsampFFTDeepest: sample the t₁ coordinate at σ₁, correct t₀ by l01·(t₁−z₁), then sample the corrected t₀ at σ₀. A single shared σ with no l01 was unfaithful — there is exactly one bottom 2x2 block per κ=0 leaf (256 vs only 128 κ=1 nodes for n=512), so l01 must live at the leaf. Leaf stores true stddevs σ/√d (the samplerZ contract), not the concrete isigma; convention noted in the docstring. B8 — integrity cleanup: Removed the vacuous `hashToPoint_welldefined : … → True` law from Primitives.Laws (referenced nowhere). Added ⚠ CONJECTURAL/UNPROVEN markers above verify_sign_correct and euf_cma_security so the sorry-bodied theorems are not mistaken for established results. Also: harden scripts/falcon_review.mjs to parse stringified `args` (the review harness was ignoring scoped args), and refresh the working doc. No new live sorrys (20 in Falcon/, unchanged); build clean. Both ends of the session ran fresh adversarial reviews; the END review caught and we fixed a stddev/isigma docstring inversion (SIGN-3). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…Sample)=c Session 2 of the falcon-faithfulness-review remediation (B2 prerequisite). The adversarial review found Correct(falconPSF) was false as constructed: fromFFTPreimage returned (c - v₀, -v₁) with v₀, v₁ INDEPENDENTLY rounded, so eval (s₁,s₂) = c - (v₀ + v₁·h) ≢ c, and the PSF's s₁ disagreed with verify's recomputed s₁ = c - s₂·h. Fix: fromFFTPreimage now threads the public key and reconstructs s₁ := c - negacyclicMul s₂ pk.h (dropping the independently-rounded v₀), so the PSF identity s₁ + s₂·h = c holds exactly and matches Falcon.verify and the real Falcon/FN-DSA flow (which store only s₂ and recompute s₁). falconPSF.trapdoorSample threads pk accordingly. Add the proven lemma falconPSF_eval_trapdoorSample: for every x in the support of trapdoorSample, eval pk x = c — the eval-half of PreimageSampleableFunction.Correct, by construction (coefficient-wise: ext + coeff_add/coeff_sub + ring over ZMod). The isShort-half is intentionally NOT claimed: ffSampling can emit over-long vectors (real Falcon retries), so it needs a rejection/retry sampler model — the remaining B2 work. No new live sorrys (20 in Falcon/, unchanged); build clean. Both session ends ran fresh adversarial reviews; the END review re-audited the eval lemma sound and surfaced SD-TS5b (abstract isShort vs concrete rint(v₀) norm-gate diverge under rounding; benign for the verify identity). Working doc refreshed (§4c END synthesis, §5 log). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…plan No code change. Records the session-3 START investigation + locked decisions for B2: - Rejection sampler realized as a fuel-bounded Option-valued loop, mirroring FiatShamir/WithAbort.fsAbortSignLoop (framework prior art that resolves the ProbComp totality caveat — partial-def is opaque, plain fuel breaks ∀-shortness). - sign : pk sk msg → (maxAttempts : ℕ) → ProbComp (Option Signature). - Full implementation plan in §2/B2 (a/b/c), incl. the needed Rq→IntPoly centered helper and the verify_sign_correct restatement. Implementation deferred to a fresh bootstrapped session to keep context clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…— resolves the `sign` sorry
Session 4 of the falcon-faithfulness-review remediation. Resolves the original
enquiry ("hash to sign / sign is a sorry").
Falcon.sign is now defined (Scheme.lean), replacing the sorry:
sign pk sk msg : ℕ → ProbComp (Option Signature)
A fuel-bounded rejection loop mirroring FiatShamir/WithAbort.fsAbortSignLoop and
the concrete Concrete.Sign.concreteSign: each of up to `maxAttempts` attempts samples
a fresh 40-byte salt, hashes c = HashToPoint(salt, pk, msg) via hashToPointForPublicKey
(FN-DSA/Falcon+ pk-binding, fresh salt per retry), runs signAttempt, and on a short
preimage (_, s₂) that also compresses within p.sbytelen returns some ⟨salt, comp⟩;
otherwise retries; none on exhaustion.
Rationale (from the session-4 START review):
- Option/none-on-exhaustion because the some-branch is NOT compress-success-by-
construction (a vector can pass the L2 isShort bound yet have a coefficient too large
to compress), so loop productivity is probabilistic — matches FiatShamirWithAbort.
- compress uses exactly p.sbytelen, matching verify's decompress … p.sbytelen so
compress_decompress chains.
New helper rqToIntPolyCentered (Scheme.lean): the coefficient-wise centered inverse of
IntPoly.toRq (via centeredRepr), to feed compress. The END review confirmed it is the
exact inverse (centeredRepr_intCast), so verify's `IntPoly.toRq s2Int = s₂` chains.
verify_sign_correct restated against `some sig ∈ support (sign … maxAttempts)` — now a
genuine, non-vacuous obligation (body still sorry; does not discard hypotheses).
Live Falcon sorries 20→19 (sign resolved); build clean; no new sorry. Both session ends
ran fresh adversarial reviews (0 refuted). Known follow-ups: keyGenFromSeed, the
verify_sign_correct proof, and the two-world bridge (Falcon.verify vs the GPV verify
euf_cma targets).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…plan validated
No code change. Session-5 START adversarial review validated the verify_sign_correct
discharge plan as SOUND (fuel-loop induction; isShort↔verify-norm identity via the
shared s₁=c−s₂·h; compress_decompress applies at slen=p.sbytelen; hvalid unneeded),
gated on two prerequisites recorded in §4d/§5:
- Gap 2 (F8): IntPoly.toRq ∘ rqToIntPolyCentered = id needs a coeff-wise proof + the
Vector ofFn/toArray index bridge (pattern at Ring/SchoolbookCert.lean:213) +
centeredRepr_intCast (Ring/Norms.lean:112).
- Gap 1 (ENC-1): result stays conditional on the assumed compress_decompress (h_laws),
which is a theorem hypothesis — fine.
New finding ENC-2 (orphan Falcon.Encoding/Laws, unsound — repair/delete). Header-ENC-3
refuted (0x30+logn IS v1.2 0cc1nnnn|cc=01).
Corrected a review-subagent error that had been written into the doc: it misreported the
branch as `main`; the live branch is falcon-faithfulness-review @ 937a36c (verified).
Implementation (toRq_rqToIntPolyCentered → verify_sign_correct induction) deferred to a
fresh bootstrapped session to keep context clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…sessions 0–5) Ran a full 9-dimension adversarial re-audit of all cumulative work @ f405e7c: NO DRIFT (19 live Falcon sorries confirmed by build-warning count); every resolved/ok claim (B8, B1, TS-5, falconPSF_eval_trapdoorSample, sign) re-verified sound at HEAD (could not refute); refuted a stale Trust-boundary stub (false 21-count) and re-confirmed the branch. New/elevated findings: - KG-4/KG-5: ~8 of 11 NTRUSolver sorries are redundant *shadowing* of the already- implemented Concrete/FXR.lean + PolyBigInt.lean (not imported). Deleting the local stubs + importing the real modules is a cheap, no-new-proof sorry reduction that also makes check_ortho_norm executable. - B9/ENC-3 over-length signature malleability re-confirmed as the one genuine wire bug. Rewrote docs/agents/falcon-review.md fresh: 823 → ~150 lines, folding the verbose §4b/§4c/§4d per-session syntheses into terse §5 log lines and refreshing §1–§4 to current truth (19 sorries, sign done, the real open items + the KG quick-win). No Lean code changed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ility) Session 6. Closes the one genuine wire-level defect found by the milestone review: Falcon signatures were malleable — `decompress` only rejected `d.length < dlen`, and `sigDecode` passes all trailing wire bytes, so a signature with appended garbage was accepted (the decode loops only read the first `dlen` bytes). Such a forgery verified identically to the canonical signature. Fix: `decompress` now rejects `d.length ≠ dlen` (Concrete/Encoding.lean), enforcing the fixed-length (NIST/c-fn-dsa) framing at the single chokepoint shared by the abstract and concrete verify paths. `compress` always zero-pads to exactly `dlen`, so legitimate signatures (length = dlen) are unaffected; only the over-length acceptance is removed. The spec's optional unpadded (variable-length) verification remains unsupported, as before (the old `< dlen` already rejected shorter inputs). Repaired the dependent nil-branch of `concrete_verify_eq_verify` (FPRBridge.lean: `hsbytelen` → `hsbytelen.ne`, matching the new `0 ≠ sbytelen` guard) and removed a now-dead `hslen` hypothesis. END review (Encoding+Verify, 0 refuted): confirms the fix closes the malleability with no regression, no second sigDecode fix required, no new sorry (19 Falcon sorries unchanged). Build + Falcon test module green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…4→3 hyps
Prove the two fast-kernel correctness theorems in Concrete/Instance.lean,
relating the UInt32/Int64 executable verifier kernels to their abstract
specification-level counterparts (both standard-axioms-only):
- `negacyclicMulU32_eq_negacyclicMul` (unconditional): the imperative O(n²)
double loop computes `negacyclicMulPure`/`negacyclicConvCoeff`. Proved by an
Array.set!-at-wrap-index loop invariant carrying per-cell `[0, modulus)`
bound + a ZMod partial-convolution sum, then reindexing to the Finset spec.
- `pairL2NormSqU32_eq_pairL2NormSq` (under `hn : 2*n*(modulus/2)^2 < 2^64`):
the UInt64 accumulator equals the centered squared-ℓ₂ spec. The ∀n form is
genuinely false — the accumulator overflows at n≈2.4e11 — so the no-overflow
bound is required; it holds with vast headroom for Falcon n∈{512,1024}.
forIn loops are reduced to List.foldl and discharged with locally re-derived
range-fold helpers (technique cribbed from CompPoly's NTTFast correctness
proofs; not imported — no new dependency).
Rewire FPRBridge.concrete_verify_eq_verify: drop the two semantic kernel
hypotheses `hmul`/`hnorm`, add one decidable numeric hypothesis `hn_ovf`,
discharging the kernels via the new lemmas. Net 4→3 hypotheses (two codec
round-trips + one no-overflow bound); still standard-axioms-only.
START+END adversarial reviews (scripts/falcon_review.mjs): plan validated,
END GREEN with no regression (RHS chains target the genuine spec; axioms
re-verified). Falcon live-sorry count unchanged at 19 (B6 cuts hypotheses,
not sorries). Full LatticeCrypto build green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…or (hpkDecode WIP)
Session 8 checkpoint (codec round-trips for concrete_verify_eq_verify), paused
mid-hpkDecode to keep the working session bounded. All committed work builds
clean with no new sorries.
- Prove `sigDecode_sigEncode` (Concrete/Encoding.lean): the signature framing
round-trip `sigDecode (sigEncode salt compSig logn) logn = some (salt, compSig)`
for `compSig ≠ []`. Standard-axioms-only. Discharges `hsigDecode` of
`FPRBridge.concrete_verify_eq_verify` (left to wire once hpkDecode lands).
- Refactor `pkEncode`/`pkDecode` from `while i+3<n do … i:=i+4` to
`for b in [0:n/4] do let i:=4*b; …`. Lean's `while` lowers to an opaque
`partial Lean.Loop.forIn.loop` with no usable equational theory (even the
0-iteration case is unprovable), so the `while` form cannot be reasoned about;
the `for` form desugars to `List.foldl` (the B6-provable shape). Byte-identical:
iteration count is `⌊n/4⌋` in both for all n, and a pure-Lean `#eval` round-trip
(n=4,8,12 + boundary coeffs) confirms `pkDecode(pkEncode h)=some h`. (FFI
differential vectors run in CI; native backends are absent in this sandbox.)
- Bank the proven hpkDecode scaffolding in docs/agents/falcon-hpkdecode-wip.lean
(inert reference, not a build target; compiles sorry-free against the refactored
codecs): the per-group 56-bit pack/unpack identity `group_roundtrip`, Nat
bit-helpers, and the full `pkEncode` characterization (`pkEncode_eq_E`,
`E_size`, `E_getElem`, `gblock_byte`) — the hard half of hpkDecode. Remaining:
the decode `forIn` invariant + `publicKeyBytes_extract` + wiring (+ a `4 ∣ p.n`
hypothesis, required since `p.n=2^p.logn` admits n∈{1,2}). Resume plan in
docs/agents/falcon-review.md §"VER-1"/s8 log.
START review (Encoding): GREEN — both round-trips true (200k+ random pack/unpack
model, 0 mismatches), ENC-2 false codec confirmed isolated to the orphan module.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…has no semantic hyps) Complete the public-key codec round-trip and discharge it inline in the verify bridge, so the byte-level Falcon verifier provably equals the spec verifier with no semantic assumptions. Encoding.lean (new, standard-axioms-only): - pkDecode_pkEncode (under 4∣n): the decode forIn invariant (decode_loop_invariant) + dead reject-branch (pkEncode_not_reject, since each decoded coeff = h[k].val < modulus); per-group 56-bit pack/unpack crux group_roundtrip + the pkEncode characterization (E_*, gblock_*, pkEncode_eq_E) lifted from the s8 WIP scaffold. - publicKeyBytes_extract (unconditional), pkEncode_size. FPRBridge.lean: - concrete_verify_eq_verify drops the hsigDecode/hpkDecode hypotheses and discharges both round-trips inline; adds hn4 : 4 ∣ p.n. Remaining hyps are purely structural/numeric (hn, hsbytelen, hn_ovf, hn4). Verified: #print axioms = [propext, Classical.choice, Quot.sound] on all three theorems; full LatticeCrypto build green; sorry count unchanged at 24 (VER-1 discharges hypotheses, not sorries). Cleaned 20 show→change lint warnings (no linter disabled). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…red = id) Discharge the abstract Falcon correctness theorem: a non-aborting signature always verifies. Standard-axioms-only; sorry count 24→23. Scheme.lean: - toRq_rqToIntPolyCentered (F8): IntPoly.toRq (rqToIntPolyCentered f) = f, coeff-wise via Poly.ext_get_eq + mapCoeffs/vectorBackend reduction + centeredRepr_intCast.symm. Security.lean: - verify_sign_correct: induction on maxAttempts (vacuous base; success-vs-retry decomposition via mem_support_bind_iff) chaining h_laws.compress_decompress → F8 → falconPSF_eval_trapdoorSample (s₁ = c - s₂·h) → the isShort ℓ₂ check. Conditional only on the abstract compress_decompress law (not the concrete codec). The key-validity hypothesis is unnecessary (renamed _hvalid). Verified: #print axioms = [propext, Classical.choice, Quot.sound] on both; signature unchanged (non-vacuous — success branch does real work); full LatticeCrypto build green. The two-world gap (TS-4: byte-level Falcon.verify vs the GPV verify the EUF-CMA theorems use) remains open. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…b→real reconciliation) Checkpoint, no code. Selected KG-quickwin as the next task and banked a fully-scoped, executable resume plan in §3: replace NTRUSolver's 9 stub sorries with the real Concrete/FXR.lean + PolyBigInt.lean (target 23→14 sorries; makes solve_NTRU/check_ortho_norm executable). Scoped against live code, correcting earlier doc claims: - fxr_sqr DOES exist (FXR.lean:87); real fns are fxr_-prefixed. - poly_big_to_small is 3-arg returning Array Int8 × Bool (offset → Array.extract). - vect_set wants Array Int32 (f.map (·.toInt32)). - all local-FXR uses confined to check_ortho_norm; poly_big_to_small only in solve_NTRU; no import cycle. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…orry 23→14) Replace NTRUSolver's 9 local stub-`sorry` definitions (`FXR.sqr`, the seven `vect_*`, and `poly_big_to_small`) with the real, fully-implemented routines in `Concrete/FXR.lean` and `Concrete/PolyBigInt.lean` (ports of c-fn-dsa `kgen_fxp.c` / `kgen_poly.c`). Import both, `open Falcon.Concrete.FXR` + `open Falcon.Concrete.PolyBigInt (poly_big_to_small)`, and delete the local `namespace FXR` and stub defs. Reconcile the two call sites against the real signatures: - `solve_NTRU` tail: real `poly_big_to_small (logn)(s)(lim) : Array Int8 × Bool` reads `s[0:n]`, so the dropped `off` becomes `buf.extract 0 n` / `buf.extract n (2*n)`; the pair return short-circuits via `if !ok then none`, semantically equal to the old `Option` bind. - `check_ortho_norm`: `fxr_*` names; `vect_set` wants `Array Int32`, so map `(·.toInt32)` over the `Array Int8` inputs (sign-extending); `vect_invnorm_fft` takes a `UInt64` last arg. NTRUSolver 11→2 sorries (only the KG-2/KG-3 ascent sorries remain); total 23→14. `check_ortho_norm` is now sorry-free (`#print axioms` = propext, Quot.sound) and `#eval`-executable — KG-6 vacuity closed. `solve_NTRU` still carries `sorryAx` solely from the two untouched ascent stubs. Standard-axioms preserved (no `native_decide`); full `LatticeCrypto` build green. END adversarial review found 0 regressions across all three reconciliations. This is plumbing, not a keygen correctness proof (`solve_NTRU ⊨ ntruEquation` and `keyGenFromSeed` remain open, B4). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion fixes
Ran the adversarial-review harness scoped to KeyGen+NTRUSolve + Trust-boundary
(baseline 14, changed=s12). Verdict: NO drift (14 sorries confirmed exactly),
no regression, no spec-divergence, no unsound statement — the s12 KG-quickwin
plumbing is faithful by two independent audits (9 stubs gone/not shadowed;
`check_ortho_norm` axioms re-confirmed {propext, Quot.sound} two-source; no
native_decide or new axiom in the FXR/PolyBigInt closure; the 2 remaining
NTRUSolver sorries are exactly the ascent stubs).
Acted on the findings (docs/comments only — no proof code):
- Corrected the doc's wrong "`fxr_of` unexercised-negative" justification
(KG-5/N-1): `fxr_of` IS exercised on the routinely-negative NTRU secrets
f,g via `vect_set ∘ (·.toInt32)`, and is correct there (sign-extends through
`toInt64`, matching C `(int64_t)j << 32`); bit-identical to the deleted stub
only for the positive constant 12289.
- Fixed the stale `fndsa_native.c` SCU citation → `fndsa.c` in
`FFI.lean:22` and `csrc/falcon/gen_testvectors.c` (N-2); the real
amalgamation per lakefile is `csrc/falcon/fndsa.c`.
- Recorded TB-5 (verify bridge `concrete_verify_eq_verify` is sound but LATENT
— referenced only in a docstring) and re-confirmed TB-3 (the 5 FPR
error-bound sorries feed only the disabled HasRealSemantics, not the live
integer verifier).
- Flagged the uninitialized `third_party/c-fn-dsa` submodule as a hard
prerequisite for the next keygen-faithfulness pass (and for the FFI/test
build).
Refreshed the harness (scripts/falcon_review.mjs): default baseline 20→14,
updated the DRIFT breakdown and the KeyGen+NTRUSolve / Theorem-soundness
dimension foci so future bookends aren't seeded with stale line numbers
(verify_sign_correct is now PROVEN, not a sorry to re-flag).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…mediate port plan Records the §3 "B4 ascent resume plan": a step-by-step, signature-validated port plan for the two remaining NTRUSolver sorries (solve_NTRU_depth0, solve_NTRU_intermediate), mapped against kgen_ntru.c @ 33026d4d (submodule now initialized) and every cited Lean helper re-checked against live source. Key finding: solve_NTRU_depth0 has ZERO helper gaps (~90-120 LOC, all existing SmallPrimeNTT/FXR/BigInt31 primitives) and is a sane single-session target — do it first. solve_NTRU_intermediate is larger (~200-280 LOC) and needs one new helper (poly_sub_kfg_scaled_depth1, depth==1 branch only) — a separate effort. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…everted to sorry Wrote a full line-by-line port of c-fn-dsa solve_NTRU_depth0 (kgen_ntru.c:1575-1766) using the validated §3 B4 plan. It compiles, but FAILS end-to-end validation at logn=1: over all 7^4 small (f,g), the pipeline deepest → depth0 → poly_big_to_small yields solved=0 — the lift leaves (F,G) un-reduced (raw coeffs far outside ±127) and/or depth0's internal f·G−g·F≡q gate rejects. Safe (the gate means no wrong key escapes) but non-functional. The C driver (kgen_ntru.c:2003) confirms deepest feeds depth0 directly for logn=1 (the intermediate loop is empty), so the test path is faithful and the bug is real. Prime suspect: solve_NTRU_deepest's deeper-(F,G) output convention — it was never runtime-validated before now (the whole pipeline was sorry); it succeeds 476/2401× but its degree-1 output (Fd=4·q, Gd=0 for [1,2]/[0,1]) satisfies no naive scalar relation, and a 31-bit-limb (sign bit 30) vs poly_mp_set's .toInt32 (sign bit 31) mismatch for negatives is plausible. Honest state: reverted solve_NTRU_depth0 to `sorry` (a non-functional executable that drops the sorry count would misrepresent progress). The full implementation + diagnostics are preserved in docs/agents/falcon-ntru-depth0-wip.lean for the next session. NTRUSolver back to 2 sorries; total 14. Submodule third_party/c-fn-dsa initialized (33026d4d). Next: build the C backend and differential-trace solve_NTRU_deepest AND solve_NTRU_depth0 word-for-word on one fixed (f,g) at logn=2 to localise the divergence, then fix depth0 from the WIP file. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… GPV/#466 Rebased onto #466 (pr/falcon); adds the complementary correctness + hardness-bridge layer on top of the now-proven GPV EUF-CMA chain. D — move `verify_sign_correct` into `LatticeCrypto/Falcon/Correctness.lean`, keeping `Security.lean` security-only (per review suggestion); adapt `NonVacuity` to the `FalconTree.leaf` arity. B — `ntruPSFCollisionProblem → ntruKeyedSISProblem` kernel-vector bridge: - `ntruSISProblemWithSample` (parameterized by challenge sampler + norm bound); `ntruKeyedSISProblem hr bound` (key-distributed `h`); `ntruSISProblem` = idealized uniform-`h` / `betaSquared`. - `collisionToNTRUSISSolution` + `ntruPSFCollisionToKeyedSISAdversary` (the reduction). - `ntruPSFCollision_to_keyedSIS_valid`: a valid collision differences to a valid keyed-SIS solution at bound `4·betaSquared` (kernel via `negacyclicMul_sub_left`; norm via new centered-residue triangle lemmas). - `ntruPSFCollision_advantage_le_keyedSIS`: the keyed adversary wins with ≥ the collision advantage (two nested `probOutput_bind_mono`, `⟨pk.h⟩ = pk` eta). - `euf_cma_security_ntruSIS`: EUF-CMA bound terminating at `ntruKeyedSISProblem (4·betaSquared)`, composing `euf_cma_security` with the advantage bridge. `Ring/Norms.lean`: `centeredRepr_sub_natAbs_le` (valMinAbs triangle, no wraparound hypothesis) + `l2NormSq_sub_le_two_mul_add` / `pairL2NormSq_sub_le_two_mul_add`. All new declarations standard-axioms-only (`propext, Classical.choice, Quot.sound`); no new `sorry` (Falcon count stays 7 = FPRBridge ×5 + NTRUSolver ascent ×2). #466's proven headline theorems are untouched. Full `LatticeCrypto` build green. Co-Authored-By: Oleksandr (Alik.eth) Vovkotrub <8048195+alik-eth@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4e07ffa to
0538916
Compare
|
Rebased this onto #466. This adds
The sorry count is 8 (down from 14): FPRBridge ×5 (FPR error bounds behind the disabled HasRealSemantics), NTRUSolver ×2 (the NTRU-solver ascent), and the ToMathlib Rényi sorry — your GPV chain resolved the other six. Credited you as co-author on the bridge commit since it builds directly on your euf_cma_security / ntruPSFCollisionProblem. Review is encouraged as always of course, but I think this is a good handover point otherwise. |
|
Coordination note on the Your The blocker there is that Blast radius is a drop-in swap of the Written by aryaethn's Claude Code Agent (Approved by aryaethn) |
|
@alexanderlhicks Heads-up for your planned rebase: #466's Falcon surface moved substantially this round, all additive to
|
Draft — opened for visibility/coordination, not for merge yet. cc @alik-eth (#466). This is the complementary half of the Falcon work: where #466 proves EUF-CMA via the abstract GPV → NTRU-collision route and deletes the sorry-backed correctness cluster (
sign/keyGenFromSeed/verify_sign_correct), this branch builds out and proves that concrete correctness layer and audits byte-level faithfulness. The two are largely orthogonal and should inform each other — flagging early so we don't diverge or duplicate.Canonical working doc:
docs/agents/falcon-review.md(session log + findings). Paired re-runnable adversarial-review harness:scripts/falcon_review.mjs.Scope & baselines
Three baselines judged separately (no single authoritative spec): Falcon v1.2, FN-DSA / FIPS 206, Falcon+ / c-fn-dsa. The repo targets c-fn-dsa / FN-DSA (FFI uses
FNDSA_HASH_ID_RAW); divergences from v1.2 (pk-bound hash, fresh salt per retry, L2-only) are intended and documented (matrix M1–M9 in the doc).Proven (standard-axioms-only:
propext, Classical.choice, Quot.sound)verify_sign_correct(Security.lean) — a non-aborting signature always verifies, conditional only on the abstracth_laws.compress_decompresslaw (not the concrete codec).toRq_rqToIntPolyCentered = id(F8,Scheme.lean).concrete_verify_eq_verify(Concrete/FPRBridge.lean) — the byte-level verifier provably equals the spec verifier with no semantic hypotheses (B6 U32-kernel equalities + both codec round-tripssigDecode/pkDecodedischarged inline; remaining side-conditions are purely structural/numeric).signimplemented as a fuel-boundedOptionrejection loop (Scheme.lean).decompressrejects non-canonical-length signatures (over-length malleability), the one genuine wire bug found.NTRUSolvernow uses the realConcrete/FXR.lean+PolyBigInt.lean(deleted 9 stubsorrys);check_ortho_normis sorry-free and executable.Open (WIP — why this is a draft)
keyGenFromSeed(Scheme.lean) —sorry.solve_NTRU_intermediate/solve_NTRU_depth0—sorry. A full port of c-fn-dsasolve_NTRU_depth0was written but fails end-to-end validation (reverted tosorry; implementation + diagnostics preserved indocs/agents/falcon-ntru-depth0-wip.lean). Prime suspect:solve_NTRU_deepest's deeper-(F,G)convention, never runtime-validated. Next step: differential-trace against the c-fn-dsa backend.euf_cma_security+ the generic GPV chain (VCVio/CryptoFoundations/GPVHashAndSign.lean×4) — this is exactly what feat(Falcon): idealized-model EUF-CMA via GPV, down to NTRU-SIS (#188) #466 addresses; coordination point.Sorry count: 14 (9 Falcon + 4 GPV + 1 ToMathlib/RenyiDivergence). Full
LatticeCryptobuild green at v4.30.0.#print axiomsconfirmed standard-only on every proven result above.🤖 Generated with Claude Code