From f3d5eeaf2fe002b1c7457c6d124ce89e1b8be58f Mon Sep 17 00:00:00 2001 From: Asher Yan Date: Tue, 28 Jul 2026 09:17:14 -0400 Subject: [PATCH] Release v0.5.0 --- .agents/PLAN.md | 48 +- .agents/SPEC.md | 31 +- .agents/audit/dependency-dag.md | 256 +- .agents/audit/fidelity.md | 98 +- .agents/inventory/carlet-chapter02.yaml | 59 +- .agents/inventory/carlet-chapter05.yaml | 10 +- .agents/inventory/carlet-chapter06.yaml | 2495 ++++++++++++++++ AGENTS.md | 23 +- CryptBoolean.lean | 1 + CryptBoolean/BooleanFunction.lean | 11 + CryptBoolean/Carlet/Chapter02.lean | 3 + .../Carlet/Chapter02/Foundations.lean | 11 + CryptBoolean/Carlet/Chapter02/FourierNNF.lean | 139 + .../Carlet/Chapter02/FourierOperations.lean | 9 + .../Chapter02/RestrictionSquareIdentity.lean | 136 + .../Carlet/Chapter02/WalshDivisibility.lean | 104 + .../Chapter04/ReedMullerCosetDistance.lean | 89 + CryptBoolean/Carlet/Chapter05.lean | 2 +- .../QuadraticTraceRepresentation.lean | 54 +- CryptBoolean/Carlet/Chapter06.lean | 59 + CryptBoolean/Carlet/Chapter06/Bentness.lean | 195 ++ .../Carlet/Chapter06/CompleteQuadratic.lean | 337 +++ .../Carlet/Chapter06/DegreeBounds.lean | 46 + .../Carlet/Chapter06/DegreeRelation.lean | 388 +++ CryptBoolean/Carlet/Chapter06/DirectSum.lean | 87 + CryptBoolean/Carlet/Chapter06/Dual.lean | 137 + CryptBoolean/Carlet/Chapter06/DualAffine.lean | 159 + .../DualCoefficientDivisibility.lean | 428 +++ .../Carlet/Chapter06/DualIsometry.lean | 120 + CryptBoolean/Carlet/Chapter06/DualNNF.lean | 94 + .../Carlet/Chapter06/DualPoisson.lean | 99 + .../Carlet/Chapter06/FlatSwitching.lean | 891 ++++++ .../Carlet/Chapter06/FourierUncertainty.lean | 610 ++++ .../Chapter06/GeometricCharacterization.lean | 1327 +++++++++ CryptBoolean/Carlet/Chapter06/HyperBent.lean | 413 +++ .../Chapter06/HyperBentPartialSpread.lean | 589 ++++ .../Chapter06/HyperplaneRestriction.lean | 372 +++ .../Carlet/Chapter06/IndirectSum.lean | 212 ++ CryptBoolean/Carlet/Chapter06/Kerdock.lean | 215 ++ .../Chapter06/KerdockCoordinateIdentity.lean | 267 ++ .../Chapter06/KerdockFieldConstruction.lean | 716 +++++ .../Carlet/Chapter06/MaioranaMcFarland.lean | 128 + .../Chapter06/MaioranaMcFarlandCounting.lean | 173 ++ .../Chapter06/MaioranaMcFarlandGeneral.lean | 309 ++ CryptBoolean/Carlet/Chapter06/McElieceAx.lean | 218 ++ .../Carlet/Chapter06/NNFCharacterization.lean | 430 +++ CryptBoolean/Carlet/Chapter06/NestedBent.lean | 196 ++ .../Carlet/Chapter06/NormalExtension.lean | 2556 +++++++++++++++++ .../Carlet/Chapter06/PartialBent.lean | 38 + .../Chapter06/PartialBentCounterexamples.lean | 238 ++ .../Carlet/Chapter06/PartialBentDual.lean | 648 +++++ .../Carlet/Chapter06/PartialSpreads.lean | 199 ++ .../Carlet/Chapter06/PartiallyBent.lean | 838 ++++++ .../Carlet/Chapter06/PermutationReindex.lean | 127 + CryptBoolean/Carlet/Chapter06/Plateaued.lean | 228 ++ .../Carlet/Chapter06/PlateauedOrphan.lean | 311 ++ .../Chapter06/PlateauedSecondOrder.lean | 131 + .../Carlet/Chapter06/PlateauedSupport.lean | 232 ++ .../Carlet/Chapter06/QuadraticBent.lean | 80 + CryptBoolean/Carlet/Chapter06/Rothaus.lean | 235 ++ .../SecondOrderCharacterization.lean | 252 ++ .../Carlet/Chapter06/SupportCode.lean | 495 ++++ .../Carlet/Chapter06/ThreeFunctionBent.lean | 184 ++ .../Chapter06/ThreeFunctionIdentity.lean | 152 + .../Carlet/Chapter06/WalshCongruence.lean | 133 + README.md | 23 +- .../CryptBooleanBlueprint/Blueprint.lean | 17 +- .../Carlet/Chapter02/Derivatives.lean | 12 +- .../Carlet/Chapter02/NumericalNormalForm.lean | 14 +- .../Carlet/Chapter02/SpectralSupport.lean | 9 + .../Carlet/Chapter02/WalshTransform.lean | 2 +- .../Carlet/Chapter05/Classes.lean | 2 +- .../Carlet/Chapter06.lean | 63 + .../Carlet/Chapter06/AlgebraicDegree.lean | 54 + .../Carlet/Chapter06/Bentness.lean | 64 + .../Carlet/Chapter06/Constructions.lean | 60 + .../Carlet/Chapter06/Counting.lean | 33 + .../Chapter06/DecompositionsCounting.lean | 37 + .../Carlet/Chapter06/Duality.lean | 114 + .../Chapter06/GeometricCharacterization.lean | 53 + .../Carlet/Chapter06/HyperBent.lean | 48 + .../Carlet/Chapter06/Kerdock.lean | 76 + .../Carlet/Chapter06/LowDegree.lean | 36 + .../Carlet/Chapter06/NNFCharacterization.lean | 33 + .../Carlet/Chapter06/Normality.lean | 105 + .../SecondOrderCharacterization.lean | 31 + .../Chapter06/SecondaryConstructions.lean | 115 + .../Carlet/Chapter06/Superclasses.lean | 162 ++ .../scripts/check_statement_style.py | 4 +- blueprint-verso/scripts/validate_manifest.py | 14 +- lakefile.lean | 2 +- 91 files changed, 20959 insertions(+), 95 deletions(-) create mode 100644 .agents/inventory/carlet-chapter06.yaml create mode 100644 CryptBoolean/Carlet/Chapter02/FourierNNF.lean create mode 100644 CryptBoolean/Carlet/Chapter02/RestrictionSquareIdentity.lean create mode 100644 CryptBoolean/Carlet/Chapter02/WalshDivisibility.lean create mode 100644 CryptBoolean/Carlet/Chapter06.lean create mode 100644 CryptBoolean/Carlet/Chapter06/Bentness.lean create mode 100644 CryptBoolean/Carlet/Chapter06/CompleteQuadratic.lean create mode 100644 CryptBoolean/Carlet/Chapter06/DegreeBounds.lean create mode 100644 CryptBoolean/Carlet/Chapter06/DegreeRelation.lean create mode 100644 CryptBoolean/Carlet/Chapter06/DirectSum.lean create mode 100644 CryptBoolean/Carlet/Chapter06/Dual.lean create mode 100644 CryptBoolean/Carlet/Chapter06/DualAffine.lean create mode 100644 CryptBoolean/Carlet/Chapter06/DualCoefficientDivisibility.lean create mode 100644 CryptBoolean/Carlet/Chapter06/DualIsometry.lean create mode 100644 CryptBoolean/Carlet/Chapter06/DualNNF.lean create mode 100644 CryptBoolean/Carlet/Chapter06/DualPoisson.lean create mode 100644 CryptBoolean/Carlet/Chapter06/FlatSwitching.lean create mode 100644 CryptBoolean/Carlet/Chapter06/FourierUncertainty.lean create mode 100644 CryptBoolean/Carlet/Chapter06/GeometricCharacterization.lean create mode 100644 CryptBoolean/Carlet/Chapter06/HyperBent.lean create mode 100644 CryptBoolean/Carlet/Chapter06/HyperBentPartialSpread.lean create mode 100644 CryptBoolean/Carlet/Chapter06/HyperplaneRestriction.lean create mode 100644 CryptBoolean/Carlet/Chapter06/IndirectSum.lean create mode 100644 CryptBoolean/Carlet/Chapter06/Kerdock.lean create mode 100644 CryptBoolean/Carlet/Chapter06/KerdockCoordinateIdentity.lean create mode 100644 CryptBoolean/Carlet/Chapter06/KerdockFieldConstruction.lean create mode 100644 CryptBoolean/Carlet/Chapter06/MaioranaMcFarland.lean create mode 100644 CryptBoolean/Carlet/Chapter06/MaioranaMcFarlandCounting.lean create mode 100644 CryptBoolean/Carlet/Chapter06/MaioranaMcFarlandGeneral.lean create mode 100644 CryptBoolean/Carlet/Chapter06/McElieceAx.lean create mode 100644 CryptBoolean/Carlet/Chapter06/NNFCharacterization.lean create mode 100644 CryptBoolean/Carlet/Chapter06/NestedBent.lean create mode 100644 CryptBoolean/Carlet/Chapter06/NormalExtension.lean create mode 100644 CryptBoolean/Carlet/Chapter06/PartialBent.lean create mode 100644 CryptBoolean/Carlet/Chapter06/PartialBentCounterexamples.lean create mode 100644 CryptBoolean/Carlet/Chapter06/PartialBentDual.lean create mode 100644 CryptBoolean/Carlet/Chapter06/PartialSpreads.lean create mode 100644 CryptBoolean/Carlet/Chapter06/PartiallyBent.lean create mode 100644 CryptBoolean/Carlet/Chapter06/PermutationReindex.lean create mode 100644 CryptBoolean/Carlet/Chapter06/Plateaued.lean create mode 100644 CryptBoolean/Carlet/Chapter06/PlateauedOrphan.lean create mode 100644 CryptBoolean/Carlet/Chapter06/PlateauedSecondOrder.lean create mode 100644 CryptBoolean/Carlet/Chapter06/PlateauedSupport.lean create mode 100644 CryptBoolean/Carlet/Chapter06/QuadraticBent.lean create mode 100644 CryptBoolean/Carlet/Chapter06/Rothaus.lean create mode 100644 CryptBoolean/Carlet/Chapter06/SecondOrderCharacterization.lean create mode 100644 CryptBoolean/Carlet/Chapter06/SupportCode.lean create mode 100644 CryptBoolean/Carlet/Chapter06/ThreeFunctionBent.lean create mode 100644 CryptBoolean/Carlet/Chapter06/ThreeFunctionIdentity.lean create mode 100644 CryptBoolean/Carlet/Chapter06/WalshCongruence.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/AlgebraicDegree.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Bentness.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Constructions.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Counting.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/DecompositionsCounting.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Duality.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/GeometricCharacterization.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/HyperBent.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Kerdock.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/LowDegree.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/NNFCharacterization.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Normality.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/SecondOrderCharacterization.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/SecondaryConstructions.lean create mode 100644 blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Superclasses.lean diff --git a/.agents/PLAN.md b/.agents/PLAN.md index 550abcd..a1f2607 100644 --- a/.agents/PLAN.md +++ b/.agents/PLAN.md @@ -8,13 +8,14 @@ Plancherel, relative Hamming distance, balancedness, restrictions, ANF, algebrai functions, and derivatives needed by CryptBoolean. FABL is the canonical owner of those shared APIs; this project imports them directly and adds only source-facing or cross-representation laws. -The current Blueprint baseline contains 149 source-facing statement nodes: 146 formalized nodes -associated with 961 proved Lean declarations and 3 visibly open nodes, connected by 296 reviewed -dependency edges. Chapter 2 contributes 38 formalized nodes, 166 declarations, and 48 incoming +The current Blueprint baseline contains 209 source-facing statement nodes: 206 formalized nodes +associated with 1338 proved Lean declarations and 3 visibly open nodes, connected by 467 reviewed +dependency edges. Chapter 2 contributes 41 formalized nodes, 174 declarations, and 56 incoming edges. Chapter 3 contributes 7 formalized nodes, 32 declarations, and 19 incoming edges. Chapter 4 contributes 73 formalized nodes, 568 declarations, and 159 incoming edges. Chapter -5 contributes 31 nodes (28 formalized and 3 open), 195 declarations, and 70 incoming edges. These -counts are a synchronized verification contract shared by the inventories, +5 contributes 31 nodes (28 formalized and 3 open), 203 declarations, and 70 incoming edges. Chapter +6 contributes 57 formalized nodes, 361 declarations, and 163 incoming edges. These counts are a +synchronized verification contract shared by the inventories, Verso sources, `blueprint-verso/scripts/validate_manifest.py`, and `AGENTS.md`. Automated PDF text extraction finds 93 numbered definition/theorem/proposition/lemma/corollary @@ -76,9 +77,10 @@ tooling pipeline runs, and no local filesystem path appears in package metadata. ## Phase 1 - Complete Carlet inventory -Status: in progress. Reviewed Chapter 2 and Chapter 3 items live under `.agents/inventory/`. -Chapter 4's 73-item inventory and Chapter 5's 31 mathematical statements are -source-reviewed and Blueprint-synchronized; Chapters 6--10 are not yet inventoried. +Status: in progress. Chapters 2--6 are source-reviewed and Blueprint-synchronized under +`.agents/inventory/`. Chapter 6 has 57 promoted mathematical statements and 19 additional +source-recovery records covering cited or underspecified families that are not yet promoted to +Blueprint nodes. Chapters 7--10 are not yet inventoried. Read Chapters 2--10 in full and create one Blueprint node per in-scope item. Record full statements, source locations, representation decisions, and mathematical dependencies. Mark referenced results @@ -103,11 +105,13 @@ render, and no proof work has silently expanded or reduced scope. ## Phase 2 - Chapter 2 foundations -Status: complete. All 38 source-facing nodes are formalized by 166 proved declarations with 48 +Status: complete. All 41 source-facing nodes are formalized by 174 proved declarations with 56 reviewed dependency edges. This phase includes Proposition 5's numerical-normal-form integrality criterion, full raw Poisson summation, affine invariance, restriction recovery, both spectral-support bounds, the coordinate/univariate binary-degree formula, Carlet Proposition 3 on -trace-monomial degree, and trace-pairing coordinates. +trace-monomial degree, trace-pairing coordinates, Relation (30)'s NNF Fourier formula, +Proposition 9's restriction-square identities, and Proposition 11's Walsh-divisibility degree +bound. Proposition 3 is closed by composing the exact binary-exponent-weight/coordinate-ANF-degree formula with noncancellation along the trace monomial's cyclotomic orbit. @@ -190,7 +194,7 @@ from reference [357]'s complementary convention. ## Phase 5 - Chapter 5 tractable classes Status: complete at the reviewed algebraic and combinatorial boundary. Twenty-eight of 31 reviewed -nodes are formalized by 195 proved declarations. +nodes are formalized by 203 proved declarations. The compiled surface includes affine spectra, quadratic polar and weight theory, the complete quadratic affine normal form, exact quadratic weight and nonlinearity value sets, even quadratic rank, quadraticization and its iterated degree-three Walsh lift, flat-indicator spectra, @@ -209,8 +213,22 @@ bent/resilient construction phases. ## Phase 6 - Chapter 6 bent functions -Order proof work by prerequisites; retain the source topic order in the public Blueprint's flat -section structure: +Status: complete. All 57 reviewed nodes are formalized by 361 proved declarations with 163 +reviewed dependency edges. The completed surface includes bentness and its dual, the Rothaus bound +and Relation (47), the reusable McEliece--Ax character-sum divisibility theorem, primary and +secondary constructions, decompositions and counting, NNF, geometric and second-order +characterizations, the hyper-bent partial-spread family, partially bent and plateaued +superclasses, normal extensions, and the explicit finite-field Kerdock construction and code +parameters. + +The implementation composes FABL's canonical Fourier, ANF, degree, affine, and derivative APIs +with the Chapter 2 raw Walsh and trace layers, Chapter 3 Reed--Muller theory, Chapter 4 +nonlinearity and propagation results, and Chapter 5 quadratic, restriction, trace, and normality +theorems. Printed edge cases and false consequences remain visible through explicit hypotheses, +corrected formulas, or formal counterexamples. + +The proof order followed mathematical prerequisites while the public Blueprint retains the source +topic order in its flat section structure: - spectral and derivative characterizations of bentness; - dual bent function and normalization laws; @@ -221,8 +239,8 @@ section structure: - hyper-bent, partially bent, partial bent, and plateaued functions; - normality questions and Kerdock-code results. -Finite-field constructions wait for Phase 2D. Kerdock results wait for the minimal Chapter 3 code -API. Spectral characterizations do not wait for either. +The finite-field constructions consume the completed Phase 2D trace layer, and the Kerdock results +consume the minimal Chapter 3 Reed--Muller API without introducing a general coding hierarchy. ## Phase 7 - Chapter 7 resilient functions diff --git a/.agents/SPEC.md b/.agents/SPEC.md index 5487d4d..9219683 100644 --- a/.agents/SPEC.md +++ b/.agents/SPEC.md @@ -32,18 +32,20 @@ PDFs, manifests, graphs, and caches are not sources of truth. ## Current verified baseline -The reviewed Blueprint contains 149 source-facing statements, of which 146 are associated with 961 -proved Lean declarations and 3 remain visibly open, connected by 296 mathematical dependency -edges. Chapter 2 contributes 38 formalized statements, 166 declarations, and 48 +The reviewed Blueprint contains 209 source-facing statements, of which 206 are associated with +1338 proved Lean declarations and 3 remain visibly open, connected by 467 mathematical dependency +edges. Chapter 2 contributes 41 formalized statements, 174 declarations, and 56 incoming edges. Chapter 3 contributes 7 formalized statements, 32 declarations, and 19 incoming edges. Chapter 4 contributes 73 formalized statements, 568 declarations, and 159 incoming edges. -Chapter 5 contributes 31 statements (28 formalized and 3 open), 195 declarations, and 70 incoming -edges. +Chapter 5 contributes 31 statements (28 formalized and 3 open), 203 declarations, and 70 incoming +edges. Chapter 6 contributes 57 formalized statements, 361 declarations, and 163 incoming edges. The completed Chapter 2 frontier includes Proposition 5's numerical-normal-form integrality criterion, the full raw Poisson formula, affine invariance, restriction recovery, the -spectral-support bounds, the coordinate/univariate binary-degree formula, Proposition 3 on trace -monomials, and trace-pairing coordinates. The completed Chapter 3 frontier includes +spectral-support bounds, Relation (30)'s NNF Fourier formula, Proposition 9's restriction-square +identity, Proposition 11's Walsh-divisibility degree bound, the coordinate/univariate +binary-degree formula, Proposition 3 on trace monomials, and trace-pairing coordinates. The +completed Chapter 3 frontier includes the general Reed--Muller distance theorem, Proposition 12's minimum-weight affine-flat classification, dimension and cardinality formulas, and duality. @@ -65,12 +67,27 @@ trace-character/nonlinearity reduction. The quadratic trace representation is cl and even dimensions. The three open nodes preserve the complete analytic source statements for the Weil character-sum bound, its nonlinearity corollary, and the reciprocal character-sum bound. +The Chapter 6 inventory is source-reviewed and Blueprint-synchronized. Its 57 formalized nodes +cover the spectral and derivative characterizations of bentness, duality, the Rothaus and +McEliece--Ax algebraic-degree bounds, primary and secondary constructions, decompositions and +counting, NNF, geometric and second-order characterizations, hyper-bent functions, partially bent +and plateaued superclasses, normal extensions, and the explicit finite-field Kerdock family and +code parameters. The proofs reuse FABL's canonical Fourier, ANF, degree, affine, and derivative +interfaces and the Chapter 2--5 Walsh, Reed--Muller, nonlinearity, quadratic, trace, restriction, +and normality layers. + Chapter 2 has no open node: the finite-field coordinate theorem identifies ANF degree with the maximum binary weight in the univariate support, cyclotomic-orbit noncancellation closes Carlet Proposition 3, and the trace-pairing coordinate theorem is compiled. Chapter 3 likewise has no open node: the affine-flat normal form, codimension--degree theorem, and equality-case slice infrastructure compose into the exact Proposition 12 classification. +Chapter 6 has no open node. Its source corrections are explicit: Proposition 16 uses the necessary +dimension lower bound; the partial-spread constructions use their valid positive range; the +punctured two-level partial-bent definition yields a corrected type formula and counterexamples to +two printed consequences; Langevin's orphan statement assumes a non-affine representative; and the +self-dual-normal-basis Kerdock identity states its coordinate hypotheses. + Source-facing splits remain explicit in Chapter 4. Rodier's one-sided lower endpoint and sharp interval have distinct nodes, as do the finite Hamming-ball and Plotkin lemmas and the resulting higher-order asymptotic estimate. The Reed--Muller coset-distance theorem diff --git a/.agents/audit/dependency-dag.md b/.agents/audit/dependency-dag.md index bba39f0..94d7124 100644 --- a/.agents/audit/dependency-dag.md +++ b/.agents/audit/dependency-dag.md @@ -12,11 +12,12 @@ spine. The current baseline is: | Chapter | Nodes | Formalized | Open | Associated declarations | Incoming edges | |---|---:|---:|---:|---:|---:| -| Carlet Chapter 2 | 38 | 38 | 0 | 166 | 48 | +| Carlet Chapter 2 | 41 | 41 | 0 | 174 | 56 | | Carlet Chapter 3 | 7 | 7 | 0 | 32 | 19 | | Carlet Chapter 4 | 73 | 73 | 0 | 568 | 159 | -| Carlet Chapter 5 | 31 | 28 | 3 | 195 | 70 | -| **Total** | **149** | **146** | **3** | **961** | **296** | +| Carlet Chapter 5 | 31 | 28 | 3 | 203 | 70 | +| Carlet Chapter 6 | 57 | 57 | 0 | 361 | 163 | +| **Total** | **209** | **206** | **3** | **1338** | **467** | An item marked `[open]` has a complete mathematical statement but no Lean association. In the tables below, `consumer <- prerequisite-1, prerequisite-2` denotes one incoming edge from each @@ -79,6 +80,9 @@ carlet-2-prop-4-nnf-mobius <- carlet-2-nnf-existence-uniqueness carlet-2-prop-5-nnf-integrality <- carlet-2-prop-4-nnf-mobius +carlet-2-rel-30-nnf-fourier + <- carlet-2-nnf-existence-uniqueness, carlet-2-pseudoboolean-fourier, + carlet-2-prop-7-subspace-indicator ``` The restriction theorem has two genuine mathematical prerequisites: unique ANF recovery and affine @@ -108,6 +112,8 @@ carlet-2-rel-22-plancherel carlet-2-spectral-support-bounds <- carlet-2-cor-1-poisson-summation, carlet-2-restriction-recovery, carlet-2-nnf-existence-uniqueness +carlet-2-prop-11-walsh-divisibility + <- carlet-2-def-algebraic-degree, carlet-2-def-walsh-transform ``` The normalized Poisson theorem and Carlet's full Corollary 1 are separate consumers of the same two @@ -127,6 +133,9 @@ carlet-2-rel-25-wiener-khinchin carlet-2-def-walsh-transform carlet-2-rel-26-total-autocorrelation <- carlet-2-rel-25-wiener-khinchin +carlet-2-prop-9-restriction-square + <- carlet-2-cor-1-poisson-summation, carlet-2-rel-25-wiener-khinchin, + carlet-2-def-2-derivative ``` Together with the convolution and Walsh-transform edges shown above, these nodes derive the raw @@ -152,7 +161,7 @@ explicit Frobenius orbit of a trace monomial. The trace-pairing coordinate theor the Chapter 5 quadratic representation and its character-sum reduction. Proposition 3 follows from the binary-degree formula and cyclic-orbit weight invariance. -The Chapter 2 groups above contain exactly 48 incoming statement edges. +The Chapter 2 groups above contain exactly 56 incoming statement edges. ## Chapter 3: Reed--Muller coding @@ -610,6 +619,229 @@ bound remain separate because the former is an additive-character theorem and th rational-function estimate. Across the four Chapter 5 families, the reviewed counts are `34 + 11 + 19 + 6 = 70` incoming edges. +## Chapter 6: bent functions + +Chapter 6 has 57 reviewed statements, all formalized by 361 proved declarations with 163 incoming +statement edges. Its graph reuses the Chapter 2 raw Walsh, Fourier, NNF, Poisson, derivative, and +trace layers; the Chapter 3 Reed--Muller layer; the Chapter 4 nonlinearity, propagation, +support-code, and linear-structure layers; and the Chapter 5 quadratic, restriction, trace, and +normality layers. + +### Bentness, duality, and algebraic degree + +```text +carlet-6-def-7-bent + <- carlet-4-rel-36-covering-radius-bent, carlet-4-nonlinearity-affine-invariance, + carlet-2-def-walsh-transform, carlet-2-def-hamming-distance +carlet-6-lemma-2-walsh-congruence + <- carlet-6-def-7-bent, carlet-2-parseval +carlet-6-theorem-8-perfect-nonlinearity + <- carlet-6-def-7-bent, carlet-2-rel-25-wiener-khinchin, + carlet-4-def-propagation-criteria +carlet-6-prop-16-support-code + <- carlet-6-def-7-bent, carlet-4-resiliency-support-dual-distance, + carlet-2-balanced-zero-walsh, carlet-2-parseval + +carlet-6-dual + <- carlet-6-def-7-bent, carlet-2-def-walsh-transform, carlet-2-fourier-inversion +carlet-6-rel-44-dual-isometry + <- carlet-6-dual, carlet-2-rel-22-plancherel, carlet-2-def-hamming-distance +carlet-6-rel-45-dual-derivatives + <- carlet-6-dual, carlet-6-rel-44-dual-isometry, carlet-2-prop-6-fourier-shifts, + carlet-2-def-2-derivative +carlet-6-dual-nnf + <- carlet-6-dual, carlet-2-nnf-existence-uniqueness, carlet-2-rel-30-nnf-fourier +carlet-6-prop-17-dual-nnf-divisibility + <- carlet-6-dual-nnf, carlet-6-lemma-2-walsh-congruence, + carlet-2-prop-5-nnf-integrality +carlet-6-half-degree-anf-complement + <- carlet-6-prop-17-dual-nnf-divisibility, carlet-6-dual-nnf, + carlet-2-anf-existence-uniqueness +carlet-6-rel-46-dual-poisson + <- carlet-6-dual, carlet-2-cor-1-poisson-summation + +carlet-6-quadratic-bent-characterization + <- carlet-6-def-7-bent, carlet-5-def-quadratic-symplectic-form, carlet-5-theorem-5, + carlet-5-quadratic-weight-nonlinearity-values +carlet-6-prop-18-rothaus-degree-bound + <- carlet-6-prop-17-dual-nnf-divisibility, carlet-6-dual, + carlet-2-def-algebraic-degree +carlet-6-prop-19 + <- carlet-6-rel-46-dual-poisson, carlet-6-prop-18-rothaus-degree-bound, carlet-6-dual, + carlet-2-anf-existence-uniqueness +``` + +The duality branch keeps Carlet's unnormalized integer Walsh convention. Proposition 17 is proved +through the NNF Fourier formula and its divisibility conditions; reducing the half-degree identity +modulo two gives the complementary ANF-coefficient relation. Proposition 19 composes Relation (46) +with a reusable McEliece--Ax character-sum divisibility theorem, the exact two-adic valuation of a +top-degree ANF slice, and the dual Rothaus bound. + +### Primary and secondary constructions + +```text +carlet-6-maiorana-mcfarland + <- carlet-6-def-7-bent, carlet-5-def-maiorana-mcfarland, + carlet-5-affine-walsh-spectrum +carlet-6-prop-20-general-maiorana-mcfarland + <- carlet-6-maiorana-mcfarland, carlet-5-affine-flat-restriction-bound, + carlet-6-def-7-bent +carlet-6-partial-spread-construction + <- carlet-6-theorem-12-geometric-characterization + +carlet-6-direct-sum + <- carlet-6-def-7-bent, carlet-6-dual +carlet-6-rothaus-construction + <- carlet-6-theorem-10-slice-construction, carlet-6-cor-4-three-function-construction +carlet-6-theorem-9-flat-switching + <- carlet-6-theorem-8-perfect-nonlinearity, carlet-6-rel-46-dual-poisson, + carlet-2-prop-11-walsh-divisibility, carlet-3-prop-12 +carlet-6-theorem-10-slice-construction + <- carlet-6-def-7-bent, carlet-6-dual +carlet-6-indirect-sum + <- carlet-6-theorem-10-slice-construction +carlet-6-prop-21-permutation-reindexing + <- carlet-6-def-7-bent, carlet-2-def-hamming-distance +carlet-6-prop-22-three-function-identity + <- carlet-2-pseudoboolean-fourier, carlet-2-def-walsh-transform +carlet-6-cor-4-three-function-construction + <- carlet-6-prop-22-three-function-identity, carlet-6-lemma-2-walsh-congruence, + carlet-6-dual + +carlet-6-theorem-11-hyperplane-restrictions + <- carlet-2-prop-9-restriction-square, carlet-6-def-7-bent +carlet-6-hyperplane-restriction-plateaued + <- carlet-6-theorem-11-hyperplane-restrictions, carlet-6-def-plateaued, + carlet-4-rel-35-nonlinearity-walsh +``` + +The flat-switching proof composes the Chapter 2 Walsh-divisibility theorem with the Chapter 3 +minimum-weight affine-flat classification. The general slice construction owns the indirect-sum +and Rothaus specializations. The hyperplane decomposition uses the exact restriction-square +identity rather than introducing a second spectral normalization. + +### Counting and three characterizations + +```text +carlet-6-maiorana-mcfarland-count + <- carlet-6-maiorana-mcfarland +carlet-6-naive-bent-count-bound + <- carlet-6-prop-18-rothaus-degree-bound, carlet-3-reed-muller-dimension + +carlet-6-prop-23-nnf-characterization + <- carlet-6-lemma-2-walsh-congruence, carlet-2-rel-30-nnf-fourier, + carlet-2-prop-4-nnf-mobius, carlet-2-prop-5-nnf-integrality +carlet-6-lemma-3-subspace-indicators +carlet-6-theorem-12-geometric-characterization + <- carlet-6-prop-23-nnf-characterization, carlet-6-lemma-3-subspace-indicators, + carlet-6-lemma-2-walsh-congruence, carlet-2-prop-7-subspace-indicator, + carlet-6-dual +carlet-6-prop-24-second-order-characterization + <- carlet-6-theorem-8-perfect-nonlinearity, carlet-4-autocorrelation-indicator-bounds, + carlet-4-second-derivative-sum, carlet-2-def-convolution, + carlet-2-prop-8-convolution, carlet-2-fourier-inversion +``` + +Lemma 3 is an independent finite-dimensional subspace-indicator root. Theorem 12 combines it with +the NNF congruence criterion and the half-dimensional indicator transform; its exact generalized +partial-spread case also transports the dual through perpendicular subspaces. Proposition 24 is +proved by Fourier transforming the triple convolution of the sign function. + +### Hyper-bent functions and superclasses + +```text +carlet-6-def-hyper-bent + <- carlet-2-absolute-trace, carlet-2-trace-pairing-coordinates, carlet-6-def-7-bent +carlet-6-lemma-4-subfield-intersection + <- carlet-6-def-hyper-bent, carlet-2-absolute-trace +carlet-6-prop-25-psap-hyper-bent + <- carlet-6-def-hyper-bent, carlet-6-lemma-4-subfield-intersection, + carlet-6-partial-spread-construction, carlet-5-quadratic-trace-representation + +carlet-6-prop-26-partially-bent + <- carlet-2-rel-25-wiener-khinchin, carlet-2-parseval, + carlet-4-def-linear-kernel, carlet-6-def-plateaued +carlet-6-prop-27-fourier-uncertainty + <- carlet-2-pseudoboolean-fourier, carlet-2-parseval, + carlet-2-cor-1-poisson-summation +carlet-6-def-partial-bent + <- carlet-2-pseudoboolean-fourier +carlet-6-partial-bent-duality + <- carlet-6-def-partial-bent, carlet-2-cor-2-fourier-involution +carlet-6-partial-bent-degree-bound + <- carlet-6-def-partial-bent, carlet-6-prop-18-rothaus-degree-bound +carlet-6-partial-bent-types + <- carlet-6-def-partial-bent, carlet-2-parseval +carlet-6-partial-bent-disjoint-support-sum + <- carlet-6-def-partial-bent, carlet-6-partial-bent-types, + carlet-2-pseudoboolean-fourier +carlet-6-def-plateaued + <- carlet-2-def-walsh-transform, carlet-2-parseval, carlet-6-def-7-bent +carlet-6-plateaued-support-nonlinearity + <- carlet-6-def-plateaued, carlet-4-rel-35-nonlinearity-walsh, carlet-2-parseval +carlet-6-prop-28-second-order-plateaued + <- carlet-6-def-plateaued, carlet-6-prop-24-second-order-characterization +carlet-6-plateaued-coset-orphan + <- carlet-6-def-plateaued, carlet-6-plateaued-support-nonlinearity, + carlet-3-reed-muller-code, carlet-4-def-nonlinearity, carlet-2-parseval +``` + +The finite-field hyper-bent predicate is reduced to ordinary cube bentness through the Chapter 2 +trace-pairing equivalence. Proposition 26 reuses Wiener--Khinchin and the Fourier uncertainty +equality case to recover the bent-plus-affine complementary decomposition. Plateauedness keeps a +positive integer Walsh amplitude and derives its power-of-two form through Parseval. Under the +source's exact punctured two-level definition, Fourier involution proves partial-bent duality and +Parseval gives the corrected type formula; explicit two-variable examples refute the printed +degree bound and disjoint-support closure. The orphan theorem uses the necessary non-affine +hypothesis. + +### Normal extensions and Kerdock codes + +```text +carlet-6-def-8-normal-extension + <- carlet-6-def-7-bent +carlet-6-normal-extension-composition-duality + <- carlet-6-def-8-normal-extension, carlet-6-dual, carlet-6-rel-46-dual-poisson +carlet-6-normal-zero-dimensional-characterization + <- carlet-6-def-8-normal-extension, carlet-5-def-4-normality, + carlet-2-affine-invariance +carlet-6-prop-29-direct-sum-normality + <- carlet-6-direct-sum, carlet-6-def-8-normal-extension, + carlet-6-normal-zero-dimensional-characterization, + carlet-5-affine-flat-restriction-bound +carlet-6-prop-30-normality-descends + <- carlet-6-def-8-normal-extension, carlet-6-normal-zero-dimensional-characterization, + carlet-6-prop-31-normal-extension-replacement, + carlet-5-affine-flat-restriction-bound +carlet-6-prop-31-normal-extension-replacement + <- carlet-6-def-8-normal-extension, carlet-6-normal-extension-composition-duality, + carlet-6-rel-46-dual-poisson + +carlet-6-rel-56-complete-quadratic + <- carlet-6-quadratic-bent-characterization, carlet-2-def-support-weight +carlet-6-kerdock-parameters + <- carlet-6-def-7-bent, carlet-3-reed-muller-code, + carlet-4-reed-muller-coset-distance +carlet-6-kerdock-field-trace-identity + <- carlet-6-rel-56-complete-quadratic, carlet-2-absolute-trace, + carlet-6-kerdock-field-construction +carlet-6-kerdock-field-construction + <- carlet-5-quadratic-trace-representation, carlet-6-quadratic-bent-characterization, + carlet-6-kerdock-parameters, carlet-2-absolute-trace, + carlet-2-trace-pairing-coordinates +``` + +The zero-dimensional normal-extension statement distinguishes the source's linear-subspace +convention from Chapter 5's affine-flat convention and supplies the necessary affine-equivalence +correction with an explicit two-variable counterexample. Proposition 31 is proved through the +Poisson formula. The Kerdock parameter theorem consumes only a finite quadratic representative +family with pairwise bent sums. The direct trace expression allowed by Carlet's footnote 44 now +constructs such a family and proves its parameters; the separate coordinate theorem proves the +self-dual-normal-basis identity under its explicit Frobenius, trace, and trace-pairing hypotheses +without conflating it with the coordinate-invariant construction. + +These Chapter 6 families contain exactly 163 incoming statement edges. + ## Remaining proof frontier Three source statements remain open, all in the analytic Chapter 5 character-sum branch. Their complete @@ -632,21 +864,25 @@ and the sharp higher-order upper bound are associated with their complete produc their mathematical ingredients remain separately visible in the graph. Chapter 5's quadratic normal form, quadratic trace representation, Relation (42), random-nonnormality limit, and trace-character reduction are closed; the three analytic open nodes above define the remaining -reviewed frontier. +reviewed frontier. Chapter 6 is closed: all 57 nodes have proved associations, while its nineteen +source-recovery records remain outside the graph until their cited statements or certificates can +be recovered faithfully. ## Machine verification The current counts and edge set are enforced by `blueprint-verso/scripts/validate_manifest.py`. The style and association split are enforced by -`blueprint-verso/scripts/check_statement_style.py`, which runs through the site driver. Before a -handoff, run from the repository root: +`blueprint-verso/scripts/check_statement_style.py`, which runs through the site driver. Local +handoff verification uses the narrow affected module and lightweight text gates: ```bash -lake build CryptBoolean +lake build CryptBoolean.Carlet.Chapter06 ./.github/scripts/forbidden_tokens.sh -./.github/scripts/audit_axioms.sh -./blueprint-verso/scripts/site.sh build +python3 ./blueprint-verso/scripts/check_statement_style.py ``` +The root build, axiom audit, complete Blueprint build, and publication build run in GitHub Actions; +they are intentionally not run on the development machine. + The inventories under `.agents/inventory/`, the Verso `uses :=` metadata, this audit, and the manifest validator must be changed together whenever the reviewed graph changes. diff --git a/.agents/audit/fidelity.md b/.agents/audit/fidelity.md index 31c3b17..07b3d1d 100644 --- a/.agents/audit/fidelity.md +++ b/.agents/audit/fidelity.md @@ -17,14 +17,15 @@ The generated manifest currently verifies the following baseline: | Chapter | Statements | Formalized | Open | Associated declarations | Incoming statement edges | |---|---:|---:|---:|---:|---:| -| Carlet Chapter 2 | 38 | 38 | 0 | 166 | 48 | +| Carlet Chapter 2 | 41 | 41 | 0 | 174 | 56 | | Carlet Chapter 3 | 7 | 7 | 0 | 32 | 19 | | Carlet Chapter 4 | 73 | 73 | 0 | 568 | 159 | -| Carlet Chapter 5 | 31 | 28 | 3 | 195 | 70 | -| **Total** | **149** | **146** | **3** | **961** | **296** | +| Carlet Chapter 5 | 31 | 28 | 3 | 203 | 70 | +| Carlet Chapter 6 | 57 | 57 | 0 | 361 | 163 | +| **Total** | **209** | **206** | **3** | **1338** | **467** | The manifest count is an association count, not a claim that every printed result in Carlet -Chapters 2--5 is complete. Coverage outside these 149 reviewed nodes remains governed by the +Chapters 2--6 is complete. Coverage outside these 209 reviewed nodes remains governed by the inventories under `.agents/inventory/`. ## Corrected source mappings @@ -76,6 +77,21 @@ inventories under `.agents/inventory/`. | `carlet-5-covering-sequence-resiliency` | Carlet p. 74 derives correlation-immunity and resiliency orders from the minimum nonzero transform-fiber weight and gives converses at the first failed order. | The forward and converse declarations retain the stated minimum and nontrivial-level conditions on every feasible order. The Walsh-zero coefficient sequence is constructed explicitly from its defining formula. | | `carlet-5-derivative-space-partial-covering-sequence` | Carlet p. 74: a nonzero binary space of derivatives has pointwise integer sum zero or half its cardinality, and a minimal representative direction set gives a nontrivial partial covering sequence. | Ten declarations model the finite Boolean-function subspace, prove the half-cardinality dichotomy, choose one direction per derivative, prove the resulting derivative map is bijective and the representative set has cardinality `|D|`, and establish the two-level partial-covering property with nonzero upper level. | | `carlet-5-theorem-6-weight-corollary` | Carlet p. 76 divides by a nonzero level `rho` to write `W_f(0)=(1-rho'/rho) sum_(x in A)(-1)^f(x)`. | The associated theorem proves the equivalent integer identity `rho W_f(0)=(rho-rho') sum_(x in A)(-1)^f(x)`, valid even at `rho=0`; the printed quotient follows under its stated nonzero hypothesis. | +| `carlet-6-prop-16-support-code` | Carlet Proposition 16, p. 79: the support of a bent function generates the ambient space and yields a binary linear code with dual distance at least three. | The printed unrestricted statement is false in dimension two: a weight-one bent function has singleton support. The formal node makes the necessary `n>=4` hypothesis explicit and proves both spanning and the dual-distance conclusion. | +| `carlet-6-prop-18-rothaus-degree-bound` | Carlet Proposition 18, p. 83 gives degree at most `n/2` for even `n>=4`; the following sentence treats `n=2`. | The main theorem retains `n>=4`. A separate declaration proves that every two-variable bent function has algebraic degree exactly two, and the same conclusions are applied independently to the dual. | +| `carlet-6-prop-19` | Carlet Proposition 19, Relation (47), p. 83 relates the algebraic degrees `d` and `d_tilde` of a bent function and its dual by `(n/2-d) >= (n/2-d_tilde)/(d_tilde-1)`. | One associated declaration proves the reusable McEliece--Ax divisibility `2^ceil(n/d) | sum_x (-1)^f(x)` for every positive degree bound `d`; the second composes it with Relation (46), an exact top-ANF-slice valuation, the dual degree bound, and the separate `n=2` case to prove the source's rational inequality. | +| `carlet-6-partial-spread-construction` | Carlet pp. 86--88 constructs the `PS^-` and `PS^+` bent families from a spread of `V_{2m}`. | The formal statement uses `m>=2`, the smallest range in which the two printed support-cardinality choices and the stated nonzero-subspace geometry are simultaneously valid. No degenerate low-dimensional family is silently admitted. | +| `carlet-6-prop-27-fourier-uncertainty` | Carlet Proposition 27, pp. 104--105: a nonzero pseudo-Boolean function and its raw Fourier support satisfy the uncertainty product, with equality exactly for a modulated affine-flat indicator. | The equality form explicitly quantifies the printed frequency `u` and requires the scale `lambda` to be nonzero; both are necessary for the iff and are implicit in the source prose. | +| `carlet-6-lemma-4-subfield-intersection` | Carlet Lemma 4, p. 102 is printed with a positive ambient dimension while its notation uses the quadratic tower `GF(2^m) subset GF(2^(2m))`. | The Blueprint corrects the dimension convention to positive half-dimension `m`, so the ambient Boolean dimension is even. The complete field-intersection claim remains visible without a weakened association. | +| `carlet-6-partial-bent-degree-bound` | Carlet p. 105 asserts the bent half-dimension degree bound for partial-bent functions defined only by two Fourier levels away from zero. | The assertion is false under that exact definition. The associated declarations give a two-variable point-indicator that satisfies the punctured two-level condition and has algebraic degree two, strictly above `n/2`. | +| `carlet-6-partial-bent-types` | Carlet p. 105 gives two possible relations among the zero-frequency value, the level `lambda`, and `f(0)`. | Fourier involution and Parseval give the corrected alternatives `W_f(0)-e=-(lambda-e)(q-1)` and `W_f(0)-e=(q+lambda-e)(q+1)` for `q=2^(n/2)` and `e=f(0)`; the node states exactly this dichotomy. | +| `carlet-6-partial-bent-disjoint-support-sum` | Carlet p. 105 asserts closure under sums of partial-bent functions of one type whose supports intersect only at zero. | The printed assertion is false under the punctured two-level definition. Explicit two-variable partial-bent functions satisfy the stated type and support conditions while their sum is not partial bent. | +| `carlet-6-prop-28-second-order-plateaued` | Carlet Proposition 28, Relation (55), p. 106 characterizes plateaued functions by a constant second-order derivative sum. | The proof paragraph's reference to “Proposition 52” is a typographical error for Relation (52), the second-order bent characterization. The dependency edge targets that mathematical statement. | +| `carlet-6-plateaued-coset-orphan` | Carlet p. 106 states that a plateaued function determines an orphan first-order Reed--Muller coset. | Affine functions are plateaued but determine the least coset, so the statement needs the omitted non-affine hypothesis. The formal theorem proves the corrected claim and records the affine countercase. | +| `carlet-6-normal-zero-dimensional-characterization` | Carlet p. 108 says a bent function is normal exactly when a zero-dimensional constant is a normal extension. | Under Chapter 5's affine-flat normality convention, the bare statement is false. The formal node proves the exact linear-subspace version, proves the affine-flat version after an affine automorphism, and supplies a two-variable bent counterexample showing that this automorphism cannot be omitted. | +| `carlet-6-kerdock-parameters` | Carlet pp. 108--110 derives the Kerdock size and minimum distance from a quadratic representative family with pairwise bent sums. | The associated theorem is deliberately conditional on a finite family satisfying those hypotheses. It proves containment between `R(1,n)` and `R(2,n)`, distinctness of the first-order cosets, cardinality, and minimum distance; it is not presented as an existence proof for the explicit field family. | +| `carlet-6-kerdock-field-trace-identity` | Carlet Relation (56), pp. 109--110 identifies the complete quadratic function with a trace expression in self-dual normal coordinates. | The theorem states the exact coordinate data it consumes: Frobenius is cyclic rotation, absolute trace is coordinate sum, and the trace pairing is the binary dot product. It then proves the identity; these hypotheses are not silently inferred from an arbitrary coordinate equivalence. | +| `carlet-6-kerdock-field-construction` | Carlet pp. 109--110 and footnote 44 allow the trace expression to define the Kerdock representatives directly. | The construction is coordinate-invariant: the Chapter 5 trace-quadratic polar formula proves every nonzero difference bent, then the conditional Kerdock parameter theorem supplies the code size and distance. It does not depend on the separate self-dual-normal-basis coordinate identity. | **Proof of Proposition 13.** Carlet refers the omitted proof to reference [72]. The formal proof follows that source's two arguments: differentiating a closest order-`r` Reed--Muller @@ -105,24 +121,44 @@ needs an explicit fidelity decision: `delta*n`; this is not Carlet's printed `n^delta` claim. That mismatch must be resolved against the primary journal theorem or recorded as a source correction before promotion. +### Chapter 6 source-recovery boundary + +Nineteen Chapter 6 records remain outside the promoted Blueprint graph. They preserve the source +boundary without manufacturing declarations from survey prose or incomplete citations: + +- equivalent Hadamard, difference-set, and Cayley-graph characterizations; alternate support-code, + derivative-moment, and geometric/GPS descriptions; +- explicit low-degree trace and power families, the `D`, `C`, Dobbertin, vectorial almost-bent, + power-sum, homogeneous, and additional primary-class structural results; +- cited specializations of the secondary constructions, additional decomposition and counting + claims, the cyclic-code degree theorem for hyper-bent functions, and the trace family from + reference [101]; +- finite nonnormal examples whose certificates or dimension-ten translate are not printed, and + Kerdock distance-enumerator, Preparata-duality, and `Z/4Z`-linearity properties that require a + code layer beyond the current membership and minimum-distance interface. + +Each record gives the recoverable quantifiers and parameters, identifies the missing primary +statement or certificate, and names the already formalized declarations that a future promotion +must reuse. + ## Reviewed formalized surface -The 146 formalized statements are split by mathematical result. Implementation module boundaries +The formalized statements are split by mathematical result. Implementation module boundaries do not determine this split. The fidelity column records how the compiled declarations meet the displayed source mathematics. | Family | Formalized Blueprint items | Fidelity | Lean declarations | |---|---|---|---:| -| Boolean foundations and raw Walsh transform | `carlet-2-def-boolean-function`, `carlet-2-def-support-weight`, `carlet-2-def-walsh-transform`, `carlet-2-walsh-normalization`, `carlet-2-balanced-zero-walsh` | Exact definitions and results, including Walsh normalization and the Hamming-weight identification | 20 | +| Boolean foundations and raw Walsh transform | `carlet-2-def-boolean-function`, `carlet-2-def-support-weight`, `carlet-2-def-walsh-transform`, `carlet-2-walsh-normalization`, `carlet-2-balanced-zero-walsh` | Exact definitions and results, including Walsh normalization, injectivity of the integer sign encoding, and the Hamming-weight identification | 21 | | Algebraic normal form | `carlet-2-anf-skeleton`, `carlet-2-anf-existence-uniqueness` | Exact, with the explicit zero-degree convention | 18 | -| Numerical normal form | `carlet-2-nnf-existence-uniqueness`, `carlet-2-prop-4-nnf-mobius`, `carlet-2-prop-5-nnf-integrality` | Exact | 19 | +| Numerical normal form | `carlet-2-nnf-existence-uniqueness`, `carlet-2-rel-30-nnf-fourier`, `carlet-2-prop-4-nnf-mobius`, `carlet-2-prop-5-nnf-integrality` | Exact, including the raw Fourier transform of an arbitrary NNF | 21 | | Algebraic degree, distance, and affine functions | `carlet-2-def-algebraic-degree`, `carlet-2-support-degree-addition`, `carlet-2-def-hamming-distance`, `carlet-2-relative-hamming-normalization`, `carlet-2-def-affine-functions` | Exact source items plus explicit relative-distance normalization and derived addition law | 18 | | Affine invariance | `carlet-2-affine-invariance` | Exact source theorem with used ANF-substitution proof layer | 13 | | Restriction recovery | `carlet-2-restriction-recovery` | Exact formula and affine-automorphism consequence | 10 | | Raw pseudo-Boolean Fourier operations | `carlet-2-pseudoboolean-fourier`, `carlet-2-prop-6-fourier-shifts`, `carlet-2-cor-2-fourier-involution`, `carlet-2-prop-7-subspace-indicator`, `carlet-2-poisson-normalized-specialization`, `carlet-2-cor-1-poisson-summation`, `carlet-2-def-convolution`, `carlet-2-prop-8-convolution`, `carlet-2-rel-22-plancherel` | Exact raw results plus one explicitly labelled direct-FABL normalized specialization | 13 | -| Spectral-support bounds | `carlet-2-spectral-support-bounds` | Exact with explicit zero-function conventions and the raw/normalized support identity | 24 | +| Spectral-support bounds and Walsh divisibility | `carlet-2-spectral-support-bounds`, `carlet-2-prop-11-walsh-divisibility` | Exact with explicit zero-function conventions, the raw/normalized support identity, and the degree consequence of uniform Walsh divisibility | 26 | | Walsh inversion and Parseval for sign views | `carlet-2-fourier-inversion`, `carlet-2-parseval` | Exact sign-function specializations | 6 | -| Derivatives and autocorrelation | `carlet-2-def-2-derivative`, `carlet-2-def-autocorrelation`, `carlet-2-rel-25-wiener-khinchin`, `carlet-2-rel-26-total-autocorrelation` | Exact | 6 | +| Derivatives, autocorrelation, and restriction squares | `carlet-2-def-2-derivative`, `carlet-2-def-autocorrelation`, `carlet-2-rel-25-wiener-khinchin`, `carlet-2-rel-26-total-autocorrelation`, `carlet-2-prop-9-restriction-square` | Exact, including both autocorrelation and perpendicular-Walsh forms of Relation (28) | 9 | | Finite-field representation | 5 formalized nodes from `carlet-2-absolute-trace` through `carlet-2-trace-monomial-degree` | Exact absolute trace and interpolation results, an explicit shared trace-pairing coordinate theorem, the binary-degree formula for canonical univariate representations, and Proposition 3's exact nonzero trace-monomial degree | 19 | | Reed--Muller foundations | `carlet-3-affine-weight`, `carlet-3-reed-muller-code`, `carlet-3-theorem-1-order-one` | Exact source items plus explicitly derived order-one specialization | 11 | | General Reed--Muller distance | `carlet-3-theorem-1` | Exact all-orders theorem | 2 | @@ -137,11 +173,16 @@ source mathematics. | Autocorrelation indicators | 5 formalized nodes from `carlet-4-def-autocorrelation-indicators` through `carlet-4-indicator-nonlinearity-spectral-support` | Exact indicators, moment identities, and spectral/nonlinearity consequences | 36 | | Maximum correlation and generalized distance | 3 formalized nodes from `carlet-4-def-maximum-correlation` through `carlet-4-generalized-linear-structure-distance` | Exact coordinate-restriction and linear-structure distances | 38 | | Other complexity criteria | `carlet-4-other-complexity-definitions`, `carlet-4-kth-nonhomomorphicity`, `carlet-4-affine-reindex-first-resilient` | Exact criteria with the recorded tuple-count terminology discrepancy | 36 | -| Chapter 5 affine and quadratic classes | 13 formalized nodes from `carlet-5-affine-walsh-spectrum` through `carlet-5-def-quadratic-semi-bent` | Exact affine spectra, quadratic polar/radical structure, Relation (41), Theorems 4 and 5, derivative and even-rank consequences, exact weight and nonlinearity value sets with realizations, the complete affine normal-form trichotomy, the odd/even finite-field quadratic trace representation, the quadraticization step and its degree-three iteration, and an exact semi-bent predicate | 89 | +| Chapter 5 affine and quadratic classes | 13 formalized nodes from `carlet-5-affine-walsh-spectrum` through `carlet-5-def-quadratic-semi-bent` | Exact affine spectra, quadratic polar/radical structure, Relation (41), Theorems 4 and 5, derivative and even-rank consequences, exact weight and nonlinearity value sets with realizations, the complete affine normal-form trichotomy, the odd/even finite-field quadratic trace representation and its reusable Frobenius-linear, polar-sum, degree, and middle-term components, the quadraticization step and its degree-three iteration, and an exact semi-bent predicate | 97 | | Chapter 5 flat restrictions and normality | `carlet-5-flat-indicator-walsh-nonlinearity`, `carlet-5-rel-42-restriction-nonlinearity`, `carlet-5-affine-flat-restriction-bound`, `carlet-5-def-4-normality`, `carlet-5-random-nonnormality` | Corrected codimension-one flat value, total restriction inequalities, the full equality case, exact fixed-dimension normality predicates, the finite certificate bound, and the exact floored logarithmic random-nonnormality limit | 44 | | Chapter 5 covering sequences | 9 formalized nodes from `carlet-5-def-5-covering-sequence` through `carlet-5-theorem-6-weight-corollary` | Exact integer covering and partial-covering definitions, Walsh characterization, balancedness/resiliency consequences, regular families, the derivative-space representative construction, Theorem 6, and its division-free weight identity | 56 | | Chapter 5 trace-character reduction | `carlet-5-trace-character-sum-walsh` | Reuse of the shared Chapter 2 trace-pairing coordinate theorem, the exact complete-sum Walsh identity, and the conditional maximum-Walsh/nonlinearity reduction | 6 | -| **Total** | **146 items** | | **961** | +| Chapter 6 bentness, duality, and algebraic degree | 14 formalized nodes from `carlet-6-def-7-bent` through `carlet-6-prop-19` | Exact Walsh and derivative characterizations, dual isometry, derivative and Poisson identities, NNF divisibility, the quadratic criterion, the Rothaus bound including dimension two, and Relation (47) through the reusable McEliece--Ax theorem | 43 | +| Chapter 6 constructions and decompositions | 13 formalized nodes from `carlet-6-maiorana-mcfarland` through `carlet-6-hyperplane-restriction-plateaued` | Exact Maiorana--McFarland and partial-spread primary families, flat switching, slicing, direct, indirect, Rothaus, permutation, and three-function constructions, and the hyperplane restriction formulas | 77 | +| Chapter 6 counting and characterizations | 6 formalized nodes from `carlet-6-maiorana-mcfarland-count` through `carlet-6-prop-24-second-order-characterization` | Exact finite counting bounds and NNF, geometric, generalized partial-spread, and second-order characterizations using the canonical raw Fourier normalization | 67 | +| Chapter 6 hyper-bent functions and superclasses | 14 formalized nodes from `carlet-6-def-hyper-bent` through `carlet-6-plateaued-coset-orphan` | Exact field/cube coordinate equivalence, subfield-intersection and `PS_ap` construction, partially bent decomposition, uncertainty equality, partial-bent duality, corrected partial-bent type formula and two counterexamples, and plateaued support, derivative, and corrected orphan results | 97 | +| Chapter 6 normal extensions and Kerdock codes | 10 formalized nodes from `carlet-6-def-8-normal-extension` through `carlet-6-kerdock-field-construction` | Exact coordinate-invariant extension relation, duality, composition, replacement, and direct-sum/normality results with the affine-flat correction; complete quadratic functions; conditional Kerdock parameters; the explicit trace family; and its separately hypothesized self-dual-normal-coordinate identity | 77 | +| **Total** | **206 items** | | **1338** | The following distinctions are part of the fidelity boundary: @@ -207,6 +248,25 @@ The following distinctions are part of the fidelity boundary: - The four Chapter 5 citation-recovery records are not weakened into Blueprint statements. In particular, the BKSSW primary formulation uses affine dimension at least `delta*n`, whereas Carlet prints `n^delta`. +- Chapter 6 reuses FABL's canonical bent predicate and dual, Maiorana--McFarland permutation + theorem, ANF and algebraic-degree APIs, affine functions, derivatives, and complete quadratic + decomposition. Raw Carlet formulas pass through the Chapter 2 scaling, inversion, Parseval, + Poisson, restriction-square, Walsh-divisibility, and trace-coordinate theorems instead of + introducing a competing normalization. +- Proposition 19 keeps its source inequality and positive even-dimensional domain. Its generic + McEliece--Ax character-sum divisibility result is associated with the same source node as the + final dual-degree relation because it is the cited mathematical proof theorem, not a separate + Carlet statement. +- The exact punctured partial-bent definition is retained even though it makes two printed + consequences false; the Blueprint presents proof-checked counterexamples and the corrected + two-type formula. The normality and orphan statements likewise expose the affine-automorphism + and non-affine hypotheses needed for correctness. +- The conditional Kerdock parameter theorem, the explicit coordinate-invariant field family, and + the self-dual-normal-coordinate identity remain distinct. The identity lists its Frobenius, + trace, and trace-pairing hypotheses, while the construction uses the Chapter 5 quadratic-trace + polar formula and does not assume those coordinates. +- The nineteen Chapter 6 source-recovery records remain outside the 57-node graph rather than + being weakened into statements without recoverable primary-source parameters or certificates. - Definitions, normalization laws, source propositions, and derived consequences have separate Blueprint nodes when their quantifiers or conclusions differ. @@ -224,9 +284,9 @@ declaration association. All three are in the Chapter 5 character-sum branch. Chapter 3 has no open node: Proposition 12's affine-flat and equality-case slice layer is formalized. Chapter 4 has no open node: its former frontier statements are associated with complete declarations while their principal mathematical ingredients retain independent nodes. Chapter 2 -has no open node: the binary-degree formula and Proposition 3 are formalized. The four Chapter 5 -citation-recovery records remain outside the 31-node Chapter 5 graph until their source statements -are complete. +has no open node: the binary-degree formula and Proposition 3 are formalized. Chapter 6 has no open +node: all 57 reviewed statements have proved associations. The four Chapter 5 citation-recovery +records remain outside the 31-node Chapter 5 graph until their source statements are complete. ## Verification perimeter @@ -235,15 +295,17 @@ missing mathematical notation, or inconsistent open/formalized metadata inside s The strict manifest validator checks the exact statement split, declaration presence and proof status, graph node set, open-node set, and edge count. -Run from the repository root: +Local review runs the narrow affected module and lightweight gates from the repository root: ```bash -lake build CryptBoolean +lake build CryptBoolean.Carlet.Chapter06 ./.github/scripts/forbidden_tokens.sh -./.github/scripts/audit_axioms.sh -./blueprint-verso/scripts/site.sh build +python3 ./blueprint-verso/scripts/check_statement_style.py ``` +The root build, axiom audit, complete Blueprint build, and publication build remain GitHub Actions +jobs because the full local workloads are outside the supported development envelope. + Source fidelity still requires human comparison with Carlet; compilation and manifest validation alone do not establish that a statement has the correct domain, hypotheses, normalization, or quantifiers. diff --git a/.agents/inventory/carlet-chapter02.yaml b/.agents/inventory/carlet-chapter02.yaml index c952b9b..8f9528e 100644 --- a/.agents/inventory/carlet-chapter02.yaml +++ b/.agents/inventory/carlet-chapter02.yaml @@ -2,11 +2,11 @@ source: carlet-2010 chapter: 2 status: blueprint-synchronized summary: - statements: 38 - formalized: 38 + statements: 41 + formalized: 41 open: 0 - declarations: 166 - dependency_edges: 48 + declarations: 174 + dependency_edges: 56 items: - id: carlet-2-def-boolean-function kind: definition @@ -45,6 +45,7 @@ items: formal_status: formalized declarations: - CryptBoolean.bitSignInt + - CryptBoolean.bitSignInt_injective - CryptBoolean.bitSignInt_add - CryptBoolean.walshTerm - CryptBoolean.walshTransform @@ -325,6 +326,24 @@ items: dependencies: - carlet-2-rel-25-wiener-khinchin + - id: carlet-2-prop-9-restriction-square + kind: proposition + location: Carlet, Proposition 9 and Relation (28), p. 28 + statement: >- + Let E and E' be complementary subspaces of V_n. For every Boolean + function f, the sum of W_f(u)^2 over u in E^perp equals |E^perp| + times the sum, over a in E', of the squared sign imbalances of the + restrictions of f to the affine cosets a+E. + formal_status: formalized + declarations: + - CryptBoolean.affineSubspaceRestrictionImbalance + - CryptBoolean.sum_autocorrelation_submodule_eq_sum_affineSubspaceRestrictionImbalance_sq + - CryptBoolean.sum_walshTransform_sq_perpendicular_eq_card_mul_sum_restrictionImbalance_sq + dependencies: + - carlet-2-cor-1-poisson-summation + - carlet-2-rel-25-wiener-khinchin + - carlet-2-def-2-derivative + - id: carlet-2-anf-skeleton kind: definition location: Carlet, Relation (1), pp. 9--12 @@ -391,6 +410,23 @@ items: dependencies: - carlet-2-def-boolean-function + - id: carlet-2-rel-30-nnf-fourier + kind: theorem + location: Carlet, Relation (30), p. 32 + statement: >- + If phi(x) = sum_S lambda_S product_(i in S) x_i is the numerical + normal form of a real-valued function on V_n, then its raw Fourier + coefficient at u is (-1)^wt(u) times the sum, over S containing the + support of u, of 2^(n-|S|) lambda_S. + formal_status: formalized + declarations: + - CryptBoolean.rawFourierTransform_numericalMonomial + - CryptBoolean.rawFourierTransform_numericalEval + dependencies: + - carlet-2-nnf-existence-uniqueness + - carlet-2-pseudoboolean-fourier + - carlet-2-prop-7-subspace-indicator + - id: carlet-2-prop-4-nnf-mobius kind: proposition location: Carlet, Proposition 4 and Relation (8), p. 19 @@ -541,6 +577,21 @@ items: dependencies: - carlet-2-anf-existence-uniqueness + - id: carlet-2-prop-11-walsh-divisibility + kind: proposition + location: Carlet, Proposition 11, p. 34 + statement: >- + Let n >= 2 and 1 <= k <= n. If every raw Walsh coefficient of a + Boolean function f is divisible by 2^k, then the algebraic degree of f + is at most n-k+1. + formal_status: formalized + declarations: + - CryptBoolean.vectorFourierCoeff_booleanRealEmbedding_eq + - CryptBoolean.functionAlgebraicDegree_le_of_two_pow_dvd_walshTransform + dependencies: + - carlet-2-def-algebraic-degree + - carlet-2-def-walsh-transform + - id: carlet-2-support-degree-addition kind: lemma location: Derived degree-under-addition lemma diff --git a/.agents/inventory/carlet-chapter05.yaml b/.agents/inventory/carlet-chapter05.yaml index 3e8b14c..b3041ac 100644 --- a/.agents/inventory/carlet-chapter05.yaml +++ b/.agents/inventory/carlet-chapter05.yaml @@ -11,7 +11,7 @@ summary: total_records: 35 formalized: 28 open: 3 - declarations: 195 + declarations: 203 dependency_edges: 70 scope_note: >- Thirty source items below have complete statements checked against the @@ -310,7 +310,15 @@ items: relative norm and iota(N_iota(z))=z^(2^m+1). formal_status: formalized declarations: + - CryptBoolean.binaryFrobeniusLinear + - CryptBoolean.binaryFrobeniusLinear_apply + - CryptBoolean.absoluteTrace_mul_frobeniusPow + - CryptBoolean.oddQuadraticTracePart + - CryptBoolean.oddQuadraticTracePart_polar_eq_sum + - CryptBoolean.functionAlgebraicDegree_traceMonomial_two_pow_add_one_le_two + - CryptBoolean.two_pow_add_one_lt_odd_modulus - CryptBoolean.quadraticTraceMiddleNorm + - CryptBoolean.quadraticTraceMiddle_finrank - CryptBoolean.quadraticTraceMiddleNorm_map_eq_pow - CryptBoolean.functionAlgebraicDegree_le_two_iff_exists_odd_quadraticTraceRepresentation - CryptBoolean.functionAlgebraicDegree_le_two_iff_exists_even_quadraticTraceRepresentation diff --git a/.agents/inventory/carlet-chapter06.yaml b/.agents/inventory/carlet-chapter06.yaml new file mode 100644 index 0000000..e8ef610 --- /dev/null +++ b/.agents/inventory/carlet-chapter06.yaml @@ -0,0 +1,2495 @@ +source: carlet-2010 +chapter: 6 +status: source-reviewed +summary: + statements: 57 + source_statements: 57 + core_items: 57 + blueprint_ready_statements: 57 + source_recovery_items: 19 + total_records: 76 + formalized: 57 + open: 0 + declarations: 361 + dependency_edges: 163 +scope_note: >- + The 57 source-facing items below have complete statements checked + against Carlet pages 77--110 and are synchronized with the current Chapter 6 + Blueprint. The 19 records under source_recovery retain complete + and incomplete cited families that have not been promoted to nodes. In + particular, the Kerdock parameter theorem is conditional on a given + representative family; only the separate finite-field construction states + that explicit representatives exist. The partial-bent nodes preserve the + exact punctured two-level definition, formalize its duality and corrected + type dichotomy, and replace two false printed consequences by explicit + counterexamples. Langevin's orphan theorem includes the necessary + non-affine hypothesis omitted in the source. +items: + - id: carlet-6-def-7-bent + kind: definition + location: >- + Definition 7 (Carlet, pp. 77--78) + statement: |- + Let n be even. A Boolean function + f:V_n\to\mathbb F_2 is bent when + + \operatorname{nl}(f)=2^{n-1}-2^{n/2-1}. + + Equivalently, |W_f(a)|=2^{n/2} for every a\in V_n, or the distance + from f to every affine function is 2^{n-1}\pm2^{n/2-1}. Bentness is + preserved by affine changes of variables and by addition of affine functions. + formal_status: formalized + declarations: + - CryptBoolean.natAbs_walshTransform_eq_two_pow_half_of_isBent + - CryptBoolean.maxWalshMagnitude_eq_two_pow_half_of_isBent + - CryptBoolean.nonlinearity_eq_two_pow_sub_two_pow_half_of_isBent + - CryptBoolean.isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half + - CryptBoolean.isBent_add_affineFunction_iff + - CryptBoolean.isBent_comp_affineEquiv_iff + - CryptBoolean.abs_hammingDistance_affine_sub_half_of_isBent + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-4-rel-36-covering-radius-bent + - carlet-4-nonlinearity-affine-invariance + - carlet-2-def-walsh-transform + - carlet-2-def-hamming-distance + + - id: carlet-6-lemma-2-walsh-congruence + kind: lemma + location: >- + Lemma 2 (Carlet, p. 77) + statement: |- + Let n\ge2 be even. A Boolean function + f:V_n\to\mathbb F_2 is bent if and only if + + W_f(a)\equiv 2^{n/2}\pmod {2^{n/2+1}} + \qquad(a\in V_n). + formal_status: formalized + declarations: + - CryptBoolean.isBent_iff_forall_walshTransform_modeq + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-7-bent + - carlet-2-parseval + + - id: carlet-6-theorem-8-perfect-nonlinearity + kind: theorem + location: >- + Theorem 8 (Carlet, p. 78) + statement: |- + A Boolean function f:V_n\to\mathbb F_2 + is bent if and only if every derivative in a nonzero direction is balanced: + + \forall a\in V_n\setminus\{0\},\qquad D_af\text{ is balanced}. + + Equivalently, f satisfies the propagation criterion of degree n. + formal_status: formalized + declarations: + - CryptBoolean.isBent_iff_forall_nonzero_derivative_isBalanced + - CryptBoolean.isBent_iff_satisfiesPropagationCriterion_dimension + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-7-bent + - carlet-2-rel-25-wiener-khinchin + - carlet-4-def-propagation-criteria + + - id: carlet-6-prop-16-support-code + kind: proposition + location: >- + Proposition 16 (Carlet, pp. 78--79; corrected dimension range) + statement: |- + Let + n\ge4 be even, let S_f=\{u_1,\ldots,u_w\} be the support of + f:V_n\to\mathbb F_2, and let + + C_f=\{(v\mathbin\cdot u_1,\ldots,v\mathbin\cdot u_w):v\in V_n\}. + + Then f is bent if and only if \dim C_f=n and the nonzero words of + C_f have exactly the two weights + + 2^{n-2}\quad\text{and}\quad w_H(f)-2^{n-2}, + + with both weights occurring. + formal_status: formalized + declarations: + - CryptBoolean.supportCodeMap + - CryptBoolean.supportCode + - CryptBoolean.supportCodewordWeight + - CryptBoolean.supportCodewordWeight_zero + - CryptBoolean.supportCodewordWeight_eq_card_filter + - CryptBoolean.codeCharacterSum_support_eq_card_sub_two_weight + - CryptBoolean.four_mul_supportCodewordWeight_eq + - CryptBoolean.SupportCodeHasExactlyTwoNonzeroWeights + - CryptBoolean.isBent_iff_supportCode_finrank_and_two_nonzero_weights + fidelity_note: >- + Carlet states positive even dimension, but in dimension two one displayed nonzero weight can be zero. The reviewed node therefore uses n >= 4 and records the exceptional failure explicitly. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-7-bent + - carlet-4-resiliency-support-dual-distance + - carlet-2-balanced-zero-walsh + - carlet-2-parseval + + - id: carlet-6-dual + kind: definition + location: >- + Bent dual (Carlet, Section 6.1, p. 79) + statement: |- + Let n be even and let + f:V_n\to\mathbb F_2 be bent. Its dual is the unique Boolean function + \widetilde f:V_n\to\mathbb F_2 satisfying + + W_f(u)=2^{n/2}(-1)^{\widetilde f(u)} + \qquad(u\in V_n). + + The function \widetilde f is bent and satisfies + + W_{\widetilde f}(a)=2^{n/2}(-1)^{f(a)}, + \qquad + \widetilde{\widetilde f}=f. + formal_status: formalized + declarations: + - CryptBoolean.bentDual + - CryptBoolean.walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + - CryptBoolean.realSignView_bentDual + - CryptBoolean.isBent_bentDual + - CryptBoolean.walshTransform_bentDual + - CryptBoolean.bentDual_bentDual + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-7-bent + - carlet-2-def-walsh-transform + - carlet-2-fourier-inversion + + - id: carlet-6-rel-44-dual-isometry + kind: theorem + location: >- + Relation (44) (Carlet, p. 79) + statement: |- + If f,g:V_n\to\mathbb F_2 are bent, + then + + W_{\widetilde f+\widetilde g}(0)=W_{f+g}(0). + + Consequently, + + d_H(\widetilde f,\widetilde g)=d_H(f,g), + + so duality preserves pairwise Hamming distance on bent functions. + formal_status: formalized + declarations: + - CryptBoolean.walshTransform_zero_bentDual_add + - CryptBoolean.hammingDistance_bentDual + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-dual + - carlet-2-rel-22-plancherel + - carlet-2-def-hamming-distance + + - id: carlet-6-rel-45-dual-derivatives + kind: theorem + location: >- + Relation (45) (Carlet, pp. 79--80) + statement: |- + Let f:V_n\to\mathbb F_2 be bent + and let a,b\in V_n. The function + + g(x)=f(x+b)+a\mathbin\cdot x + + is bent, and its dual is + + \widetilde g(x)=\widetilde f(x+a)+b\mathbin\cdot(x+a). + + Writing \ell_c(x)=c\mathbin\cdot x, one has + + W_{D_a\widetilde f+\ell_b}(0) + =W_{D_bf+\ell_a}(0). + formal_status: formalized + declarations: + - CryptBoolean.isBent_domainTranslate + - CryptBoolean.isBent_domainTranslate_add_linear + - CryptBoolean.bentDual_domainTranslate_add_linear + - CryptBoolean.walshTransform_zero_bentDual_derivative_add_linear + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-dual + - carlet-6-rel-44-dual-isometry + - carlet-2-prop-6-fourier-shifts + - carlet-2-def-2-derivative + + - id: carlet-6-dual-nnf + kind: theorem + location: >- + Numerical normal form of the dual (Carlet, pp. 79--80) + statement: |- + Let + f:V_n\to\mathbb F_2 be bent, and write its numerical normal form as + + f(x)=\sum_{S\subseteq[n]}\lambda_Sx^S. + + If \delta_0(x) is one at x=0 and zero elsewhere, then + + \widetilde f(x) + =\frac12-\frac{2^{n/2}}2\,\delta_0(x) + +\frac{(-1)^{w_H(x)}}{2^{n/2}} + \sum_{\operatorname{supp}(x)\subseteq S} + 2^{n-|S|}\lambda_S. + + This identity determines the numerical normal form of \widetilde f. + formal_status: formalized + declarations: + - CryptBoolean.booleanRealEmbedding_bentDual_eq_rawFourierTransform + - CryptBoolean.booleanRealEmbedding_bentDual_eq_numericalCoeff_sum + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-dual + - carlet-2-nnf-existence-uniqueness + - carlet-2-rel-30-nnf-fourier + + - id: carlet-6-prop-17-dual-nnf-divisibility + kind: proposition + location: >- + Proposition 17 (Carlet, p. 80) + statement: |- + Let f:V_n\to\mathbb F_2 be bent, + where n is even, and let \lambda_I and \widetilde\lambda_I be the + integer numerical-normal-form coefficients of f and \widetilde f. + For every proper subset I\subsetneq[n] with |I|>n/2, + + 2^{|I|-n/2}\mid\lambda_I, + \qquad + 2^{|I|-n/2}\mid\widetilde\lambda_I. + formal_status: formalized + declarations: + - CryptBoolean.bentDual_and_self_nnfCoefficient_divisibility + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-dual-nnf + - carlet-6-lemma-2-walsh-congruence + - carlet-2-prop-5-nnf-integrality + + - id: carlet-6-half-degree-anf-complement + kind: corollary + location: >- + Complementary half-degree ANF coefficients (Carlet, p. 81) + statement: |- + Let n\ge4, + let f:V_n\to\mathbb F_2 be bent, and let c_{f,I} denote the coefficient + of x^I in the ANF of f. For every I\subseteq[n] with |I|=n/2, + + c_{\widetilde f,I}=c_{f,[n]\setminus I}, + \qquad + c_{f,I}=c_{\widetilde f,[n]\setminus I}. + formal_status: formalized + declarations: + - CryptBoolean.anfCoeff_bentDual_eq_complement_of_card_eq_half + - CryptBoolean.anfCoeff_eq_bentDual_complement_of_card_eq_half + fidelity_note: >- + The first coefficient identity is the source consequence on p. 81; the second is its exact dual-symmetric counterpart obtained from involutivity, with no changed hypothesis. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-prop-17-dual-nnf-divisibility + - carlet-6-dual-nnf + - carlet-2-anf-existence-uniqueness + + - id: carlet-6-rel-46-dual-poisson + kind: theorem + location: >- + Relation (46) (Carlet, p. 81) + statement: |- + Let f:V_n\to\mathbb F_2 be bent, let + E\le V_n, and let a,b\in V_n. Then + + \sum_{x\in a+E}(-1)^{\widetilde f(x)+b\mathbin\cdot x} + =2^{-n/2}|E|(-1)^{a\mathbin\cdot b} + \sum_{x\in b+E^\perp}(-1)^{f(x)+a\mathbin\cdot x}. + formal_status: formalized + declarations: + - CryptBoolean.bentDual_poissonSummationFormula + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-dual + - carlet-2-cor-1-poisson-summation + + - id: carlet-6-quadratic-bent-characterization + kind: theorem + location: >- + Quadratic bent functions (Carlet, Section 6.2, pp. 80--81) + statement: |- + Let n\ge2 + be even and let f:V_n\to\mathbb F_2 have algebraic degree at most two. The + following conditions are equivalent: + + 1. f is bent; + 2. w_H(f)=2^{n-1}\pm2^{n/2-1}; + 3. the alternating polar form + + \phi_f(x,y)=f(0)+f(x)+f(y)+f(x+y) + + is nondegenerate, equivalently the linear kernel of f is \{0\}; + 4. the symmetric zero-diagonal coefficient matrix of the quadratic part of + f is nonsingular; + 5. after an invertible affine change of variables, f has the form + + x_1x_2+x_3x_4+\cdots+x_{n-1}x_n+\varepsilon + \qquad(\varepsilon\in\mathbb F_2). + formal_status: formalized + declarations: + - CryptBoolean.isBent_iff_quadraticRadical_eq_bot + - CryptBoolean.isBent_iff_linearKernel_eq_bot_of_degree_le_two + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-7-bent + - carlet-5-def-quadratic-symplectic-form + - carlet-5-theorem-5 + - carlet-5-quadratic-weight-nonlinearity-values + + - id: carlet-6-prop-18-rothaus-degree-bound + kind: proposition + location: >- + Proposition 18: Rothaus' bound (Carlet, p. 83) + statement: |- + Let n\ge4 be even. + Every bent function f:V_n\to\mathbb F_2 satisfies + + \deg_{\mathrm{alg}}(f)\le n/2, + \qquad + \deg_{\mathrm{alg}}(\widetilde f)\le n/2. + + In dimension n=2, every bent function, and hence its dual, has algebraic + degree exactly two. + formal_status: formalized + declarations: + - CryptBoolean.functionAlgebraicDegree_le_half_of_isBent + - CryptBoolean.functionAlgebraicDegree_eq_two_of_isBent + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-prop-17-dual-nnf-divisibility + - carlet-6-dual + - carlet-2-def-algebraic-degree + + - id: carlet-6-prop-19 + kind: proposition + location: >- + Proposition 19 (Carlet, Relation (47), p. 83) + statement: |- + Let n\ge2 be even, let + f:V_n\to\mathbb F_2 be bent, and put + + d=\deg_{\mathrm{alg}}(f), + \qquad + \widetilde d=\deg_{\mathrm{alg}}(\widetilde f). + + Then + + \frac n2-d + \ge + \frac{\frac n2-\widetilde d}{\widetilde d-1}. + formal_status: formalized + declarations: + - CryptBoolean.two_pow_ceilDiv_dvd_booleanCharacterSum_of_degree_le + - CryptBoolean.bentDual_functionAlgebraicDegree_relation + fidelity_note: >- + The positive even-dimension convention makes every displayed degree and denominator meaningful. The complete domains, hypotheses, normalization, and rational inequality match the reviewed source passage. + reuse_note: >- + The associated declarations formalize the McEliece--Ax character-sum divisibility exponent and compose it with the canonical bent dual, Poisson summation, and algebraic-degree APIs. + dependencies: + - carlet-6-rel-46-dual-poisson + - carlet-6-prop-18-rothaus-degree-bound + - carlet-6-dual + - carlet-2-anf-existence-uniqueness + + - id: carlet-6-maiorana-mcfarland + kind: theorem + location: >- + Maiorana--McFarland construction (Carlet, Relation (48), pp. 83--84) + statement: |- + For x,y\in V_m, let + + f(x,y)=x\mathbin\cdot\pi(y)+g(y), + + where g:V_m\to\mathbb F_2 is arbitrary. The function f is bent if + and only if \pi:V_m\to V_m is bijective. In that case + + \widetilde f(a,b)=b\mathbin\cdot\pi^{-1}(a)+g(\pi^{-1}(a)). + formal_status: formalized + declarations: + - CryptBoolean.isMaioranaMcFarland_of_eq_permutation + - CryptBoolean.walshTransform_maioranaMcFarlandPermutation + - CryptBoolean.isBent_of_maioranaMcFarlandPermutation + - CryptBoolean.bentDual_maioranaMcFarlandPermutation + - CryptBoolean.isBent_iff_bijective_maioranaMcFarland + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-7-bent + - carlet-5-def-maiorana-mcfarland + - carlet-5-affine-walsh-spectrum + + - id: carlet-6-prop-20-general-maiorana-mcfarland + kind: proposition + location: >- + Proposition 20 (Carlet, Relation (49), pp. 84--85) + statement: |- + Let n=r+s be + even with r\le s, let \varphi:V_s\to V_r, and put + + f_{\varphi,g}(x,y)=x\mathbin\cdot\varphi(y)+g(y). + + For every a\in V_r and b\in V_s, + + W_{f_{\varphi,g}}(a,b) + =2^r\sum_{y\in\varphi^{-1}(a)}(-1)^{g(y)+b\mathbin\cdot y}. + + If every fiber \varphi^{-1}(a) is an affine subspace of dimension + s-r and, when r- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-maiorana-mcfarland + - carlet-5-affine-flat-restriction-bound + - carlet-6-def-7-bent + + - id: carlet-6-partial-spread-construction + kind: theorem + location: >- + Dillon's partial-spread construction (Carlet, pp. 85--86) + statement: |- + Let n be + even with n/2\ge2, and let \mathcal P be a family of + n/2-dimensional subspaces of V_n such that distinct members meet only + at zero. If + + |\mathcal P|=2^{n/2-1}\quad\text{or}\quad + |\mathcal P|=2^{n/2-1}+1, + + then the sum over \mathbb F_2 of the indicators of the members of + \mathcal P is bent. Its dual is obtained by replacing every member by + its orthogonal complement in the corresponding exact partial-spread + expression. + formal_status: formalized + declarations: + - CryptBoolean.IsHalfDimensionalPartialSpread + - CryptBoolean.HasPartialSpreadBentCardinality + - CryptBoolean.partialSpreadFunction + - CryptBoolean.partialSpreadCoefficients + - CryptBoolean.bitValueInt_partialSpreadFunction_of_ne_zero + - CryptBoolean.partialSpreadFunction_zero + - CryptBoolean.hasExactGPSRepresentation_partialSpreadFunction + - CryptBoolean.isBent_partialSpreadFunction + fidelity_note: >- + The positive nondegenerate half-dimension convention makes the two cardinality cases and exact partial-spread expression total; the dual statement retains the same representation. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-theorem-12-geometric-characterization + + - id: carlet-6-direct-sum + kind: theorem + location: >- + Direct sum (Carlet, pp. 88--89) + statement: |- + If f:V_n\to\mathbb F_2 and + g:V_m\to\mathbb F_2 are bent, then + + h(x,y)=f(x)+g(y) + + is bent on V_{n+m}. Its spectrum and dual factor as + W_h(a,b)=W_f(a)W_g(b) and + \widetilde h(a,b)=\widetilde f(a)+\widetilde g(b). + formal_status: formalized + declarations: + - CryptBoolean.IsDecomposable + - CryptBoolean.isDecomposable_booleanDirectSum + - CryptBoolean.walshTransform_directSum + - CryptBoolean.isBent_booleanDirectSum + - CryptBoolean.bentDual_booleanDirectSum_append + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-7-bent + - carlet-6-dual + + - id: carlet-6-rothaus-construction + kind: theorem + location: >- + Dillon--Rothaus construction (Carlet, p. 89) + statement: |- + Let g,h,k, and + g+h+k be bent functions on V_n. Then the function on + \mathbb F_2^2\times V_n given by + + gh+gk+hk+(g+h)x_1+(g+k)x_2+x_1x_2 + + is bent. + formal_status: formalized + declarations: + - CryptBoolean.rothausConstruction + - CryptBoolean.rothausConstruction_append + - CryptBoolean.isBent_rothausConstruction + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-theorem-10-slice-construction + - carlet-6-cor-4-three-function-construction + + - id: carlet-6-theorem-9-flat-switching + kind: theorem + location: >- + Theorem 9 (Carlet, pp. 90--91) + statement: |- + Let f be bent on V_n, let + b+E be an affine flat, and put f^*=f+\mathbf1_{b+E}. Then f^* is + bent if and only if either of the following equivalent conditions holds: + + 1. for every a\notin E, the derivative D_af is balanced on b+E; + 2. on every coset of E^\perp, the restriction of + \widetilde f(x)+b\mathbin\cdot x is constant or balanced. + + If both f and f^* are bent, then \dim E\ge n/2 and the restriction + of f to b+E has algebraic degree at most + \dim E-n/2+1. Conversely, if \dim E=n/2 and that restriction is + affine, then f^* is bent. + formal_status: formalized + declarations: + - CryptBoolean.flatSwitch + - CryptBoolean.IsBalancedOnAffineFlat + - CryptBoolean.IsConstantOrBalancedOnAffineFlat + - CryptBoolean.affineFlatWalshSum + - CryptBoolean.walshTransform_sub_flatSwitch + - CryptBoolean.affineFlatWalshSum_eq_bitSignInt_mul_walshTransform_restriction + - CryptBoolean.affineSubspaceRestrictionImbalance_bentDual_add_linear + - CryptBoolean.abs_affineSubspaceRestrictionImbalance_bentDual_add_linear + - CryptBoolean.autocorrelation_flatSwitch + - CryptBoolean.isBent_flatSwitch_iff_derivative_balanced_on_affineFlat + - CryptBoolean.isBent_flatSwitch_iff_bentDual_add_linear_constant_or_balanced + - CryptBoolean.derivative_balanced_on_affineFlat_iff_bentDual_add_linear_constant_or_balanced + - CryptBoolean.two_pow_half_dvd_walshTransform_affineFlatRestriction + - CryptBoolean.half_dimension_le_finrank_of_isBent_flatSwitch + - CryptBoolean.functionAlgebraicDegree_affineFlatRestriction_le_of_isBent_flatSwitch + - CryptBoolean.isBent_flatSwitch_of_half_dimension_of_restriction_degree_le_one + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-theorem-8-perfect-nonlinearity + - carlet-6-rel-46-dual-poisson + - carlet-2-prop-11-walsh-divisibility + - carlet-3-prop-12 + + - id: carlet-6-theorem-10-slice-construction + kind: theorem + location: >- + Theorem 10 (Carlet, pp. 91--92) + statement: |- + Let n,m be even and let + f:V_n\times V_m\to\mathbb F_2. Suppose every slice + f_y(x)=f(x,y) is bent, and define \varphi_s(y)=\widetilde{f_y}(s). + Then f is bent if and only if every \varphi_s is bent. In that case + + \widetilde f(s,t)=\widetilde{\varphi_s}(t). + formal_status: formalized + declarations: + - CryptBoolean.firstBlockSlice + - CryptBoolean.dualSliceFunction + - CryptBoolean.walshTransform_eq_two_pow_half_mul_walshTransform_dualSliceFunction + - CryptBoolean.isBent_iff_forall_isBent_dualSliceFunction + - CryptBoolean.bentDual_append_eq_bentDual_dualSliceFunction + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-7-bent + - carlet-6-dual + + - id: carlet-6-indirect-sum + kind: theorem + location: >- + Indirect sum (Carlet, p. 92) + statement: |- + If f_1,f_2 are bent on V_n and + g_1,g_2 are bent on V_m, then + + h(x,y)=f_1(x)+g_1(y)+(f_1+f_2)(x)(g_1+g_2)(y) + + is bent. Its dual is obtained by applying the same formula to the four + duals. + formal_status: formalized + declarations: + - CryptBoolean.indirectSum + - CryptBoolean.indirectSum_append + - CryptBoolean.isBent_indirectSum + - CryptBoolean.bentDual_indirectSum_append + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-theorem-10-slice-construction + + - id: carlet-6-prop-21-permutation-reindexing + kind: proposition + location: >- + Proposition 21 (Carlet, pp. 93--94) + statement: |- + Let \sigma be a permutation of + V_n, with coordinate functions \sigma_1,\ldots,\sigma_n. If + + d_H\!\left(f,\sum_{i=1}^n a_i\sigma_i\right) + =2^{n-1}\pm2^{n/2-1} + \qquad(a\in V_n), + + then f\circ\sigma^{-1} is bent. + formal_status: formalized + declarations: + - CryptBoolean.hammingDistance_comp_perm + - CryptBoolean.hammingDistance_comp_perm_symm_linearFunction + - CryptBoolean.walshTransform_comp_perm_symm_eq_two_pow_sub_two_hammingDistance + - CryptBoolean.isBent_comp_perm_symm_of_hammingDistance + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-7-bent + - carlet-2-def-hamming-distance + + - id: carlet-6-prop-22-three-function-identity + kind: proposition + location: >- + Proposition 22 (Carlet, Relation (50), pp. 94--95) + statement: |- + For Boolean functions + f_1,f_2,f_3, put + + s_1=f_1+f_2+f_3, + \qquad + s_2=f_1f_2+f_1f_3+f_2f_3. + + As integer-valued functions, f_1+f_2+f_3=s_1+2s_2; consequently + + W_{f_1}+W_{f_2}+W_{f_3}=W_{s_1}+2W_{s_2}. + formal_status: formalized + declarations: + - CryptBoolean.threeFunctionSum + - CryptBoolean.threeFunctionPairwiseProductSum + - CryptBoolean.bitValueInt_threeFunctionIdentity + - CryptBoolean.rawFourierTransform_threeFunctionIdentity + - CryptBoolean.walshTransform_cast_eq_rawFourierTransform_sub_two_mul + - CryptBoolean.walshTransform_threeFunctionIdentity + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-2-pseudoboolean-fourier + - carlet-2-def-walsh-transform + + - id: carlet-6-cor-4-three-function-construction + kind: corollary + location: >- + Corollary 4 (Carlet, p. 95) + statement: |- + Suppose f_1,f_2,f_3 are bent. If + s_1=f_1+f_2+f_3 is bent and + \widetilde{s_1}=\widetilde f_1+\widetilde f_2+\widetilde f_3, then + s_2=f_1f_2+f_1f_3+f_2f_3 is bent and + + \widetilde{s_2} + =\widetilde f_1\widetilde f_2+ + \widetilde f_1\widetilde f_3+ + \widetilde f_2\widetilde f_3. + + Conversely, if 2^{n/2} divides every Walsh coefficient of s_2, then + s_1 is bent. + formal_status: formalized + declarations: + - CryptBoolean.isBent_threeFunctionPairwiseProductSum_and_bentDual_eq + - CryptBoolean.isBent_threeFunctionSum_of_two_pow_half_dvd_walshTransform + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-prop-22-three-function-identity + - carlet-6-lemma-2-walsh-congruence + - carlet-6-dual + + - id: carlet-6-theorem-11-hyperplane-restrictions + kind: theorem + location: >- + Theorem 11 (Carlet, pp. 95--96) + statement: |- + Let n\ge4 be even and let + f:V_n\to\mathbb F_2. For a linear hyperplane E, identify E and + its complementary coset with V_{n-1} and denote the two restrictions by + h_0,h_1. The following are equivalent: + + 1. f is bent; + 2. for every linear hyperplane, and equivalently for at least one linear + hyperplane, the transforms W_{h_0} and W_{h_1} take values in + \{0,\pm2^{n/2}\}, and at every frequency exactly one is nonzero. + formal_status: formalized + declarations: + - CryptBoolean.singletonF₂Cube + - CryptBoolean.singletonF₂Cube_apply + - CryptBoolean.walshTransform_append_singletonF₂Cube + - CryptBoolean.linearHyperplaneRestriction + - CryptBoolean.HasComplementaryHyperplaneRestrictionSpectra + - CryptBoolean.isBent_iff_hasComplementaryHyperplaneRestrictionSpectra + - CryptBoolean.hyperplaneExtension + - CryptBoolean.hyperplaneExtension_append_singletonF₂Cube + - CryptBoolean.linearHyperplaneRestriction_hyperplaneExtension_refl + - CryptBoolean.isBent_hyperplaneExtension_of_complementaryWalshSpectra + - CryptBoolean.isBent_iff_forall_hasComplementaryHyperplaneRestrictionSpectra + - CryptBoolean.isBent_iff_exists_hasComplementaryHyperplaneRestrictionSpectra + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-2-prop-9-restriction-square + - carlet-6-def-7-bent + + - id: carlet-6-hyperplane-restriction-plateaued + kind: corollary + location: >- + Hyperplane-restriction consequence (Carlet, p. 96) + statement: |- + Every restriction of + an n-variable bent function to an affine hyperplane, with n\ge4 even, + is plateaued on V_{n-1} with amplitude 2^{n/2} and has the optimal + odd-dimensional nonlinearity + + 2^{n-2}-2^{(n-2)/2}. + formal_status: formalized + declarations: + - CryptBoolean.hasPlateauedWalshAmplitude_linearHyperplaneRestriction_of_isBent + - CryptBoolean.isPlateaued_linearHyperplaneRestriction_of_isBent + - CryptBoolean.nonlinearity_linearHyperplaneRestriction_of_isBent + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-theorem-11-hyperplane-restrictions + - carlet-6-def-plateaued + - carlet-4-rel-35-nonlinearity-walsh + + - id: carlet-6-maiorana-mcfarland-count + kind: theorem + location: >- + Number of Maiorana--McFarland functions (Carlet, p. 97) + statement: |- + In dimension + n=2m, the original Maiorana--McFarland class contains exactly + + (2^m)!\,2^{2^m} + + distinct bent functions. + formal_status: formalized + declarations: + - CryptBoolean.MaioranaMcFarlandParameters + - CryptBoolean.booleanMaioranaMcFarlandPermutation + - CryptBoolean.booleanMaioranaMcFarlandPermutation_joinF₂CubeBlocks + - CryptBoolean.booleanMaioranaMcFarlandOfParameters + - CryptBoolean.booleanMaioranaMcFarlandOfParameters_injective + - CryptBoolean.card_maioranaMcFarlandParameters + - CryptBoolean.originalMaioranaMcFarlandClass + - CryptBoolean.card_originalMaioranaMcFarlandClass + - CryptBoolean.isBent_booleanMaioranaMcFarlandPermutation + - CryptBoolean.originalMaioranaMcFarlandClass_subset_bentFunctionFamily + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-maiorana-mcfarland + + - id: carlet-6-naive-bent-count-bound + kind: theorem + location: >- + Naive upper bound for the number of bent functions (Carlet, p. 97) + statement: |- + If + n\ge4 is even, then the number B_n of bent functions on V_n + satisfies + + B_n\le 2^{\sum_{i=0}^{n/2}\binom ni}. + formal_status: formalized + declarations: + - CryptBoolean.bentFunctionFamily + - CryptBoolean.mem_bentFunctionFamily_iff + - CryptBoolean.card_bentFunctionFamily_le_naiveBound + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-prop-18-rothaus-degree-bound + - carlet-3-reed-muller-dimension + + - id: carlet-6-prop-23-nnf-characterization + kind: proposition + location: >- + Proposition 23 (Carlet, p. 98) + statement: |- + Let n\ge2 be even, and let + f:V_n\to\mathbb F_2 have numerical normal form + + f(x)=\sum_{I\subseteq[n]}\lambda_Ix^I. + + Then f is bent if and only if both of the following conditions hold: + + 1. for every I\subseteq[n] with n/2<|I|- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-lemma-2-walsh-congruence + - carlet-2-rel-30-nnf-fourier + - carlet-2-prop-4-nnf-mobius + - carlet-2-prop-5-nnf-integrality + + - id: carlet-6-lemma-3-subspace-indicators + kind: lemma + location: >- + Lemma 3 (Carlet, p. 99) + statement: |- + Let n be even and let F\le V_n have + dimension d. There are n/2-dimensional subspaces + E_1,\ldots,E_k, integers m_1,\ldots,m_k, and an integer m such + that, pointwise on V_n, + + 2^{n/2-d}1_F\equiv m+\sum_{i=1}^k m_i1_{E_i} + \pmod {2^{n/2}} + \qquad(dn/2). + formal_status: formalized + declarations: + - CryptBoolean.linearSubspaceIndicatorInt + - CryptBoolean.halfSubspaceCombination + - CryptBoolean.ambientFunctionalKernel + - CryptBoolean.mem_ambientFunctionalKernel_iff + - CryptBoolean.finrank_ambientFunctionalKernel + - CryptBoolean.nonzeroDualFinset + - CryptBoolean.mem_nonzeroDualFinset + - CryptBoolean.card_nonzeroDualFinset + - CryptBoolean.functionalKernelCombination_modeq + - CryptBoolean.HasHalfSubspaceRepresentation + - CryptBoolean.hasHalfSubspaceRepresentation_indicator_of_finrank_eq + - CryptBoolean.hasHalfSubspaceRepresentation_indicator_of_half_le_finrank + - CryptBoolean.rankTwoIntermediateSubspace + - CryptBoolean.mem_rankTwoIntermediateSubspace_iff + - CryptBoolean.finrank_rankTwoIntermediateSubspace + - CryptBoolean.rankTwoSubspaceDiamond + - CryptBoolean.hasHalfSubspaceRepresentation_scaledIndicator_of_finrank_le_half + - CryptBoolean.carletLemma3 + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + This independent source lemma uses the existing finite-dimensional linear-subspace and indicator surfaces and introduces no parallel mathematical representation. + dependencies: [] + + - id: carlet-6-theorem-12-geometric-characterization + kind: theorem + location: >- + Theorem 12 (Carlet, Relation (51), p. 99) + statement: |- + Let n\ge2 be even. A + Boolean function f:V_n\to\mathbb F_2 is bent if and only if there are + n/2-dimensional subspaces E_1,\ldots,E_k\le V_n and integers + m_1,\ldots,m_k such that, for every x\in V_n, + + f(x)\equiv\sum_{i=1}^k m_i1_{E_i}(x)-2^{n/2-1}\delta_0(x) + \pmod {2^{n/2}}. + + If this congruence is an equality over the integers, then f belongs to + the generalized partial-spread class and its dual is + + \widetilde f(x)= + \sum_{i=1}^k m_i1_{E_i^\perp}(x)-2^{n/2-1}\delta_0(x). + + In particular, the dual also belongs to the generalized partial-spread + class. + formal_status: formalized + declarations: + - CryptBoolean.originIndicatorInt + - CryptBoolean.geometricBentExpression + - CryptBoolean.perpendicularGeometricBentExpression + - CryptBoolean.integerWalshTransform_linearSubspaceIndicatorInt + - CryptBoolean.integerWalshTransform_originIndicatorInt + - CryptBoolean.integerWalshTransform_bitValueInt_eq_booleanNNFFourierCoeffInt + - CryptBoolean.integerWalshTransform_halfSubspaceCombination + - CryptBoolean.integerWalshTransform_geometricBentExpression + - CryptBoolean.HasGeometricBentCongruence + - CryptBoolean.isBent_of_hasGeometricBentCongruence + - CryptBoolean.HasExactGPSRepresentation + - CryptBoolean.isBent_and_bitValueInt_bentDual_of_exactGPSRepresentation + - CryptBoolean.numericalMonomialInt + - CryptBoolean.numericalMonomialInt_cast + - CryptBoolean.numericalMonomialInt_eq_sum_coordinateZeroIndicators + - CryptBoolean.finrank_coordinateZeroSubspace + - CryptBoolean.linearSubspaceIndicatorInt_coordinateZeroSubspace_univ + - CryptBoolean.bitValueInt_eq_sum_booleanNumericalCoeffInt_mul_numericalMonomialInt + - CryptBoolean.hasGeometricBentCongruence_of_isBent + - CryptBoolean.isBent_iff_hasGeometricBentCongruence + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-prop-23-nnf-characterization + - carlet-6-lemma-3-subspace-indicators + - carlet-6-lemma-2-walsh-congruence + - carlet-2-prop-7-subspace-indicator + - carlet-6-dual + + - id: carlet-6-prop-24-second-order-characterization + kind: proposition + location: >- + Proposition 24 (Carlet, Relation (52), p. 100) + statement: |- + A Boolean function + f:V_n\to\mathbb F_2 is bent if and only if, for every x\in V_n, + + \sum_{a,b\in V_n}(-1)^{D_aD_bf(x)}=2^n. + + Equivalently, for the sign function f_\chi=(-1)^f, + + f_\chi\otimes f_\chi\otimes f_\chi=2^nf_\chi, + + or, at every u\in V_n, + + W_f(u)^3=2^nW_f(u). + formal_status: formalized + declarations: + - CryptBoolean.secondDerivativeDoubleSum + - CryptBoolean.rawTripleConvolution + - CryptBoolean.secondDerivativeDoubleSum_eq_mul_rawTripleConvolution + - CryptBoolean.rawFourierTransform_rawTripleConvolution + - CryptBoolean.rawFourierTransform_const_mul_realSignView + - CryptBoolean.eq_of_rawFourierTransform_eq + - CryptBoolean.isBent_iff_forall_secondDerivativeDoubleSum_eq_two_pow + - CryptBoolean.secondDerivativeDoubleSum_eq_two_pow_iff_rawTripleConvolution_eq + - CryptBoolean.isBent_iff_rawTripleConvolution_realSignView_eq + - CryptBoolean.isBent_iff_forall_walshTransform_cube_eq + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-theorem-8-perfect-nonlinearity + - carlet-4-autocorrelation-indicator-bounds + - carlet-4-second-derivative-sum + - carlet-2-def-convolution + - carlet-2-prop-8-convolution + - carlet-2-fourier-inversion + + - id: carlet-6-def-hyper-bent + kind: definition + location: >- + Hyper-bent functions (Carlet, pp. 100--101) + statement: |- + Let n be even and + f:\operatorname{GF}(2^n)\to\mathbb F_2. The function f is hyper-bent + when, for every integer i coprime to 2^n-1, every a in the field, + and both \varepsilon\in\mathbb F_2, its distance to + x\mapsto\operatorname{Tr}_n(ax^i)+\varepsilon is + 2^{n-1}\pm2^{n/2-1}. Equivalently, every function x\mapsto f(x^i) + is bent. In particular, every hyper-bent function is bent. + formal_status: formalized + declarations: + - CryptBoolean.fieldWalshTransform + - CryptBoolean.IsFieldBent + - CryptBoolean.fieldPowerReindex + - CryptBoolean.fieldPowerMap_bijective + - CryptBoolean.fieldPowerEquiv + - CryptBoolean.fieldPowerEquiv_apply + - CryptBoolean.fieldPowerReindex_eq_comp_fieldPowerEquiv + - CryptBoolean.IsHyperBent + - CryptBoolean.exists_fieldWalshTransform_eq_walshTransform + - CryptBoolean.exists_walshTransform_eq_fieldWalshTransform + - CryptBoolean.isFieldBent_iff_isBent_comp_linearEquiv + - CryptBoolean.IsHyperBent.isFieldBent + - CryptBoolean.isHyperBent_iff_forall_isBent_powerReindex_comp_linearEquiv + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-2-absolute-trace + - carlet-2-trace-pairing-coordinates + - carlet-6-def-7-bent + + - id: carlet-6-lemma-4-subfield-intersection + kind: lemma + location: >- + Lemma 4 (Carlet, p. 102; corrected dimension convention) + statement: |- + Let m>0, + let K=\operatorname{GF}(2^m) be the quadratic subfield of + L=\operatorname{GF}(2^{2m}), and let a,\omega\in L\setminus K. If + i is coprime to 2^{2m}-1, then there is a unique z\in K such that + + a(z+\omega)^i\in K. + formal_status: formalized + declarations: + - CryptBoolean.quadraticSubfieldBasisMap_bijective + - CryptBoolean.quadraticSubfieldBasisEquiv + - CryptBoolean.quadraticSubfieldBasisEquiv_apply + - CryptBoolean.existsUnique_subfield_power_intersection + fidelity_note: >- + Carlet writes n/2 while calling n positive. The node reparametrizes the claim as the quadratic extension GF(2^(2m))/GF(2^m), making the required even ambient dimension explicit. + reuse_note: >- + The finite-field proof constructs the quadratic-subfield coordinate equivalence and composes it with coprime power-map bijectivity to obtain the unique intersection point. + dependencies: + - carlet-6-def-hyper-bent + - carlet-2-absolute-trace + + - id: carlet-6-prop-25-psap-hyper-bent + kind: proposition + location: >- + Proposition 25 (Carlet, pp. 101--102) + statement: |- + Let m\ge2, put + K=\operatorname{GF}(2^m) and L=\operatorname{GF}(2^{2m}), choose + \omega\in L\setminus K, and write every x\in L uniquely as + x=y'+\omega y with y',y\in K. If g:K\to\mathbb F_2 is balanced + and g(0)=0, define + + f(y'+\omega y)=g(y'/y), + + with y'/y=0 when y=0. Then f is hyper-bent. Equivalently, every + function in Dillon's class PS_{ap} is hyper-bent. + formal_status: formalized + declarations: + - CryptBoolean.quadraticSubfield_powerMap_bijective + - CryptBoolean.pow_mem_quadraticSubfield_iff + - CryptBoolean.relativeTrace_eq_zero_iff_mem_quadraticSubfield + - CryptBoolean.absoluteTrace_mul_quadraticSubfield + - CryptBoolean.sum_bitSignInt_absoluteTrace_mul_eq_zero + - CryptBoolean.sum_quadraticSubfieldTraceCharacter_of_mem + - CryptBoolean.sum_quadraticSubfieldTraceCharacter_of_not_mem + - CryptBoolean.psapFunction + - CryptBoolean.psapFunction_coordinate + - CryptBoolean.sum_bitSignInt_field_eq_zero_of_balanced + - CryptBoolean.fieldPowerTraceTransform + - CryptBoolean.fieldPowerTraceTransform_psap_eq + - CryptBoolean.fieldPowerTraceTransform_psap_natAbs + - CryptBoolean.isHyperBent_of_forall_fieldPowerTraceTransform + - CryptBoolean.isHyperBent_psapFunction + fidelity_note: >- + The statement makes the positive, nondegenerate half-dimension and the quotient-at-zero convention explicit while preserving Dillon's PS_ap construction. + reuse_note: >- + The construction composes quadratic-subfield coordinates, the unique power-map intersection, relative and absolute trace identities, balanced character sums, and the finite-field Walsh criterion for hyper-bentness. + dependencies: + - carlet-6-def-hyper-bent + - carlet-6-lemma-4-subfield-intersection + - carlet-6-partial-spread-construction + - carlet-5-quadratic-trace-representation + + - id: carlet-6-prop-26-partially-bent + kind: proposition + location: >- + Proposition 26 (Carlet, Relation (53), pp. 103--104) + statement: |- + For a Boolean + function f:V_n\to\mathbb F_2, let + + N_{\Delta_f}=|\{b:\Delta_f(b)\ne0\}|, + \qquad + N_{W_f}=|\{u:W_f(u)\ne0\}|. + + Then N_{\Delta_f}N_{W_f}\ge2^n. Equality holds if and only if every + derivative D_bf is balanced or constant. Equivalently, there are + complementary subspaces E,E' and functions g,h, with g bent on + E and h affine on E', such that + + f(x+y)=g(x)+h(y) + \qquad(x\in E,\ y\in E'). + + Such functions are called partially bent. Every quadratic function is + partially bent, and every partially bent function is plateaued. + formal_status: formalized + declarations: + - CryptBoolean.autocorrelationSupport + - CryptBoolean.mem_autocorrelationSupport + - CryptBoolean.nonzeroAutocorrelationCount + - CryptBoolean.rawFourierSupport_autocorrelation + - CryptBoolean.two_pow_le_nonzeroAutocorrelationCount_mul_card_walshSupport + - CryptBoolean.IsPartiallyBent + - CryptBoolean.isPartiallyBent_of_functionAlgebraicDegree_le_two + - CryptBoolean.HasBentAffineComplementDecomposition + - CryptBoolean.HasBentAffineComplementDecomposition.isPartiallyBent + - CryptBoolean.HasBentAffineComplementDecomposition.linearKernel_eq_affineSubspace + - CryptBoolean.HasBentAffineComplementDecomposition.dimensions_add + - CryptBoolean.HasBentAffineComplementDecomposition.even_bentDimension + - CryptBoolean.exists_hasBentAffineComplementDecomposition_of_isPartiallyBent + - CryptBoolean.isPartiallyBent_iff_exists_bentAffineComplementDecomposition + - CryptBoolean.isLinearStructure_iff_abs_autocorrelation_eq_two_pow + - CryptBoolean.isPartiallyBent_of_nonzeroAutocorrelationCount_mul_card_walshSupport_eq + - CryptBoolean.nonzeroAutocorrelationCount_mul_card_walshSupport_eq_of_isPartiallyBent + - CryptBoolean.nonzeroAutocorrelationCount_mul_card_walshSupport_eq_two_pow_iff + - CryptBoolean.HasBentAffineComplementDecomposition.nonzeroAutocorrelationCount_eq + - CryptBoolean.hasPlateauedWalshSpectrum_of_isPartiallyBent + - CryptBoolean.IsPartiallyBent.isPlateaued + - CryptBoolean.isPlateaued_of_functionAlgebraicDegree_le_two + - CryptBoolean.HasBentAffineComplementDecomposition.hasPlateauedWalshAmplitude + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-2-rel-25-wiener-khinchin + - carlet-2-parseval + - carlet-4-def-linear-kernel + - carlet-6-def-plateaued + + - id: carlet-6-prop-27-fourier-uncertainty + kind: proposition + location: >- + Proposition 27 (Carlet, pp. 104--105) + statement: |- + Let + \varphi:V_n\to\mathbb R be nonzero, and write + + N_\varphi=|\{x:\varphi(x)\ne0\}|, + \qquad + N_{\widehat\varphi}=|\{u:\widehat\varphi(u)\ne0\}|. + + Then N_\varphi N_{\widehat\varphi}\ge2^n. Equality holds if and only if + there are a nonzero real number \lambda, a frequency u, and an affine + flat F such that + + \varphi(x)= + \begin{cases} + \lambda(-1)^{u\mathbin\cdot x},&x\in F,\\ + 0,&x\notin F. + \end{cases} + formal_status: formalized + declarations: + - CryptBoolean.pseudoBooleanSupport + - CryptBoolean.mem_pseudoBooleanSupport + - CryptBoolean.two_pow_le_card_pseudoBooleanSupport_mul_card_rawFourierSupport + - CryptBoolean.IsModulatedAffineFlatIndicator + - CryptBoolean.IsModulatedAffineFlatIndicator.card_support_mul_card_rawFourierSupport_eq + - CryptBoolean.isModulatedAffineFlatIndicator_of_card_support_mul_card_rawFourierSupport_eq + - CryptBoolean.card_support_mul_card_rawFourierSupport_eq_two_pow_iff + fidelity_note: >- + Because the pseudo-Boolean input is nonzero, the equality-case modulation scalar must be nonzero; the reviewed statement records this necessary condition explicitly. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-2-pseudoboolean-fourier + - carlet-2-parseval + - carlet-2-cor-1-poisson-summation + + - id: carlet-6-def-partial-bent + kind: definition + location: >- + Partial bent functions (Carlet, p. 105) + statement: |- + Let n be even. A Boolean + function f:V_n\to\mathbb F_2 is partial bent if there is an integer + \lambda such that, on V_n\setminus\{0\}, its raw Fourier transform as + a \{0,1\}-valued function takes exactly the two values \lambda and + \lambda+2^{n/2}. + formal_status: formalized + declarations: + - CryptBoolean.HasPartialBentFourierLevels + - CryptBoolean.IsPartialBent + - CryptBoolean.partialBentIntegerFourier + - CryptBoolean.partialBentIntegerFourier_cast + fidelity_note: >- + The level is integral because the raw Fourier transform of a zero-one-valued Boolean function is integer-valued; equality of the punctured spectral range records that both displayed values occur. + reuse_note: >- + The definition is expressed directly through the canonical raw pseudo-Boolean Fourier transform and remains distinct from the derivative-based IsPartiallyBent predicate. + dependencies: + - carlet-2-pseudoboolean-fourier + + - id: carlet-6-partial-bent-duality + kind: theorem + location: >- + Duality for partial bent functions (Carlet, p. 105) + statement: |- + Let f be partial + bent with Fourier levels \lambda and \lambda+2^{n/2}. Define its dual + at zero by \widetilde f(0)=f(0) and, for every nonzero u, by + + \widetilde f(u)= + \begin{cases} + 0,&\widehat f(u)=\lambda,\\ + 1,&\widehat f(u)=\lambda+2^{n/2}. + \end{cases} + + Then \widetilde f is partial bent and \widetilde{\widetilde f}=f. + formal_status: formalized + declarations: + - CryptBoolean.partialBentDual + - CryptBoolean.partialBentDual_zero + - CryptBoolean.exists_partialBentDual_fourierLevels + - CryptBoolean.partialBentDual_involution + - CryptBoolean.exists_isPartialBent_partialBentDual_and_involution + fidelity_note: >- + Carlet gives the two branches on the punctured frequency space. The statement adopts the formal convention \widetilde f(0)=f(0), verified to make the dual a total Boolean function and the involution claim well-formed. + reuse_note: >- + The integral transform adapter composes raw Fourier involution with the punctured spectral branch definition; the resulting dual-level theorem proves both closure and involution without reusing the differently normalized bent dual. + dependencies: + - carlet-6-def-partial-bent + - carlet-2-cor-2-fourier-involution + + - id: carlet-6-partial-bent-degree-bound + kind: theorem + location: >- + Counterexample to the printed partial-bent degree bound (Carlet, p. 105) + statement: |- + On V_2, let f be the indicator of the point (1,0). Then f is + partial bent, but + + \deg_{\mathrm{alg}}(f)=2>2/2. + + Thus the printed half-dimension bound requires additional regularity + hypotheses beyond the exact punctured two-level definition. + formal_status: formalized + declarations: + - CryptBoolean.partialBentDegreeCounterexample + - CryptBoolean.partialBentDegreeCounterexample_refutes_bound + fidelity_note: >- + This is a formal counterexample to the literal printed assertion under the exact-two-level definition. The singleton indicator on V_2 has punctured levels -1 and 1 but algebraic degree two; the footnote identifying partial bent functions with partial difference sets indicates an omitted nontriviality or regularity convention. + reuse_note: >- + The explicit two-variable indicator composes the canonical partial-bent predicate with FABL's top-degree support-parity characterization to certify the strict failure of the printed bound. + dependencies: + - carlet-6-def-partial-bent + - carlet-6-prop-18-rothaus-degree-bound + + - id: carlet-6-partial-bent-types + kind: theorem + location: >- + The two types of partial bent functions (Carlet, p. 105) + statement: |- + Let n>0 be even, put q=2^{n/2} and e=f(0), and let f be partial + bent with Fourier levels \lambda and \lambda+q. Exactly one of the + two identities + + \widehat f(0)-e=-(\lambda-e)(q-1) + + and + + \widehat f(0)-e=(q+\lambda-e)(q+1) + + holds; these alternatives define the two types. + formal_status: formalized + declarations: + - CryptBoolean.partialBent_fourier_level_types + fidelity_note: >- + This deliberately corrects the printed type formulas. For the punctured spectrum and e=f(0), Parseval gives -(\lambda-e)(q-1) or (q+\lambda-e)(q+1); Carlet's second displayed factor q-\lambda fails even for f(0)=0, while omitting e fails when f(0)=1. + reuse_note: >- + Parseval and the integral Fourier adapter reduce the punctured two-level multiplicities to the corrected mutually exclusive integer dichotomy. + dependencies: + - carlet-6-def-partial-bent + - carlet-2-parseval + + - id: carlet-6-partial-bent-disjoint-support-sum + kind: theorem + location: >- + Counterexample to the printed partial-bent sum assertion (Carlet, p. 105) + statement: |- + On V_2, let f be the indicator of \{(1,0)\} and let g(x)=x_2, + the indicator of \{(0,1),(1,1)\}. Their punctured Fourier levels are + \{-1,1\} and \{-2,0\}, respectively. Both functions are partial bent + of the corrected first type, and + + \operatorname{supp}(f)\cap\operatorname{supp}(g)\subseteq\{0\}. + + Nevertheless, f+g is not partial bent. Hence the printed closure assertion + also requires an additional regularity convention. + formal_status: formalized + declarations: + - CryptBoolean.partialBentSumCounterexampleCompanion + - CryptBoolean.partialBentCounterexamples_refute_disjoint_support_sum + fidelity_note: >- + This is a formal counterexample to the literal printed assertion under the exact-two-level definition. The two functions have disjoint supports and both satisfy the corrected first-type identity, but their sum has only one punctured Fourier level. The partial-difference-set reading therefore needs an omitted regularity convention. + reuse_note: >- + The two explicit functions compose the integral Fourier adapter, the corrected first-type identity, exact support computation, and the canonical partial-bent predicate to certify failure of closure. + dependencies: + - carlet-6-def-partial-bent + - carlet-6-partial-bent-types + - carlet-2-pseudoboolean-fourier + + - id: carlet-6-def-plateaued + kind: definition + location: >- + Plateaued functions (Carlet, pp. 105--106) + statement: |- + A Boolean function is + plateaued with amplitude \lambda>0 when every Walsh coefficient belongs + to \{0,\lambda,-\lambda\}. A plateaued function is bent exactly when + its Walsh transform has full support. Parseval's identity forces + \lambda=2^r with 2r\ge n; consequently every Walsh coefficient is + divisible by 2^{\lceil n/2\rceil}. + formal_status: formalized + declarations: + - CryptBoolean.HasPlateauedWalshAmplitude + - CryptBoolean.IsPlateaued + - CryptBoolean.isPlateaued_iff_hasPlateauedWalshSpectrum + - CryptBoolean.isBent_iff_isPlateaued_and_forall_walshTransform_ne_zero + - CryptBoolean.card_walshSupport_mul_amplitude_sq_eq_two_pow_two_mul + - CryptBoolean.exists_plateauedAmplitudeExponent + - CryptBoolean.two_pow_add_one_div_two_dvd_walshTransform_of_hasPlateauedWalshAmplitude + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-2-def-walsh-transform + - carlet-2-parseval + - carlet-6-def-7-bent + + - id: carlet-6-plateaued-support-nonlinearity + kind: theorem + location: >- + Walsh-support bound (Carlet, p. 106) + statement: |- + If N_{W_f} is the cardinality + of the Walsh support of f:V_n\to\mathbb F_2, then + + \operatorname{nl}(f) + \le 2^{n-1}\left(1-\frac1{\sqrt{N_{W_f}}}\right). + + Equality holds if and only if f is plateaued. + formal_status: formalized + declarations: + - CryptBoolean.maxWalshMagnitude_eq_of_hasPlateauedWalshAmplitude + - CryptBoolean.sum_walshTransform_sq_walshSupport + - CryptBoolean.two_pow_sq_le_card_walshSupport_mul_maxWalshMagnitude_sq + - CryptBoolean.two_pow_sq_eq_card_walshSupport_mul_maxWalshMagnitude_sq_iff_plateaued + - CryptBoolean.nonlinearity_cast_le_walshSupport_bound + - CryptBoolean.nonlinearity_cast_eq_walshSupport_bound_iff_plateaued + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-plateaued + - carlet-4-rel-35-nonlinearity-walsh + - carlet-2-parseval + + - id: carlet-6-prop-28-second-order-plateaued + kind: proposition + location: >- + Proposition 28 (Carlet, Relation (55), p. 106) + statement: |- + A Boolean function + f:V_n\to\mathbb F_2 is plateaued if and only if there is a positive + integer \lambda such that, for every x\in V_n, + + \sum_{a,b\in V_n}(-1)^{D_aD_bf(x)}=\lambda^2. + + The integer \lambda is the Walsh amplitude. + formal_status: formalized + declarations: + - CryptBoolean.hasPlateauedWalshAmplitude_iff_forall_walshTransform_cube_eq + - CryptBoolean.isPlateaued_iff_exists_forall_secondDerivativeDoubleSum_eq_sq + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-plateaued + - carlet-6-prop-24-second-order-characterization + + - id: carlet-6-plateaued-coset-orphan + kind: theorem + location: >- + Langevin's orphan theorem (Carlet, p. 106) + statement: |- + Order the cosets of + R(1,n) as follows: g+R(1,n) is below f+R(1,n) when there are + minimum-weight representatives g_1 and f_1 of the respective cosets + such that \operatorname{supp}(g_1)\subseteq\operatorname{supp}(f_1). + A maximal coset for this order is called an orphan. If f is plateaued and + f\notin R(1,n), then f+R(1,n) is an orphan. The non-affine hypothesis + is necessary: affine functions are plateaued, while R(1,n) is the least + coset in this order. + formal_status: formalized + declarations: + - CryptBoolean.IsFirstOrderCosetLeader + - CryptBoolean.FirstOrderCosetBelow + - CryptBoolean.IsFirstOrderOrphan + - CryptBoolean.IsPlateaued.add_affineFunction + - CryptBoolean.eq_of_plateaued_cosetLeaders_of_support_subset + - CryptBoolean.isFirstOrderOrphan_of_isPlateaued + fidelity_note: >- + This deliberately corrects the source's missing non-affine hypothesis: an affine function is plateaued, but its first-order Reed--Muller coset has the empty minimum-weight support and is least rather than maximal. + reuse_note: >- + The support order is represented directly on first-order Reed--Muller cosets, and the maximality theorem composes affine invariance, coset-leader normalization, Parseval, and the plateaued Walsh-support identity. + dependencies: + - carlet-6-def-plateaued + - carlet-6-plateaued-support-nonlinearity + - carlet-3-reed-muller-code + - carlet-4-def-nonlinearity + - carlet-2-parseval + + - id: carlet-6-def-8-normal-extension + kind: definition + location: >- + Normal extension (Carlet, Definition 8, pp. 107--108) + statement: |- + Let + \beta:V_k\to\mathbb F_2 and f:V_n\to\mathbb F_2 be bent. Write + \beta\preccurlyeq f when there are a nonnegative integer m and a + linear isomorphism + + L:V_k\times V_m\times V_m\longrightarrow V_n + + such that + + f\bigl(L(u,w,0)\bigr)=\beta(u) + \qquad(u\in V_k,\ w\in V_m). + + Equivalently, V_n=U\oplus W_1\oplus W_2 with + \dim W_1=\dim W_2, and the restriction of f to + U\oplus W_1 is \beta pulled back from U. Every bent function is + a normal extension of itself. + formal_status: formalized + declarations: + - CryptBoolean.IsNormalExtension + - CryptBoolean.IsNormalExtension.isBent_left + - CryptBoolean.IsNormalExtension.isBent_right + - CryptBoolean.isNormalExtension_refl + fidelity_note: >- + The coordinate-invariant linear-isomorphism form is equivalent to Carlet's direct decomposition V=U+W_1+W_2 with equal complementary dimensions. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-7-bent + + - id: carlet-6-normal-extension-composition-duality + kind: theorem + location: >- + Composition and duality of normal extensions (Carlet, p. 108) + statement: |- + The + relation \preccurlyeq is transitive. Moreover, if + \beta\preccurlyeq f, then + + \widetilde\beta\preccurlyeq\widetilde f. + + In standard coordinates, duality exchanges the two equal complementary + summands. + formal_status: formalized + declarations: + - CryptBoolean.walshAdjointLinearEquiv + - CryptBoolean.walshTransform_comp_linearEquiv + - CryptBoolean.bentDual_comp_linearEquiv + - CryptBoolean.bentDual_canonical_normalExtension + - CryptBoolean.IsNormalExtension.trans + - CryptBoolean.IsNormalExtension.bentDual + fidelity_note: >- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-8-normal-extension + - carlet-6-dual + - carlet-6-rel-46-dual-poisson + + - id: carlet-6-normal-zero-dimensional-characterization + kind: theorem + location: >- + Zero-dimensional normal extensions (Carlet, p. 108; corrected normality convention) + statement: |- + Let f:V_n\to\mathbb F_2 be bent. If normality means that + f is constant on an n/2-dimensional linear subspace, then + + f\text{ is normal} + \quad\Longleftrightarrow\quad + \varepsilon\preccurlyeq f + \text{ for some }\varepsilon\in\mathbb F_2. + + For the affine-flat convention of Definition 4, the exact statement is + instead + + f\text{ is }(n/2)\text{-normal} + \quad\Longleftrightarrow\quad + \varepsilon\preccurlyeq(f\circ A) + + for some \varepsilon\in\mathbb F_2 and some affine automorphism A + of V_n. + + The affine automorphism cannot in general be omitted. The two-variable + function + + f(x_1,x_2)=(x_1+1)(x_2+1) + + is bent and constant on a one-dimensional affine flat, but it is not + constant on any one-dimensional linear subspace. + formal_status: formalized + declarations: + - CryptBoolean.zeroDimensionalBooleanFunction + - CryptBoolean.zeroDimensionalBooleanFunction_apply + - CryptBoolean.isBent_zeroDimensionalBooleanFunction + - CryptBoolean.IsSubspaceNormal + - CryptBoolean.IsAffineNormalExtension + - CryptBoolean.isKNormal_comp_affineEquiv_iff + - CryptBoolean.exists_isNormalExtension_zeroDimensional_iff_isSubspaceNormal + - CryptBoolean.exists_isAffineNormalExtension_zeroDimensional_iff_isKNormal + - CryptBoolean.exists_isKNormal_not_isNormalExtension_zeroDimensional + fidelity_note: >- + Carlet's zero-dimensional sentence is exact for constancy on a linear half-dimensional subspace. Under Chapter 5's affine-flat definition of normality an affine automorphism is necessary; the two-variable counterexample records the correction. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-8-normal-extension + - carlet-5-def-4-normality + - carlet-2-affine-invariance + + - id: carlet-6-prop-29-direct-sum-normality + kind: proposition + location: >- + Proposition 29 (Carlet, p. 108) + statement: |- + Let + f_i:V_i\to\mathbb F_2 be bent for i=1,2. The direct sum + f_1\oplus f_2 is normal if and only if there are bent functions + \beta_i such that \beta_i\preccurlyeq f_i for i=1,2 and either + \beta_1 is linearly equivalent to \beta_2, or \beta_1 is linearly + equivalent to \beta_2+1. + formal_status: formalized + declarations: + - CryptBoolean.AreLinearlyEquivalentOrComplementary + - CryptBoolean.isSubspaceNormal_booleanDirectSum_iff + fidelity_note: >- + The statement follows Carlet's linear-subspace normality convention and does not silently replace linear equivalence by affine equivalence. + reuse_note: >- + The classification composes the canonical direct-sum construction, normal-extension coordinates, and the affine-flat restriction equality case; the paired linear-equivalence-or-complement relation records precisely the two constant values. + dependencies: + - carlet-6-direct-sum + - carlet-6-def-8-normal-extension + - carlet-6-normal-zero-dimensional-characterization + - carlet-5-affine-flat-restriction-bound + + - id: carlet-6-prop-30-normality-descends + kind: proposition + location: >- + Proposition 30 (Carlet, p. 108) + statement: |- + If \beta\preccurlyeq f and the bent + function f is normal, then the bent function \beta is normal. + formal_status: formalized + declarations: + - CryptBoolean.isSubspaceNormal_comp_linearEquiv_iff + - CryptBoolean.IsNormalExtension.isSubspaceNormal_left + fidelity_note: >- + The statement follows Carlet's linear-subspace normality convention and retains descent from a genuine normal extension. + reuse_note: >- + The production proof transports normality across a linear equivalence and then descends it through the normal-extension relation. + dependencies: + - carlet-6-def-8-normal-extension + - carlet-6-normal-zero-dimensional-characterization + - carlet-6-prop-31-normal-extension-replacement + - carlet-5-affine-flat-restriction-bound + + - id: carlet-6-prop-31-normal-extension-replacement + kind: proposition + location: >- + Proposition 31 (Carlet, p. 108) + statement: |- + Let \beta be bent on U, let + f be bent on U\times W\times W, and suppose + \beta\preccurlyeq f through + + f(x,y,0)=\beta(x). + + For any bent \beta':U\to\mathbb F_2, define + + f'(x,y,z)= + \begin{cases} + \beta'(x),&z=0,\\ + f(x,y,z),&z\ne0. + \end{cases} + + Then f' is bent and \beta'\preccurlyeq f'. + formal_status: formalized + declarations: + - CryptBoolean.canonicalNormalExtensionReplacement + - CryptBoolean.canonicalNormalExtensionReplacement_apply_append + - CryptBoolean.isBent_canonicalNormalExtensionReplacement + - CryptBoolean.normalExtensionReplacement + - CryptBoolean.normalExtensionReplacement_apply + - CryptBoolean.normalExtensionReplacement_isNormalExtension + fidelity_note: >- + The coordinate presentation is equivalent to Carlet's direct-sum formulation and preserves both bentness and the normal-extension relation. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-def-8-normal-extension + - carlet-6-normal-extension-composition-duality + - carlet-6-rel-46-dual-poisson + + - id: carlet-6-rel-56-complete-quadratic + kind: theorem + location: >- + Relation (56) (Carlet, pp. 109--110) + statement: |- + Define the complete quadratic + function on V_n by + + q_n(x)=\sum_{1\le i- + The complete domains, hypotheses, normalization, and conclusion match the reviewed source passage. + reuse_note: >- + The associated declarations compose the canonical statements listed under dependencies and introduce no parallel definition or normalization. + dependencies: + - carlet-6-quadratic-bent-characterization + - carlet-2-def-support-weight + + - id: carlet-6-kerdock-parameters + kind: theorem + location: >- + Kerdock parameters (Carlet, pp. 109--110) + statement: |- + Let n\ge2 be even and + let F be a family of 2^{n-1} Boolean functions on V_n containing + zero. Suppose that every nonzero member of F has algebraic degree two + and that f+g is bent whenever f,g\in F are distinct. Then + + K(F)=\bigcup_{f\in F}\bigl(f+R(1,n)\bigr) + + contains R(1,n), is contained in R(2,n), has 2^{2n} words, and + has minimum distance + 2^{n-1}-2^{n/2-1}. The first-order Reed--Muller cosets in this union + are pairwise distinct. + formal_status: formalized + declarations: + - CryptBoolean.IsKerdockRepresentativeFamily + - CryptBoolean.kerdockCodeOfRepresentatives + - CryptBoolean.functionAlgebraicDegree_le_two_of_mem_kerdockRepresentatives + - CryptBoolean.reedMuller_one_subset_kerdockCodeOfRepresentatives + - CryptBoolean.kerdockCodeOfRepresentatives_subset_reedMuller_two + - CryptBoolean.nonlinearity_add_eq_kerdockDistance_of_mem + - CryptBoolean.hasDistinctFirstOrderCosets_of_isKerdockRepresentativeFamily + - CryptBoolean.kerdockRepresentativeFamily_offDiag_nonempty + - CryptBoolean.card_kerdockCodeOfRepresentatives + - CryptBoolean.minimumPairNonlinearity_eq_kerdockDistance + - CryptBoolean.minimumHammingDistance_kerdockCodeOfRepresentatives + - CryptBoolean.kerdockCodeOfRepresentatives_parameters + fidelity_note: >- + This is a conditional reduction: a representative family F is an input hypothesis. It proves the code parameters from that hypothesis and does not assert that such a family exists; existence belongs only to the separate field-construction node. + reuse_note: >- + The proof composes bent pairwise differences with the existing Reed--Muller code and coset-distance results while leaving representative-family construction external. + dependencies: + - carlet-6-def-7-bent + - carlet-3-reed-muller-code + - carlet-4-reed-muller-coset-distance + + - id: carlet-6-kerdock-field-trace-identity + kind: theorem + location: >- + Self-dual normal-basis trace identity (Carlet, pp. 109--110) + statement: |- + Let + m=2t+1 and identify V_m with \mathbb F_{2^m} through a self-dual + normal basis. Explicitly, assume that the coordinate equivalence + intertwines Frobenius squaring with cyclic rotation, identifies the + absolute trace with the coordinate sum, and identifies the trace pairing + with the standard binary dot product. Under the induced identification + V_{m+1}\simeq\mathbb F_{2^m}\times\mathbb F_2, the complete quadratic + function of Relation (56) is + + q(x,z)=\operatorname{Tr}_m\!\left(\sum_{j=1}^{t}x^{2^j+1}\right) + +z\operatorname{Tr}_m(x). + formal_status: formalized + declarations: + - CryptBoolean.completeQuadraticBit_eq_kerdockFieldRepresentative_one_of_selfDualNormalCoordinates + fidelity_note: >- + The formal theorem unpacks the self-dual normal-basis condition into its + cyclic Frobenius, coordinate-trace, and self-dual trace-pairing equations; + under these explicit hypotheses its domain and conclusion match Carlet's + conditional coordinate identity. + reuse_note: >- + The proof composes the canonical complete quadratic polar form, the + finite-field Kerdock trace quadratic, and the existing affine-difference + criterion without introducing a second normalization. + dependencies: + - carlet-6-rel-56-complete-quadratic + - carlet-2-absolute-trace + - carlet-6-kerdock-field-construction + + - id: carlet-6-kerdock-field-construction + kind: theorem + location: >- + Finite-field construction of the Kerdock code (Carlet, pp. 109--110) + statement: |- + Let m=2t+1, set n=m+1, and define + + q(x,z)=\operatorname{Tr}_m\!\left(\sum_{j=1}^{t}x^{2^j+1}\right) + +z\operatorname{Tr}_m(x) + + on \mathbb F_{2^m}\times\mathbb F_2. For + u\in\mathbb F_{2^m}, set q_u(x,z)=q(ux,z) and transport these + functions to V_n along an \mathbb F_2-linear coordinate + identification. The representative q_0 is zero, every q_u with + u\ne0 has algebraic degree two, and q_u+q_v is bent whenever + u\ne v. Thus the 2^m representatives form a Kerdock representative + family. Consequently the union of the cosets q_u+R(1,n) is a Kerdock + code with 2^{2n} words and minimum distance + 2^{n-1}-2^{n/2-1}. + formal_status: formalized + declarations: + - CryptBoolean.kerdockTraceQuadratic + - CryptBoolean.kerdockFieldQuadratic + - CryptBoolean.absoluteTrace_algebraMap_odd + - CryptBoolean.kerdockTraceCube + - CryptBoolean.kerdockTraceLinearCube + - CryptBoolean.functionAlgebraicDegree_kerdockTraceCube_le_two + - CryptBoolean.functionAlgebraicDegree_kerdockTraceLinearCube_le_one + - CryptBoolean.kerdockFieldCoordinateEquiv + - CryptBoolean.kerdockFieldRepresentative + - CryptBoolean.kerdockFieldRepresentative_coordinate + - CryptBoolean.kerdockFieldRepresentative_zero + - CryptBoolean.functionAlgebraicDegree_kerdockFieldRepresentative_le_two + - CryptBoolean.quadraticPolarKernel_kerdockFieldRepresentative + - CryptBoolean.quadraticPolarKernel_kerdockFieldRepresentative_add + - CryptBoolean.eq_zero_of_forall_quadraticPolarKernel_kerdockFieldRepresentative_add + - CryptBoolean.isBent_kerdockFieldRepresentative_add + - CryptBoolean.functionAlgebraicDegree_kerdockFieldRepresentative_eq_two + - CryptBoolean.kerdockFieldRepresentative_injective + - CryptBoolean.kerdockFieldRepresentativeFamily + - CryptBoolean.card_kerdockFieldRepresentativeFamily + - CryptBoolean.isKerdockRepresentativeFamily_kerdockField + - CryptBoolean.kerdockFieldConstruction_parameters + fidelity_note: >- + The construction defines Carlet's footnote-44 trace formula directly and transports it through an arbitrary binary linear coordinate equivalence. The separate self-dual-normal-basis identity remains open, and the conditional parameter theorem is used only after the representative family has been constructed. + reuse_note: >- + The proof composes absolute-trace algebra, the quadratic polar-form criterion, trace-pairing coordinates, and the conditional Kerdock parameter reduction without postulating a representative family. + dependencies: + - carlet-5-quadratic-trace-representation + - carlet-6-quadratic-bent-characterization + - carlet-6-kerdock-parameters + - carlet-2-absolute-trace + - carlet-2-trace-pairing-coordinates + +source_recovery: + - id: carlet-6-hadamard-difference-set-cayley + kind: characterization-family + location: >- + Carlet, Section 6 opening discussion and Section 6.6.3, pp. 78 and 100 + source_claim: >- + For f : V_n -> F_2, bentness is equivalent to the matrix + H[x,y] = (-1)^(f(x+y)) being Hadamard and to supp(f) being a difference + set in the elementary Abelian 2-group V_n. The difference-set condition + implies that the Boolean Cayley graph G_f is strongly regular. Carlet later + reports a further characterization of bent functions through Cayley graphs. + statement_status: mixed-complete-equivalences-and-incomplete-cayley-reference + formal_status: open + declarations: [] + references: [18, 134, 202] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The two equivalences are complete in the survey. The strongly regular + graph sentence omits its parameters, and the later Cayley-graph + characterization is only a citation. Neither is strengthened to an unstated + parameter theorem here. + reuse_note: >- + The Walsh and derivative characterizations already provide the scalar + spectral content. Promotion should add explicit Hadamard-matrix, + difference-set, and strongly-regular-graph layers rather than encode those + objects as Boolean-function aliases. + blocker: >- + The repository has no reviewed design or graph API for these objects, and + reference [18] must be recovered for the exact Cayley parameters and the + later iff characterization. + dependencies: + - carlet-6-def-7-bent + - carlet-6-theorem-8-perfect-nonlinearity + - carlet-2-def-support-weight + + - id: carlet-6-restricted-derivative-and-moment-families + kind: theorem-family + location: >- + Carlet, discussion after Theorem 8, p. 78 + source_claim: >- + Carlet reports classifications of functions whose derivatives are + balanced in every nonzero direction of a fixed hyperplane, and likewise + of a fixed codimension-two subspace; in even dimension the first family + consists of bent functions. He also reports that every positive even Walsh + moment sum_a W_f(a)^w is minimized by bent functions and relates small + low-order moments to fast-correlation resistance. + statement_status: incomplete-source-recovery + formal_status: open + declarations: [] + references: [39, 40, 41, 46] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The survey states the scope and consequences but gives neither + classification formula nor the value and equality case of the moment + minimum. + reuse_note: >- + The derivative, propagation, Walsh, and autocorrelation APIs are already + canonical. Exact classification and moment statements should be recovered + before adding new nodes. + blocker: >- + References [39--41,46] are needed for the omitted parameterizations, + quantifiers, minimum value, and equality conditions. + dependencies: + - carlet-6-theorem-8-perfect-nonlinearity + - carlet-4-def-propagation-criteria + - carlet-2-parseval + + - id: carlet-6-support-code-alternate-characterizations + kind: theorem-family + location: >- + Carlet, alternatives following Proposition 16, p. 79 + source_claim: >- + For the support code C_f, Carlet reports two further iff + characterizations of bentness: C_f has dimension n and exactly two + weights whose sum is w_H(f); and the length w_H(f) is even, C_f has + exactly two weights, and one of them is 2^(n-2). + statement_status: complete-source-statements + formal_status: open + declarations: [] + references: [348] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The displayed alternatives are complete, but their small-dimension + conventions must be reconciled with the corrected n >= 4 range of the + existing Proposition 16 node. + reuse_note: >- + Both alternatives should reuse the existing support-code map, dimension, + and weight declarations rather than define a second code. + blocker: >- + No production declaration currently proves either alternative, including + the occurrence and zero-weight edge cases. + dependencies: + - carlet-6-prop-16-support-code + + - id: carlet-6-quadratic-trace-families + kind: construction-family + location: >- + Carlet, Section 6.2, pp. 81--82 + source_claim: >- + In even dimension n with gcd(i,n)=1, + Tr_n(v x^(2^i+1)) is bent exactly when v is not a cube. Carlet says the + analogous calculation applies to the Kasami exponent + 2^(2i)-2^i+1. He also gives the quadratic bent function + Tr_n(sum_(i=1)^(n/2-1) x^(2^i+1)) + + Tr_(n/2)(x^(2^(n/2)+1)), and, when gcd(n,3)=gcd(i,n)=1, the bent + two-variable function + Tr_(n/2)(x^(2^i+1)+y^(2^i+1)+xy). + statement_status: mixed-complete-examples-and-abbreviated-kasami-analogue + formal_status: open + declarations: [] + references: [] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The Gold criterion and the last two displayed examples are explicit. + The Kasami sentence says only that the same result is proved similarly, + so its coefficient convention must not be guessed. + reuse_note: >- + Promotion should specialize the quadratic polar-form and trace-pairing + nodes and prove triviality of the resulting radicals. + blocker: >- + The finite-field Frobenius equations and the abbreviated Kasami + coefficient statement are not yet represented by reviewed declarations. + dependencies: + - carlet-6-quadratic-bent-characterization + - carlet-5-quadratic-trace-representation + - carlet-2-absolute-trace + + - id: carlet-6-low-degree-classification-and-z-bent + kind: classification-family + location: >- + Carlet, end of Section 6.2, p. 82 + source_claim: >- + Carlet reports affine classifications for all bent functions through + six variables, for degree-at-most-three bent functions in eight variables, + and a completed enumeration of all eight-variable bent functions. Every + listed degree-at-most-three eight-variable function has a nonzero affine + derivative. He also cites a recursive construction by gluing Z-bent + functions. + statement_status: incomplete-source-recovery + formal_status: open + declarations: [] + references: [42, 141, 188, 231, 299, 310] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The survey supplies dimension and degree ranges but no orbit + representatives, counts, affine-equivalence certificates, or definition of + the Z-bent gluing operation. + reuse_note: >- + Any recovered classification should reuse affine invariance, derivative, + degree, and counting nodes; the Z-bent construction needs its own precise + semantic layer. + blocker: >- + The cited classifications and recursive construction must be recovered + from their primary sources before faithful statements can be written. + dependencies: + - carlet-6-def-7-bent + - carlet-6-quadratic-bent-characterization + - carlet-2-affine-invariance + + - id: carlet-6-primary-class-structural-results + kind: theorem-family + location: >- + Carlet, structural consequences for primary classes, pp. 85--87 + source_claim: >- + Every bent function represented as + f_(phi,g)(x,y)=x dot phi(y)+g(y) has balanced phi; every six-variable + bent function is affinely equivalent to a member of the original + Maiorana--McFarland class; n/2-dimensional vector spaces of n-variable + Boolean functions whose nonzero elements are bent exist, while no such + space has dimension greater than n/2. For the partial-spread classes, + Carlet records the exact degree of PS^- members, the explicit PS_ap + quotient form and self-duality, and a field-power/trace characterization + of its completed class, while leaving a general ANF characterization of + PS open. + statement_status: mixed-complete-consequences-vectorial-bound-and-explicit-open-problem + formal_status: open + declarations: [] + references: [24, 81, 134, 254] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The survey states these as several distinct consequences. The + balanced-vector-map and dimension bound use vectorial Boolean-function + theory, and the open PS ANF problem is not replaced by the explicit + PS_ap subclass. + reuse_note: >- + Promotion should specialize the general Maiorana--McFarland and + partial-spread nodes and reuse affine equivalence, algebraic degree, and + the field trace layer. + blocker: >- + The six-variable affine classification, vectorial balance/dimension + bound, and completed-class trace characterization need independent + primary-source statements and proofs. + dependencies: + - carlet-6-maiorana-mcfarland + - carlet-6-prop-20-general-maiorana-mcfarland + - carlet-6-partial-spread-construction + - carlet-6-dual + + - id: carlet-6-primary-power-families + kind: construction-family + location: >- + Carlet, primary power-function constructions, pp. 88--89 + source_claim: >- + For f(x)=Tr_n(a x^i), Carlet lists the known monomial bent + families up to Frobenius conjugacy: Gold exponents i=2^j+1 when + n/gcd(j,n) is even, with bentness exactly when a is not an i-th power; + Dillon exponents i=j(2^(n/2)-1), gcd(j,2^(n/2)+1)=1 and + a in GF(2^(n/2)), with bentness exactly when the stated Kloosterman sum + vanishes; Kasami exponents i=2^(2j)-2^j+1, gcd(j,n)=1, with bentness + exactly when a is not a cube; i=(2^(n/4)+1)^2 for 4 | n, for which one + coefficient example is known but the full coefficient set is open; and + i=2^(n/3)+2^(n/6)+1 for 6 | n, with the displayed relative-trace + criterion on a. The section also gives + Tr_(n/2)(x^(2^(n/2)+1)), the necessary coprimality alternative for any + bent power exponent, and bent restrictions of Kasami functions to the + trace-zero hyperplane when n+1=3k+1 or 3k-1. + statement_status: mixed-complete-conditional-families-and-explicit-open-coefficient-set + formal_status: open + declarations: [] + references: [39, 43, 101, 133, 134, 137, 138, 223, 238] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The inventory retains every printed parameter condition and the + explicitly unknown coefficient set. It does not turn the list of exponents + known in 2010 into a timeless classification theorem. + reuse_note: >- + Promotion requires the absolute-trace, univariate binary-degree, + quadratic-radical, Kloosterman-sum, and affine-restriction surfaces already + owned by earlier chapters. + blocker: >- + The monomial families require several independent finite-field power-map + and character-sum proofs; the coefficient classification for the + (2^(n/4)+1)^2 family is explicitly open. + dependencies: + - carlet-2-absolute-trace + - carlet-2-univariate-binary-degree + - carlet-6-quadratic-bent-characterization + - carlet-6-theorem-11-hyperplane-restrictions + + - id: carlet-6-power-sum-and-homogeneous-families + kind: construction-family + location: >- + Carlet, end of primary constructions, pp. 88--89 + source_claim: >- + Carlet cites further bent functions that are sums of a few power + functions, bent sequences obtained from the listed primary and secondary + constructions, and homogeneous bent functions on at most twelve variables + found by invariant-theory searches. + statement_status: incomplete-source-recovery + formal_status: open + declarations: [] + references: [98, 101, 134, 137, 142, 143, 195, 237, 350, 352] + first_release_scope: required-after-source-recovery + fidelity_note: >- + No exponent lists, coefficient conditions, ANFs, orbit + representatives, or exact variable-by-variable existence statement are + printed in this chapter. + reuse_note: >- + Recovered scalar families should reuse the canonical trace, + algebraic-degree, affine-equivalence, and bentness definitions. + blocker: >- + The primary papers are required to identify the actual families and + quantifiers; a citation list cannot support a source-facing theorem. + dependencies: + - carlet-2-absolute-trace + - carlet-2-def-algebraic-degree + - carlet-6-def-7-bent + + - id: carlet-6-classes-d-and-c + kind: construction-family + location: >- + Carlet, secondary classes D_0, D, and C, pp. 90--91 + source_claim: >- + For a permutation pi on V_(n/2), D_0 consists of + x dot pi(y)+delta_0(x) and has dual y dot pi^(-1)(x)+delta_0(y). + Class D consists of + x dot pi(y)+1_(E_1)(x)1_(E_2)(y) with pi(E_2)=E_1^perp. + Class C consists of x dot pi(y)+1_L(x) when every + pi^(-1)(a+L^perp) is an affine flat; under the same condition, + x dot pi(y)+1_L(x)+g(y) is bent whenever g restricts affinely to every + such flat. Carlet also records completion and six-variable consequences + for D_0. + statement_status: complete-source-specializations-with-cited-class-separation-claims + formal_status: open + declarations: [] + references: [44, 53] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The construction hypotheses and dual formula are explicit. Claims + that D_0 is outside completed M and PS classes and covers all six-variable + bent functions are retained as cited consequences, not inferred from the + generic switching theorem. + reuse_note: >- + The bentness constructions are direct specializations of the + Maiorana--McFarland and flat-switching nodes and should reuse their affine + flat indicators and dual laws. + blocker: >- + No dedicated declarations instantiate Theorem 9 with these parameters, + and the completed-class nonmembership claims require formal affine-class + predicates not currently present. + dependencies: + - carlet-6-maiorana-mcfarland + - carlet-6-theorem-9-flat-switching + - carlet-5-flat-indicator-walsh-nonlinearity + + - id: carlet-6-dobbertin-primary-class + kind: construction-family + location: >- + Carlet, Dobbertin construction, p. 87 + source_claim: >- + Let g be balanced on GF(2^(n/2)), let T be the affine + subspace spanned by the support of (-1)^g, and let phi and psi be maps + that restrict affinely to every aT, with phi injective. Dobbertin's class + defines f by + f(x,phi(y))=g((x+psi(y))/y) + and contains both PS_ap and the Maiorana--McFarland class. The cited work + also gives two explicit examples with phi a power map. + statement_status: complete-general-template-with-incomplete-explicit-examples + formal_status: open + declarations: [] + references: [139] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The general template and its hypotheses are printed, but the two + power-map examples are not. Division-at-zero and the precise affine-span + convention must be recovered before promotion. + reuse_note: >- + The construction should reuse the finite-field realization of the + Maiorana--McFarland and partial-spread families rather than replace their + Boolean-cube statements. + blocker: >- + The omitted examples and quotient conventions require reference [139]; + the present finite-field layer has no reviewed declaration for this + template. + dependencies: + - carlet-6-maiorana-mcfarland + - carlet-6-partial-spread-construction + - carlet-2-absolute-trace + + - id: carlet-6-vectorial-ab-construction + kind: construction-family + location: >- + Carlet, vectorial almost-bent construction, p. 87 + source_claim: >- + Let m=n/2 be odd and let F : V_m -> V_m be almost bent, + meaning that every nonzero component v dot F is plateaued with amplitude + 2^((m+1)/2). Define gamma_F(a,b)=1 exactly when a is nonzero and + F(x)+F(x+a)=b has a solution, and zero otherwise. Then gamma_F is bent + on V_m x V_m. Carlet notes that the ANF and univariate representation are + open when F is a Kasami, Welch, or Niho almost-bent function. + statement_status: complete-scalar-consequence-with-vectorial-prerequisite + formal_status: open + declarations: [] + references: [] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The scalar output and AB hypothesis are complete, including the + a != 0 convention. No scalar surrogate is substituted for the vectorial + AB definition. + reuse_note: >- + The conclusion can reuse scalar bentness and plateaued component + functions, but the input predicate belongs to the later vectorial Boolean + function theory. + blocker: >- + Vectorial Boolean functions and their AB spectrum are outside the first + scalar release, and the cited proof is delegated to the absent vectorial + chapter. + dependencies: + - carlet-6-def-7-bent + - carlet-6-def-plateaued + + - id: carlet-6-secondary-specializations + kind: construction-family + location: >- + Carlet, additional secondary constructions, pp. 92--94 + source_claim: >- + Carlet records the normal extension of + Maiorana--McFarland type obtained by adjoining a y-indexed family of bent + functions, three explicit four-block families derived from Theorem 10, + and three Hou--Langevin consequences of Proposition 21, including the + degree-at-most-three derivative reindexing and a quadratic-form + reindexing of x dot y+g(y). + statement_status: mixed-complete-formulas-and-cited-examples + formal_status: open + declarations: [] + references: [56, 78, 190, 194] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The displayed construction formulas are complete, while the + additional examples in references [56,190,194] are only mentioned. + This record does not merge their distinct hypotheses into one theorem. + reuse_note: >- + The complete displayed families are specializations of the slice + construction or permutation reindexing and should be proved by those + general combinators. + blocker: >- + No public specialization declarations are associated, and the cited + example families require primary-source recovery. + dependencies: + - carlet-6-theorem-10-slice-construction + - carlet-6-prop-21-permutation-reindexing + - carlet-6-maiorana-mcfarland + + - id: carlet-6-additional-decompositions + kind: theorem-family + location: >- + Carlet, Section 6.4.3, p. 97 + source_claim: >- + If an odd-variable function f has every derivative D_u f + balanced for nonzero u in a fixed hyperplane a^perp, then the restriction + of f to a^perp and its complementary coset is bent. For a bent f, the + four restrictions to the cosets of a codimension-two subspace have the + same sets of Walsh magnitudes; if its orthogonal complement is spanned by + a,b, all four restrictions are bent exactly when D_a D_b of the dual is + the constant one function. Carlet cites further decomposition results. + statement_status: complete-two-results-with-incomplete-further-family + formal_status: open + declarations: [] + references: [41, 42, 100] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The two displayed consequences are complete. The phrase "more on + decomposing bent functions" contains no additional theorem statement and + remains unpromoted. + reuse_note: >- + Both complete consequences should reuse the hyperplane-restriction, + dual, and second-derivative APIs. + blocker: >- + The codimension-two restriction spectrum and its iff criterion have no + associated declarations; the remaining cited family lacks statements. + dependencies: + - carlet-6-theorem-11-hyperplane-restrictions + - carlet-6-dual + - carlet-6-prop-24-second-order-characterization + + - id: carlet-6-additional-counting + kind: counting-family + location: >- + Carlet, Section 6.5, pp. 97--98 + source_claim: >- + Besides the exact Maiorana--McFarland count, Carlet gives + C(2^(n/2),2^(n/2-1)) for the PS_ap family, an affine-automorphism upper + estimate for the completed Maiorana--McFarland class, and states that an + efficient general lower bound remains open. He reports the approximate + exact counts B_6 approximately 2^32.3 and B_8 approximately 2^106.3, + earlier and improved upper bounds for B_8, and an exponentially improved + upper bound over the naive bound that divides it by approximately + 2^(2^(n/2)-n/2-1). + statement_status: mixed-complete-counts-asymptotics-and-incomplete-cited-bound + formal_status: open + declarations: [] + references: [81, 89, 125, 231, 232, 299] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The PS_ap binomial count and the reported finite values are + explicit. The chapter gives only an approximate description of the [89] + upper bound and no efficient lower-bound theorem. + reuse_note: >- + The finite family counts should reuse the partial-spread and + Maiorana--McFarland parameter spaces; any global bound should reuse the + bent-function family and Reed--Muller degree count. + blocker: >- + The exact theorem behind reference [89], the exact integer values behind + the logarithmic approximations, and the affine-orbit overlap count must be + recovered before promotion. + dependencies: + - carlet-6-maiorana-mcfarland-count + - carlet-6-naive-bent-count-bound + - carlet-6-partial-spread-construction + + - id: carlet-6-alternate-geometric-and-gps-translation + kind: characterization-family + location: >- + Carlet, discussion following Theorem 12, pp. 99--100 + source_claim: >- + Carlet cites an alternative geometric characterization + f=sum_i m_i 1_(E_i) plus or minus 2^(n/2-1)delta_0, where every E_i has + dimension n/2 or n/2+1, together with a restricted choice of such spaces + that makes the representation unique. He also reports Guillot's theorem + that every bent function becomes a member of the exact generalized + partial-spread class after a translation of its input. + statement_status: mixed-complete-shape-and-incomplete-unique-subclass + formal_status: open + declarations: [] + references: [85, 169] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The allowed dimensions, coefficients, sign, and translation + conclusion are explicit. The chapter does not identify the distinguished + subclass that yields uniqueness, so that part remains incomplete. + reuse_note: >- + Both results should reuse the subspace-indicator lemma, Theorem 12, + affine translation, and the exact GPS representation predicate. + blocker: >- + The alternative representation and Guillot translation theorem have no + production associations, and reference [85] is required to define the + unique representing subclass. + dependencies: + - carlet-6-lemma-3-subspace-indicators + - carlet-6-theorem-12-geometric-characterization + - carlet-2-affine-invariance + + - id: carlet-6-hyper-bent-trace-degree + kind: theorem + location: >- + Carlet, cyclic-code consequence, p. 102 + source_claim: >- + Every hyper-bent f : GF(2^n) -> F_2 can be represented as + f(x)=sum_i Tr_n(a_i x^(t_i))+epsilon with every binary exponent weight + w_2(t_i)=n/2. Consequently every hyper-bent function has algebraic + degree exactly n/2. + statement_status: complete-source-statement + formal_status: open + declarations: [] + references: [81] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The source states both the representation and exact degree. Promotion + must retain a canonical reduced univariate representation so cancellation + between cyclotomic orbits is not silently ignored. + reuse_note: >- + The result should reuse hyper-bentness, the Chapter 2 univariate + binary-degree theorem, and cyclotomic-orbit noncancellation. + blocker: >- + The required normal form for sums of trace monomials and the + noncancellation argument for all exponent orbits are not yet associated + with this Chapter 6 claim. + dependencies: + - carlet-6-def-hyper-bent + - carlet-2-univariate-binary-degree + - carlet-2-trace-monomial-degree + + - id: carlet-6-reference-101-hyper-bent-family + kind: theorem + location: >- + Carlet, trace family from reference [101], p. 103 + source_claim: >- + Let n be even, lambda in GF(2^(n/2))^*, and + 0- + The hypotheses, both exponents, the nonzero coefficient, and the iff + balance condition are retained. Bent and hyper-bent are equivalent only + for this family as stated by Carlet; no general equivalence is inferred. + reuse_note: >- + Promotion should reuse the field hyper-bent transform and balance + predicate, with a separate cyclotomic-coset size interface. + blocker: >- + The repository lacks cyclotomic-coset cardinality and inverse-power + character-sum declarations needed for this equivalence. + dependencies: + - carlet-6-def-hyper-bent + - carlet-2-absolute-trace + - carlet-2-balanced-zero-walsh + + - id: carlet-6-nonnormal-examples + kind: example-family + location: >- + Carlet, Section 6.9, p. 107 + source_claim: >- + For gcd(k,n)=1, n not divisible by 3, and a not a cube, + the Kasami function + f(x)=Tr_n(a x^(2^(2k)-2^k+1)) + is bent. For a in GF(4)\GF(2) and k=3, in dimension 10 a constant + translate f+Tr_n(b) is nonnormal for some b, while in dimension 14 f is + not weakly normal. Every cubic bent function in eight variables is + normal. + statement_status: complete-reported-examples-with-unspecified-witness-b + formal_status: open + declarations: [] + references: [44, 100, 137] + first_release_scope: required-after-source-recovery + fidelity_note: >- + The dimensions, exponent, coprimality, noncube condition, and + normality conclusions are retained. The source does not identify the + dimension-ten witness b, so no explicit representative is invented. + reuse_note: >- + The examples should reuse the fixed-dimensional normality predicates, + trace monomials, algebraic degree, and affine-flat restriction APIs. + blocker: >- + The witness b and the exhaustive eight-variable cubic classification + require the cited computations and certificates. + dependencies: + - carlet-6-def-7-bent + - carlet-5-def-4-normality + - carlet-2-trace-monomial-degree + + - id: carlet-6-kerdock-additional-properties + kind: code-property-family + location: >- + Carlet, Kerdock open problem and remark, p. 110 + source_claim: >- + Carlet reports other codes with Kerdock parameters, all affinely + equivalent to subcodes of R(2,n), and leaves construction with + nonquadratic representatives open. Kerdock codes are distance-invariant, + so their distance and weight enumerators agree; their weight enumerators + are formally dual to those of Preparata codes; and the codes admit a + Z/4Z-linear structure for which a MacWilliams identity holds. + statement_status: mixed-complete-properties-and-explicit-open-construction + formal_status: open + declarations: [] + references: [173, 203, 324] + first_release_scope: required-after-source-recovery + fidelity_note: >- + These are properties of the actual Kerdock construction, not + consequences of an arbitrary family satisfying only the conditional + parameter hypotheses. The open nonquadratic construction remains an + open problem. + reuse_note: >- + Promotion should build on the explicit field-construction node and a + separate distance-enumerator, Preparata, and Z/4Z code layer. + blocker: >- + The current code API records only membership, cardinality, and minimum + distance. It has no distance distribution, formal duality, Preparata code, + or Z/4Z-linear structure. + dependencies: + - carlet-6-kerdock-field-construction + - carlet-6-kerdock-parameters + - carlet-3-reed-muller-code diff --git a/AGENTS.md b/AGENTS.md index a23bf3e..f597090 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,17 +28,19 @@ matching Verso entry and production declaration. ## Current verified surface -The Blueprint baseline is 149 source-facing statement nodes: 146 formalized nodes associated with -961 proved Lean declarations and 3 visibly open nodes, connected by 296 reviewed dependency edges. +The Blueprint baseline is 209 source-facing statement nodes: 206 formalized nodes associated with +1338 proved Lean declarations and 3 visibly open nodes, connected by 467 reviewed dependency +edges. -- Chapter 2 contributes 38 formalized nodes, 166 declarations, and 48 incoming +- Chapter 2 contributes 41 formalized nodes, 174 declarations, and 56 incoming edges. It covers the scalar Boolean-function domain, support and weight, balancedness, raw Walsh transforms, the scaling identity for FABL coefficients, Walsh inversion, Parseval, algebraic and numerical normal forms, raw pseudo-Boolean Fourier operations, the full raw Poisson formula, derivatives, autocorrelation, finite-field trace and representation, distance scaling, affine invariance, restriction recovery, - spectral-support bounds, the coordinate/univariate binary-degree formula, trace-monomial degree, - and trace-pairing coordinates. + spectral-support bounds, the NNF Fourier formula, restriction-square identities, Walsh + divisibility, the coordinate/univariate binary-degree formula, trace-monomial degree, and + trace-pairing coordinates. - Chapter 3 contributes 7 formalized nodes, 32 declarations, and 19 incoming edges. It defines `reedMuller r n` and proves the affine-weight theorem, general-order distance theorem, Proposition 12's minimum-weight affine-flat classification, dimension and cardinality formulas, @@ -48,13 +50,19 @@ The Blueprint baseline is 149 source-facing statement nodes: 146 formalized node and propagation, linear structures, algebraic immunity, autocorrelation, maximum correlation, and related complexity criteria, including the sharp random-nonlinearity interval, the exact dimension-seven maximum, and the sharp fixed-order higher-order asymptotic upper bound. -- Chapter 5 contributes 31 nodes (28 formalized and 3 open), 195 declarations, and 70 incoming +- Chapter 5 contributes 31 nodes (28 formalized and 3 open), 203 declarations, and 70 incoming edges. Its statements cover affine spectra, quadratic polar forms, weights and affine normal forms, the exact quadratic weight and nonlinearity value sets, quadraticization Walsh lifts, affine-flat indicator spectra and nonlinearity, the full restriction bound and its equality case, exact random nonnormality, covering-sequence consequences, quadratic trace representation, and the conditional character-sum/nonlinearity reduction. +- Chapter 6 contributes 57 formalized nodes, 361 declarations, and 163 incoming edges. It covers + bentness, duality, algebraic-degree bounds and Relation (47), primary and secondary + constructions, decompositions and counting, NNF, geometric and second-order characterizations, + hyper-bent functions, partially bent and plateaued superclasses, normal extensions, and the + Kerdock field construction and parameters. The proof of Relation (47) includes the reusable + McEliece--Ax character-sum divisibility theorem. - Chapter 2 has no open source node. Its binary-degree formula and trace-pairing coordinates, together with cyclotomic-orbit noncancellation, close Carlet Proposition 3 on trace-monomial algebraic degree. @@ -62,6 +70,9 @@ The Blueprint baseline is 149 source-facing statement nodes: 146 formalized node dual-code weight decomposition, exact weight-`16` rank-seven classification, character-sum estimate, and finite Plotkin induction; these remain separate formalized nodes so that the proof structure is visible in the Blueprint. +- Chapter 6 has no open source node. Its finite proofs reuse the canonical FABL Fourier, ANF, + algebraic-degree, affine, and derivative APIs together with the preceding Carlet Walsh, + Reed--Muller, nonlinearity, quadratic, trace, restriction, and normality layers. - The three open Chapter 5 nodes are the analytic Weil character-sum bound, its nonlinearity corollary, and the reciprocal character-sum bound. - Carlet's Reed--Muller coset-distance equality is formalized with the necessary pairwise-distinct- diff --git a/CryptBoolean.lean b/CryptBoolean.lean index c3e8597..076a626 100644 --- a/CryptBoolean.lean +++ b/CryptBoolean.lean @@ -10,6 +10,7 @@ public import CryptBoolean.Carlet.Chapter02 public import CryptBoolean.Carlet.Chapter03 public import CryptBoolean.Carlet.Chapter04 public import CryptBoolean.Carlet.Chapter05 +public import CryptBoolean.Carlet.Chapter06 /-! # CryptBoolean diff --git a/CryptBoolean/BooleanFunction.lean b/CryptBoolean/BooleanFunction.lean index 95408a5..8b32a13 100644 --- a/CryptBoolean/BooleanFunction.lean +++ b/CryptBoolean/BooleanFunction.lean @@ -29,4 +29,15 @@ abbrev BooleanFunction (n : ℕ) := FABL.F₂Cube n → FABL.𝔽₂ abbrev realSignView {n : ℕ} (f : BooleanFunction n) : FABL.F₂Cube n → ℝ := FABL.realSignEncodedFunction f +/-- The canonical linear splitting of a binary cube into two coordinate +blocks. -/ +def cubeSplitLinearEquiv (a b : ℕ) : + FABL.F₂Cube (a + b) ≃ₗ[FABL.𝔽₂] + (FABL.F₂Cube a × FABL.F₂Cube b) where + __ := (Fin.appendEquiv a b).symm + map_add' _ _ := by + apply Prod.ext <;> funext i <;> rfl + map_smul' _ _ := by + apply Prod.ext <;> funext i <;> rfl + end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter02.lean b/CryptBoolean/Carlet/Chapter02.lean index 6b9e453..2b39d11 100644 --- a/CryptBoolean/Carlet/Chapter02.lean +++ b/CryptBoolean/Carlet/Chapter02.lean @@ -7,6 +7,7 @@ module public import CryptBoolean.Carlet.Chapter02.Foundations public import CryptBoolean.Carlet.Chapter02.Fourier +public import CryptBoolean.Carlet.Chapter02.FourierNNF public import CryptBoolean.Carlet.Chapter02.FourierOperations public import CryptBoolean.Carlet.Chapter02.Subspaces public import CryptBoolean.Carlet.Chapter02.Derivatives @@ -15,6 +16,7 @@ public import CryptBoolean.Carlet.Chapter02.ANFExistence public import CryptBoolean.Carlet.Chapter02.AlgebraicDegree public import CryptBoolean.Carlet.Chapter02.Affine public import CryptBoolean.Carlet.Chapter02.AffineSubspaceRestrictions +public import CryptBoolean.Carlet.Chapter02.RestrictionSquareIdentity public import CryptBoolean.Carlet.Chapter02.Restrictions public import CryptBoolean.Carlet.Chapter02.NumericalNormalForm public import CryptBoolean.Carlet.Chapter02.SpectralSupport @@ -22,6 +24,7 @@ public import CryptBoolean.Carlet.Chapter02.FiniteField public import CryptBoolean.Carlet.Chapter02.FiniteFieldAlgebraicDegree public import CryptBoolean.Carlet.Chapter02.TraceMonomialDegree public import CryptBoolean.Carlet.Chapter02.TracePairing +public import CryptBoolean.Carlet.Chapter02.WalshDivisibility /-! # Carlet Chapter 2 diff --git a/CryptBoolean/Carlet/Chapter02/Foundations.lean b/CryptBoolean/Carlet/Chapter02/Foundations.lean index 9dc60f7..9d88f1a 100644 --- a/CryptBoolean/Carlet/Chapter02/Foundations.lean +++ b/CryptBoolean/Carlet/Chapter02/Foundations.lean @@ -71,6 +71,17 @@ theorem bitSignInt_eq_if_one (b : FABL.𝔽₂) : exact hb (Fin.eq_one_of_ne_zero b hzero) simp [bitSignInt, hb_zero] +/-- The integer sign encoding distinguishes the two binary values. -/ +theorem bitSignInt_injective : Function.Injective bitSignInt := by + intro p q hpq + apply FABL.binarySign_injective + rw [← FABL.signValue_signEncode_eq_binarySign, + ← FABL.signValue_signEncode_eq_binarySign] + have hunit : FABL.signEncode p = FABL.signEncode q := by + apply Units.ext + exact hpq + exact congrArg FABL.signValue hunit + /-- The integer sign encoding sends binary addition to multiplication. -/ theorem bitSignInt_add (a b : FABL.𝔽₂) : bitSignInt (a + b) = bitSignInt a * bitSignInt b := by diff --git a/CryptBoolean/Carlet/Chapter02/FourierNNF.lean b/CryptBoolean/Carlet/Chapter02/FourierNNF.lean new file mode 100644 index 0000000..47da2b6 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter02/FourierNNF.lean @@ -0,0 +1,139 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter02.SpectralSupport +import FABL.Chapter05.DegreeOneWeight + +/-! +# Fourier transform of the numerical normal form + +Carlet Relation (30): the unnormalized Fourier coefficients of a pseudo-Boolean +function in numerical normal form. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +open FABL + +variable {n : ℕ} + +/-- The raw Fourier coefficient of a numerical monomial. -/ +theorem rawFourierTransform_numericalMonomial + (S : Finset (Fin n)) (u : FABL.F₂Cube n) : + rawFourierTransform (numericalMonomial S) u = + if FABL.f₂Support u ⊆ S then + (-1 : ℝ) ^ (FABL.f₂Support u).card * (2 : ℝ) ^ (n - S.card) + else 0 := by + classical + rw [numericalMonomial_eq_setIndicator_coordinateSubcube, + FABL.F₂DecisionTree.coordinateSubcube_eq_binaryAffineSubspace, + rawFourierTransform_setIndicator_binaryAffineSubspace] + by_cases hu : FABL.f₂Support u ⊆ S + · have humem : + u ∈ FABL.perpendicularSubspace + (FABL.F₂DecisionTree.coordinateZeroSubspace S) := + (FABL.mem_perpendicular_coordinateZeroSubspace_iff_f₂Support_subset S u).2 hu + rw [if_pos humem, if_pos hu] + have hcharacter : + FABL.vectorWalshCharacter u (FABL.f₂CubeOfFinset S) = + (-1 : ℝ) ^ (FABL.f₂Support u).card := by + rw [FABL.vectorWalshCharacter_apply, + FABL.f₂DotProduct_eq_coordinateSum_f₂Support] + change FABL.binarySign + (∑ i ∈ FABL.f₂Support u, FABL.f₂CubeOfFinset S i) = _ + have hvalues : ∀ i ∈ FABL.f₂Support u, + FABL.f₂CubeOfFinset S i = 1 := by + intro i hi + simp [FABL.f₂CubeOfFinset_apply, hu hi] + have hsum : + (∑ i ∈ FABL.f₂Support u, FABL.f₂CubeOfFinset S i) = + (FABL.f₂Support u).card • (1 : FABL.𝔽₂) := by + calc + (∑ i ∈ FABL.f₂Support u, FABL.f₂CubeOfFinset S i) = + ∑ _i ∈ FABL.f₂Support u, (1 : FABL.𝔽₂) := by + apply Finset.sum_congr rfl + intro i hi + exact hvalues i hi + _ = (FABL.f₂Support u).card • (1 : FABL.𝔽₂) := by + rw [Finset.sum_const] + rw [hsum, AddChar.map_nsmul_eq_pow] + rw [show FABL.binarySign (1 : FABL.𝔽₂) = (-1 : ℝ) by + change (-1 : ℝ) ^ (1 : FABL.𝔽₂).val = -1 + rw [show (1 : FABL.𝔽₂).val = 1 by decide] + norm_num] + have hcard : + Nat.card (FABL.F₂DecisionTree.coordinateZeroSubspace S) = + 2 ^ (n - S.card) := by + rw [FABL.card_submodule_eq_two_pow_finrank] + congr 1 + have hcodimension := + FABL.F₂DecisionTree.f₂Codimension_coordinateZeroSubspace S + rw [FABL.f₂Codimension, FABL.finrank_perpendicularSubspace] at hcodimension + have hfinrank : + Module.finrank FABL.𝔽₂ + (FABL.F₂DecisionTree.coordinateZeroSubspace S) ≤ n := by + simpa using (FABL.F₂DecisionTree.coordinateZeroSubspace S).finrank_le + omega + have hcardReal : + (Nat.card (FABL.F₂DecisionTree.coordinateZeroSubspace S) : ℝ) = + (2 : ℝ) ^ (n - S.card) := by + exact_mod_cast hcard + rw [hcharacter, hcardReal] + · have hunotmem : + u ∉ FABL.perpendicularSubspace + (FABL.F₂DecisionTree.coordinateZeroSubspace S) := fun humem ↦ + hu ((FABL.mem_perpendicular_coordinateZeroSubspace_iff_f₂Support_subset S u).1 + humem) + rw [if_neg hunotmem, if_neg hu, mul_zero] + +/-- Carlet Relation (30): the raw Fourier transform of a numerical normal form. -/ +theorem rawFourierTransform_numericalEval + (c : NumericalCoefficients n) (u : FABL.F₂Cube n) : + rawFourierTransform (numericalEval c) u = + (-1 : ℝ) ^ (FABL.f₂Support u).card * + ∑ S ∈ (Finset.univ.filter fun S : Finset (Fin n) ↦ + FABL.f₂Support u ⊆ S), + (2 : ℝ) ^ (n - S.card) * c S := by + classical + rw [rawFourierTransform_eq_two_pow_mul_vectorFourierCoeff, + vectorFourierCoeff_numericalEval, Finset.mul_sum] + calc + ∑ S : Finset (Fin n), + (2 ^ n : ℝ) * + (c S * FABL.vectorFourierCoeff (numericalMonomial S) u) = + ∑ S : Finset (Fin n), c S * rawFourierTransform (numericalMonomial S) u := by + apply Finset.sum_congr rfl + intro S _ + rw [rawFourierTransform_eq_two_pow_mul_vectorFourierCoeff] + ring + _ = ∑ S : Finset (Fin n), + if FABL.f₂Support u ⊆ S then + (-1 : ℝ) ^ (FABL.f₂Support u).card * + ((2 : ℝ) ^ (n - S.card) * c S) + else 0 := by + apply Finset.sum_congr rfl + intro S _ + rw [rawFourierTransform_numericalMonomial] + by_cases hS : FABL.f₂Support u ⊆ S <;> simp [hS] + ring + _ = ∑ S ∈ (Finset.univ.filter fun S : Finset (Fin n) ↦ + FABL.f₂Support u ⊆ S), + (-1 : ℝ) ^ (FABL.f₂Support u).card * + ((2 : ℝ) ^ (n - S.card) * c S) := by + rw [Finset.sum_filter] + _ = (-1 : ℝ) ^ (FABL.f₂Support u).card * + ∑ S ∈ (Finset.univ.filter fun S : Finset (Fin n) ↦ + FABL.f₂Support u ⊆ S), + (2 : ℝ) ^ (n - S.card) * c S := by + rw [Finset.mul_sum] + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter02/FourierOperations.lean b/CryptBoolean/Carlet/Chapter02/FourierOperations.lean index 14c6165..966e977 100644 --- a/CryptBoolean/Carlet/Chapter02/FourierOperations.lean +++ b/CryptBoolean/Carlet/Chapter02/FourierOperations.lean @@ -39,6 +39,15 @@ theorem rawFourierTransform_eq_two_pow_mul_vectorFourierCoeff norm_num field_simp +/-- The raw Fourier transform of the constant-one function is supported only +at the zero frequency. -/ +theorem rawFourierTransform_one (a : FABL.F₂Cube n) : + rawFourierTransform (fun _ ↦ (1 : ℝ)) a = + if a = 0 then (2 : ℝ) ^ n else 0 := by + rw [rawFourierTransform_eq_two_pow_mul_vectorFourierCoeff, + FABL.vectorFourierCoeff_eq_expect] + simp [FABL.expect_vectorWalshCharacter] + /-- Multiplying by a Walsh character shifts the normalized Fourier index. -/ theorem vectorFourierCoeff_mul_vectorWalshCharacter (φ : FABL.F₂Cube n → ℝ) (a u : FABL.F₂Cube n) : diff --git a/CryptBoolean/Carlet/Chapter02/RestrictionSquareIdentity.lean b/CryptBoolean/Carlet/Chapter02/RestrictionSquareIdentity.lean new file mode 100644 index 0000000..8066c62 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter02/RestrictionSquareIdentity.lean @@ -0,0 +1,136 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter02.AffineSubspaceRestrictions +public import CryptBoolean.Carlet.Chapter02.Derivatives +public import CryptBoolean.Carlet.Chapter02.Subspaces + +import Mathlib.LinearAlgebra.Projection + +/-! +# Walsh square mass of affine-subspace restrictions + +Carlet Proposition 9 and Relation (28), with unnormalized Walsh transforms and +affine-coset restrictions represented on their direction subspace. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +noncomputable local instance restrictionSquareSubmoduleFintype + (S : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) : Fintype S := + Fintype.ofFinite S + +/-- The unnormalized sign imbalance of the restriction of `f` to `a + E`. -/ +noncomputable def affineSubspaceRestrictionImbalance + (f : BooleanFunction n) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (a : FABL.F₂Cube n) : ℝ := + ∑ x : E, FABL.affineSubspaceRestriction (realSignView f) E a x + +private theorem sum_additiveCorrelation_eq_sum_sq + {G : Type*} [Fintype G] [AddCommGroup G] (φ : G → ℝ) : + (∑ e : G, ∑ x : G, φ x * φ (x + e)) = (∑ x : G, φ x) ^ 2 := by + classical + calc + (∑ e : G, ∑ x : G, φ x * φ (x + e)) = + ∑ x : G, ∑ e : G, φ x * φ (x + e) := by + rw [Finset.sum_comm] + _ = ∑ x : G, φ x * ∑ y : G, φ y := by + apply Finset.sum_congr rfl + intro x _hx + rw [← Finset.mul_sum] + congr 1 + simpa [add_comm] using Equiv.sum_comp (Equiv.addRight x) φ + _ = (∑ x : G, φ x) * ∑ y : G, φ y := by + rw [Finset.sum_mul] + _ = (∑ x : G, φ x) ^ 2 := by ring + +/-- Summing ambient autocorrelation over `E` separates into the squared +imbalances of the restrictions on the cosets indexed by a complement `E'`. -/ +theorem sum_autocorrelation_submodule_eq_sum_affineSubspaceRestrictionImbalance_sq + (f : BooleanFunction n) + (E E' : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hcompl : IsCompl E E') : + (∑ e : E, autocorrelation f e.1) = + ∑ a : E', (affineSubspaceRestrictionImbalance f E a.1) ^ 2 := by + classical + have hcoset (e : E) : + autocorrelation f e.1 = + ∑ p : E × E', + FABL.affineSubspaceRestriction (realSignView f) E p.2.1 p.1 * + FABL.affineSubspaceRestriction (realSignView f) E p.2.1 + (p.1 + e) := by + rw [autocorrelation] + simp_rw [realSignView_booleanDerivative] + rw [← Equiv.sum_comp (E.prodEquivOfIsCompl E' hcompl).toEquiv] + apply Finset.sum_congr rfl + intro p _hp + simp only [FABL.affineSubspaceRestriction_apply, Submodule.coe_add] + congr 1 + ac_rfl + calc + (∑ e : E, autocorrelation f e.1) = + ∑ e : E, ∑ p : E × E', + FABL.affineSubspaceRestriction (realSignView f) E p.2.1 p.1 * + FABL.affineSubspaceRestriction (realSignView f) E p.2.1 + (p.1 + e) := by + apply Finset.sum_congr rfl + intro e _he + exact hcoset e + _ = ∑ e : E, ∑ x : E, ∑ a : E', + FABL.affineSubspaceRestriction (realSignView f) E a.1 x * + FABL.affineSubspaceRestriction (realSignView f) E a.1 (x + e) := by + simp only [Fintype.sum_prod_type] + _ = ∑ e : E, ∑ a : E', ∑ x : E, + FABL.affineSubspaceRestriction (realSignView f) E a.1 x * + FABL.affineSubspaceRestriction (realSignView f) E a.1 (x + e) := by + apply Finset.sum_congr rfl + intro e _he + rw [Finset.sum_comm] + _ = ∑ a : E', ∑ e : E, ∑ x : E, + FABL.affineSubspaceRestriction (realSignView f) E a.1 x * + FABL.affineSubspaceRestriction (realSignView f) E a.1 (x + e) := by + rw [Finset.sum_comm] + _ = ∑ a : E', (affineSubspaceRestrictionImbalance f E a.1) ^ 2 := by + apply Finset.sum_congr rfl + intro a _ha + exact sum_additiveCorrelation_eq_sum_sq + (FABL.affineSubspaceRestriction (realSignView f) E a.1) + +/-- Carlet Proposition 9, Relation (28): the Walsh square mass on `E`'s +perpendicular is the perpendicular cardinality times the second moment of the +imbalances of the restrictions to the cosets indexed by a complement `E'`. -/ +theorem sum_walshTransform_sq_perpendicular_eq_card_mul_sum_restrictionImbalance_sq + (f : BooleanFunction n) + (E E' : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hcompl : IsCompl E E') : + (∑ u : FABL.perpendicularSubspace E, + (walshTransform f u.1 : ℝ) ^ 2) = + (Nat.card (FABL.perpendicularSubspace E) : ℝ) * + ∑ a : E', (affineSubspaceRestrictionImbalance f E a.1) ^ 2 := by + have hpoisson := rawPoissonSummationFormula + (autocorrelation f) (FABL.perpendicularSubspace E) 0 0 + rw [FABL.perpendicularSubspace_perpendicularSubspace] at hpoisson + simp_rw [rawFourierTransform_autocorrelation] at hpoisson + have hspectral : + (∑ u : FABL.perpendicularSubspace E, + (walshTransform f u.1 : ℝ) ^ 2) = + (Nat.card (FABL.perpendicularSubspace E) : ℝ) * + ∑ e : E, autocorrelation f e.1 := by + simpa using hpoisson + rw [hspectral, + sum_autocorrelation_submodule_eq_sum_affineSubspaceRestrictionImbalance_sq + f E E' hcompl] + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter02/WalshDivisibility.lean b/CryptBoolean/Carlet/Chapter02/WalshDivisibility.lean new file mode 100644 index 0000000..a9d7b41 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter02/WalshDivisibility.lean @@ -0,0 +1,104 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter02.Fourier +public import FABL.Chapter06.F₂Polynomials.BentDegree + +/-! +# Walsh divisibility and algebraic degree + +Carlet Proposition 11. +-/ + +open scoped BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The normalized Fourier coefficient of the zero-one embedding is obtained +from the sign embedding by the affine relation `f = (1-χ_f)/2`. -/ +theorem vectorFourierCoeff_booleanRealEmbedding_eq + (f : BooleanFunction n) (a : FABL.F₂Cube n) : + FABL.vectorFourierCoeff (FABL.booleanRealEmbedding f) a = + ((if FABL.f₂Support a = ∅ then 1 else 0) - + FABL.vectorFourierCoeff (realSignView f) a) / 2 := by + rw [FABL.vectorFourierCoeff_eq_fourierCoeff_binaryFunctionOnSignCube, + FABL.vectorFourierCoeff_eq_fourierCoeff_binaryFunctionOnSignCube] + rw [show + FABL.binaryFunctionOnSignCube (FABL.booleanRealEmbedding f) = + fun x ↦ + (1 - FABL.binaryFunctionOnSignCube (realSignView f) x) / 2 by + funext x + change FABL.booleanRealEmbedding f ((FABL.binaryCubeSignEquiv n).symm x) = + (1 - FABL.realSignEncodedFunction f + ((FABL.binaryCubeSignEquiv n).symm x)) / 2 + rw [FABL.realSignEncodedFunction_eq_one_sub_two_booleanRealEmbedding] + ring] + exact FABL.fourierCoeff_one_sub_div_two + (FABL.binaryFunctionOnSignCube (realSignView f)) (FABL.f₂Support a) + +/-- Carlet Proposition 11: divisibility of every raw Walsh coefficient by +`2^k` forces algebraic degree at most `n-k+1`. -/ +theorem functionAlgebraicDegree_le_of_two_pow_dvd_walshTransform + (f : BooleanFunction n) (k : ℕ) (_hn : 2 ≤ n) (_hk : 1 ≤ k) + (hkn : k ≤ n) + (hdiv : ∀ a : FABL.F₂Cube n, (2 : ℤ) ^ k ∣ walshTransform f a) : + FABL.functionAlgebraicDegree f ≤ n - k + 1 := by + apply + FABL.functionAlgebraicDegree_le_of_isVectorFourierGranular_booleanRealEmbedding + rw [FABL.isVectorFourierGranular_iff] + intro a + obtain ⟨z, hz⟩ := hdiv a + have hwalsh := walshTransform_eq_two_pow_mul_vectorFourierCoeff f a + rw [hz] at hwalsh + simp only [Int.cast_mul, Int.cast_pow, Int.cast_ofNat] at hwalsh + have hpow : + (2 : ℝ) ^ n = (2 : ℝ) ^ k * (2 : ℝ) ^ (n - k) := by + calc + (2 : ℝ) ^ n = (2 : ℝ) ^ (k + (n - k)) := by + congr 1 + omega + _ = (2 : ℝ) ^ k * (2 : ℝ) ^ (n - k) := pow_add _ _ _ + rw [hpow] at hwalsh + have hscale : + FABL.vectorFourierCoeff (realSignView f) a = + (z : ℝ) * ((2 : ℝ) ^ (n - k))⁻¹ := by + have hcancel : + (z : ℝ) = (2 : ℝ) ^ (n - k) * + FABL.vectorFourierCoeff (realSignView f) a := by + apply mul_left_cancel₀ (by positivity : (2 : ℝ) ^ k ≠ 0) + calc + (2 : ℝ) ^ k * (z : ℝ) = + (2 : ℝ) ^ k * (2 : ℝ) ^ (n - k) * + FABL.vectorFourierCoeff (realSignView f) a := hwalsh + _ = (2 : ℝ) ^ k * + ((2 : ℝ) ^ (n - k) * + FABL.vectorFourierCoeff (realSignView f) a) := by ring + apply (eq_div_iff (by positivity : (2 : ℝ) ^ (n - k) ≠ 0)).2 + calc + FABL.vectorFourierCoeff (realSignView f) a * (2 : ℝ) ^ (n - k) = + (2 : ℝ) ^ (n - k) * + FABL.vectorFourierCoeff (realSignView f) a := mul_comm _ _ + _ = (z : ℝ) := hcancel.symm + rw [vectorFourierCoeff_booleanRealEmbedding_eq, hscale] + by_cases ha : FABL.f₂Support a = ∅ + · refine ⟨(2 : ℤ) ^ (n - k) - z, ?_⟩ + rw [if_pos ha] + simp only [Int.cast_sub, Int.cast_pow, Int.cast_ofNat] + rw [pow_succ] + field_simp + · refine ⟨-z, ?_⟩ + rw [if_neg ha] + simp only [Int.cast_neg] + rw [pow_succ] + field_simp + ring + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter04/ReedMullerCosetDistance.lean b/CryptBoolean/Carlet/Chapter04/ReedMullerCosetDistance.lean index 23426e7..54f9279 100644 --- a/CryptBoolean/Carlet/Chapter04/ReedMullerCosetDistance.lean +++ b/CryptBoolean/Carlet/Chapter04/ReedMullerCosetDistance.lean @@ -23,6 +23,10 @@ namespace CryptBoolean variable {n : ℕ} +noncomputable local instance firstOrderReedMullerFintype : + Fintype (reedMuller 1 n) := + Fintype.ofFinite (reedMuller 1 n) + /-- The minimum Hamming distance between distinct functions in a finite code, with value zero for a code having fewer than two words. -/ noncomputable def minimumHammingDistance @@ -81,6 +85,91 @@ theorem firstOrderCosetUnion_pair ext c simp +/-- A first-order Reed--Muller coset is the translate of the Reed--Muller +submodule by its representative. -/ +theorem firstOrderReedMullerCoset_eq_image + (f : BooleanFunction n) : + firstOrderReedMullerCoset f = + (Finset.univ : Finset (reedMuller 1 n)).image + (fun ell ↦ ell.1 + f) := by + classical + ext c + rw [mem_firstOrderReedMullerCoset_iff] + constructor + · intro hc + rw [Finset.mem_image] + refine ⟨⟨c + f, hc⟩, Finset.mem_univ _, ?_⟩ + ext x + exact CharTwo.add_cancel_right _ _ + · intro hc + rw [Finset.mem_image] at hc + obtain ⟨ell, _hell, rfl⟩ := hc + have hcancel : (ell.1 + f) + f = ell.1 := by + ext x + exact CharTwo.add_cancel_right _ _ + rw [hcancel] + exact ell.2 + +/-- Every first-order Reed--Muller coset has the cardinality of the code. -/ +theorem card_firstOrderReedMullerCoset + (f : BooleanFunction n) : + (firstOrderReedMullerCoset f).card = Nat.card (reedMuller 1 n) := by + classical + rw [firstOrderReedMullerCoset_eq_image, + Finset.card_image_of_injective] + · rw [Finset.card_univ, ← Nat.card_eq_fintype_card] + · intro ell₁ ell₂ h + apply Subtype.ext + exact add_right_cancel h + +/-- A finite union of first-order cosets is the indexed union of its +individual cosets. -/ +theorem firstOrderCosetUnion_eq_biUnion + (F : Finset (BooleanFunction n)) : + firstOrderCosetUnion F = + F.biUnion firstOrderReedMullerCoset := by + classical + ext c + simp + +/-- Distinct representatives give pairwise disjoint first-order cosets. -/ +theorem pairwiseDisjoint_firstOrderReedMullerCoset + {F : Finset (BooleanFunction n)} + (hcosets : HasDistinctFirstOrderCosets F) : + (F : Set (BooleanFunction n)).PairwiseDisjoint + firstOrderReedMullerCoset := by + classical + intro f hf g hg hfg + change Disjoint (firstOrderReedMullerCoset f) + (firstOrderReedMullerCoset g) + rw [Finset.disjoint_left] + intro c hcf hcg + rw [mem_firstOrderReedMullerCoset_iff] at hcf hcg + apply hcosets hf hg hfg + have hsum := (reedMuller 1 n).add_mem hcf hcg + have heq : (c + f) + (c + g) = f + g := by + ext x + simp only [Pi.add_apply] + calc + (c x + f x) + (c x + g x) = + (c x + c x) + (f x + g x) := by ac_rfl + _ = f x + g x := by rw [CharTwo.add_self_eq_zero, zero_add] + rwa [heq] at hsum + +/-- The size of a union of distinct first-order Reed--Muller cosets is the +number of representatives times the size of one coset. -/ +theorem card_firstOrderCosetUnion + {F : Finset (BooleanFunction n)} + (hcosets : HasDistinctFirstOrderCosets F) : + (firstOrderCosetUnion F).card = + F.card * Nat.card (reedMuller 1 n) := by + classical + rw [firstOrderCosetUnion_eq_biUnion, + Finset.card_biUnion + (pairwiseDisjoint_firstOrderReedMullerCoset hcosets)] + simp_rw [card_firstOrderReedMullerCoset] + simp + theorem minimumHammingDistance_le {C : Finset (BooleanFunction n)} (hC : C.offDiag.Nonempty) {f g : BooleanFunction n} (hf : f ∈ C) (hg : g ∈ C) (hfg : f ≠ g) : diff --git a/CryptBoolean/Carlet/Chapter05.lean b/CryptBoolean/Carlet/Chapter05.lean index 6983ac4..38e77b4 100644 --- a/CryptBoolean/Carlet/Chapter05.lean +++ b/CryptBoolean/Carlet/Chapter05.lean @@ -24,5 +24,5 @@ public import CryptBoolean.Carlet.Chapter05.WeilNonlinearityReduction /-! # Carlet Chapter 5 -Classes of Boolean functions with restricted weights, Walsh spectra, and nonlinearities. +Classes with provable spectra and weights. -/ diff --git a/CryptBoolean/Carlet/Chapter05/QuadraticTraceRepresentation.lean b/CryptBoolean/Carlet/Chapter05/QuadraticTraceRepresentation.lean index 013042d..b095b2f 100644 --- a/CryptBoolean/Carlet/Chapter05/QuadraticTraceRepresentation.lean +++ b/CryptBoolean/Carlet/Chapter05/QuadraticTraceRepresentation.lean @@ -25,7 +25,8 @@ open scoped BigOperators BooleanCube namespace CryptBoolean -private noncomputable def binaryFrobeniusLinear (n i : ℕ) : +/-- The `i`th binary Frobenius power as a linear endomorphism. -/ +noncomputable def binaryFrobeniusLinear (n i : ℕ) : BinaryGaloisField n →ₗ[FABL.𝔽₂] BinaryGaloisField n := (FiniteField.frobeniusAlgHom FABL.𝔽₂ (BinaryGaloisField n) ^ i).toLinearMap @@ -34,7 +35,9 @@ private noncomputable def binaryFrobeniusEquiv (n : ℕ) : FiniteField.frobeniusAlgEquivOfAlgebraic FABL.𝔽₂ (BinaryGaloisField n) -private theorem binaryFrobeniusLinear_apply (n i : ℕ) +/-- Evaluation of the linear Frobenius endomorphism is the corresponding +binary power. -/ +theorem binaryFrobeniusLinear_apply (n i : ℕ) (x : BinaryGaloisField n) : binaryFrobeniusLinear n i x = x ^ (2 ^ i) := by change (FiniteField.frobeniusAlgHom FABL.𝔽₂ @@ -108,6 +111,18 @@ private theorem absoluteTrace_mul_binaryFrobeniusLinear rw [binaryFrobeniusAlgEquiv_pow_complement_apply n i hn hi] _ = _ := rfl +/-- The adjoint of the `i`th binary Frobenius power under the absolute-trace +pairing is the complementary Frobenius power. -/ +theorem absoluteTrace_mul_frobeniusPow + (n i : ℕ) (hn : n ≠ 0) (hi : i ≤ n) + (a y : BinaryGaloisField n) : + absoluteTrace n (a * y ^ (2 ^ i)) = + absoluteTrace n (a ^ (2 ^ (n - i)) * y) := by + rw [← binaryFrobeniusLinear_apply n i y, + absoluteTrace_mul_binaryFrobeniusLinear n i hn hi] + rw [← binaryFrobeniusLinear_eq_algEquiv_pow_apply n (n - i) a, + binaryFrobeniusLinear_apply] + private noncomputable def alternatingMapOfBilinForm {V : Type*} [AddCommGroup V] [Module FABL.𝔽₂ V] (B : LinearMap.BilinForm FABL.𝔽₂ V) (hB : B.IsAlt) : @@ -181,7 +196,9 @@ private noncomputable def oddQuadraticPolarAlternating (m : ℕ) x * binaryFrobeniusLinear (2 * m + 1) (i + 1) y)) := by rfl -private noncomputable def oddQuadraticTracePart (m : ℕ) +/-- The homogeneous quadratic part in Carlet's odd-dimensional trace +representation. -/ +noncomputable def oddQuadraticTracePart (m : ℕ) (beta : Fin m → BinaryGaloisField (2 * m + 1)) : FieldBooleanFunction (2 * m + 1) := fun x ↦ absoluteTrace (2 * m + 1) @@ -211,6 +228,25 @@ private theorem oddQuadraticTracePart_polar (m : ℕ) CharP.cast_eq_zero (BinaryGaloisField (2 * m + 1)) 2] simp +/-- The polar form of the odd-dimensional quadratic trace part, written as +the explicit sum of paired Frobenius monomials. -/ +theorem oddQuadraticTracePart_polar_eq_sum (m : ℕ) + (beta : Fin m → BinaryGaloisField (2 * m + 1)) + (x y : BinaryGaloisField (2 * m + 1)) : + oddQuadraticTracePart m beta (x + y) + + oddQuadraticTracePart m beta x + + oddQuadraticTracePart m beta y + + oddQuadraticTracePart m beta 0 = + ∑ i, absoluteTrace (2 * m + 1) + (beta i * + (x ^ (2 ^ ((i : ℕ) + 1)) * y + + x * y ^ (2 ^ ((i : ℕ) + 1)))) := by + rw [oddQuadraticTracePart_polar, + oddQuadraticPolarAlternating_apply] + apply Finset.sum_congr rfl + intro i _hi + rw [binaryFrobeniusLinear_apply, binaryFrobeniusLinear_apply] + private noncomputable def oddQuadraticPolarMap (m : ℕ) : (Fin m → BinaryGaloisField (2 * m + 1)) →ₗ[FABL.𝔽₂] (BinaryGaloisField (2 * m + 1) [⋀^Fin 2]→ₗ[FABL.𝔽₂] FABL.𝔽₂) where @@ -630,7 +666,9 @@ private theorem functionAlgebraicDegree_constant_le_two {n : ℕ} (c : FABL.𝔽 rw [hconstant] simp -private theorem functionAlgebraicDegree_traceMonomial_two_pow_add_one_le_two +/-- A binary trace monomial with exponent `2^i + 1` has algebraic degree at +most two whenever the exponent lies below the field modulus. -/ +theorem functionAlgebraicDegree_traceMonomial_two_pow_add_one_le_two {n i : ℕ} (hn : 0 < n) (hk : 2 ^ i + 1 < 2 ^ n - 1) (theta : FABL.F₂Cube n ≃ₗ[FABL.𝔽₂] BinaryGaloisField n) (a : BinaryGaloisField n) : @@ -643,7 +681,9 @@ private theorem functionAlgebraicDegree_traceMonomial_two_pow_add_one_le_two · rw [functionAlgebraicDegree_traceMonomial hn hk theta a hzero] exact binaryWeight_two_pow_add_one_le_two i -private theorem two_pow_add_one_lt_odd_modulus +/-- The quadratic exponents in the odd-dimensional trace representation lie +strictly below the multiplicative field modulus. -/ +theorem two_pow_add_one_lt_odd_modulus (m : ℕ) (hm : 0 < m) (i : Fin (m + 1)) : 2 ^ (i : ℕ) + 1 < 2 ^ (2 * m + 1) - 1 := by have hi : (i : ℕ) ≤ m := Nat.le_of_lt_succ i.isLt @@ -714,7 +754,9 @@ noncomputable def quadraticTraceMiddleNorm letI := iota.toAlgebra exact Algebra.norm (BinaryGaloisField m) x -private theorem quadraticTraceMiddle_finrank (hm : m ≠ 0) +/-- The explicitly embedded middle field has relative degree two in the +quadratic binary extension. -/ +theorem quadraticTraceMiddle_finrank (hm : m ≠ 0) (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] BinaryGaloisField (2 * m)) : letI := iota.toAlgebra Module.finrank (BinaryGaloisField m) (BinaryGaloisField (2 * m)) = 2 := by diff --git a/CryptBoolean/Carlet/Chapter06.lean b/CryptBoolean/Carlet/Chapter06.lean new file mode 100644 index 0000000..a6670e7 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06.lean @@ -0,0 +1,59 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.Bentness +public import CryptBoolean.Carlet.Chapter06.CompleteQuadratic +public import CryptBoolean.Carlet.Chapter06.DegreeBounds +public import CryptBoolean.Carlet.Chapter06.DegreeRelation +public import CryptBoolean.Carlet.Chapter06.DirectSum +public import CryptBoolean.Carlet.Chapter06.Dual +public import CryptBoolean.Carlet.Chapter06.DualAffine +public import CryptBoolean.Carlet.Chapter06.DualCoefficientDivisibility +public import CryptBoolean.Carlet.Chapter06.DualIsometry +public import CryptBoolean.Carlet.Chapter06.DualNNF +public import CryptBoolean.Carlet.Chapter06.DualPoisson +public import CryptBoolean.Carlet.Chapter06.FlatSwitching +public import CryptBoolean.Carlet.Chapter06.FourierUncertainty +public import CryptBoolean.Carlet.Chapter06.GeometricCharacterization +public import CryptBoolean.Carlet.Chapter06.HyperBent +public import CryptBoolean.Carlet.Chapter06.HyperBentPartialSpread +public import CryptBoolean.Carlet.Chapter06.HyperplaneRestriction +public import CryptBoolean.Carlet.Chapter06.IndirectSum +public import CryptBoolean.Carlet.Chapter06.Kerdock +public import CryptBoolean.Carlet.Chapter06.KerdockCoordinateIdentity +public import CryptBoolean.Carlet.Chapter06.KerdockFieldConstruction +public import CryptBoolean.Carlet.Chapter06.MaioranaMcFarland +public import CryptBoolean.Carlet.Chapter06.MaioranaMcFarlandCounting +public import CryptBoolean.Carlet.Chapter06.MaioranaMcFarlandGeneral +public import CryptBoolean.Carlet.Chapter06.McElieceAx +public import CryptBoolean.Carlet.Chapter06.NNFCharacterization +public import CryptBoolean.Carlet.Chapter06.NestedBent +public import CryptBoolean.Carlet.Chapter06.NormalExtension +public import CryptBoolean.Carlet.Chapter06.PartialBent +public import CryptBoolean.Carlet.Chapter06.PartialBentDual +public import CryptBoolean.Carlet.Chapter06.PartialBentCounterexamples +public import CryptBoolean.Carlet.Chapter06.PartiallyBent +public import CryptBoolean.Carlet.Chapter06.PartialSpreads +public import CryptBoolean.Carlet.Chapter06.PermutationReindex +public import CryptBoolean.Carlet.Chapter06.Plateaued +public import CryptBoolean.Carlet.Chapter06.PlateauedOrphan +public import CryptBoolean.Carlet.Chapter06.PlateauedSecondOrder +public import CryptBoolean.Carlet.Chapter06.PlateauedSupport +public import CryptBoolean.Carlet.Chapter06.QuadraticBent +public import CryptBoolean.Carlet.Chapter06.Rothaus +public import CryptBoolean.Carlet.Chapter06.SecondOrderCharacterization +public import CryptBoolean.Carlet.Chapter06.SupportCode +public import CryptBoolean.Carlet.Chapter06.ThreeFunctionBent +public import CryptBoolean.Carlet.Chapter06.ThreeFunctionIdentity +public import CryptBoolean.Carlet.Chapter06.WalshCongruence + +/-! +# Carlet Chapter 6 + +Bent functions, their duals, constructions, characterizations, superclasses, +and the Kerdock-code parameter layer. +-/ diff --git a/CryptBoolean/Carlet/Chapter06/Bentness.lean b/CryptBoolean/Carlet/Chapter06/Bentness.lean new file mode 100644 index 0000000..040016b --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/Bentness.lean @@ -0,0 +1,195 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter04.DistanceToLinearStructures +public import CryptBoolean.Carlet.Chapter04.PropagationCriteria +public import CryptBoolean.Carlet.Chapter05.QuadraticValues + +/-! +# Bent Boolean functions + +Carlet Definition 7 and Theorem 8: distance, spectrum, affine invariance, and derivatives. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- Every raw Walsh coefficient of a bent Boolean function has magnitude `2^(n/2)`. -/ +theorem natAbs_walshTransform_eq_two_pow_half_of_isBent + (f : BooleanFunction n) (hf : IsBent f) (a : FABL.F₂Cube n) : + (walshTransform f a).natAbs = 2 ^ (n / 2) := by + have hn := even_of_isBent f hf + have hflat := (hasFlatWalshSpectrum_iff_isBent f).2 hf a + rw [sqrt_two_pow_eq_pow_half hn] at hflat + apply Nat.cast_injective (R := ℝ) + simpa only [Nat.cast_natAbs, Int.cast_abs, Nat.cast_pow, Nat.cast_ofNat] + using hflat + +/-- The maximum raw Walsh magnitude of a bent function is `2^(n/2)`. -/ +theorem maxWalshMagnitude_eq_two_pow_half_of_isBent + (f : BooleanFunction n) (hf : IsBent f) : + maxWalshMagnitude f = 2 ^ (n / 2) := by + unfold maxWalshMagnitude + simp_rw [natAbs_walshTransform_eq_two_pow_half_of_isBent f hf] + simp + +/-- In positive even dimension, a bent function attains Carlet's integral +nonlinearity value `2^(n-1)-2^(n/2-1)`. -/ +theorem nonlinearity_eq_two_pow_sub_two_pow_half_of_isBent + (f : BooleanFunction n) (hf : IsBent f) (hn : 2 ≤ n) : + nonlinearity f = 2 ^ (n - 1) - 2 ^ (n / 2 - 1) := by + have heven := even_of_isBent f hf + have hhalf : 1 ≤ n / 2 := by + rcases heven with ⟨k, hk⟩ + omega + have hrelation := two_mul_nonlinearity_add_maxWalshMagnitude f + rw [maxWalshMagnitude_eq_two_pow_half_of_isBent f hf] at hrelation + have hnPow : 2 ^ n = 2 * 2 ^ (n - 1) := by + obtain ⟨m, rfl⟩ := Nat.exists_eq_succ_of_ne_zero (by omega : n ≠ 0) + simp [pow_succ, Nat.mul_comm] + have hhalfPow : 2 ^ (n / 2) = 2 * 2 ^ (n / 2 - 1) := by + obtain ⟨m, hm⟩ := Nat.exists_eq_succ_of_ne_zero (by omega : n / 2 ≠ 0) + rw [hm] + simp [pow_succ, Nat.mul_comm] + rw [hnPow, hhalfPow] at hrelation + omega + +/-- Bentness is equivalent to the exact raw Walsh magnitude at every frequency. -/ +theorem isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half + (f : BooleanFunction n) : + IsBent f ↔ ∀ a, (walshTransform f a).natAbs = 2 ^ (n / 2) := by + constructor + · intro hf a + exact natAbs_walshTransform_eq_two_pow_half_of_isBent f hf a + · intro h + apply (hasFlatWalshSpectrum_iff_isBent f).1 + have hn : Even n := by + have hparseval := sum_walshTransform_sq_eq_two_pow_sq f + have hsum : + (∑ a : FABL.F₂Cube n, (walshTransform f a : ℝ) ^ 2) = + (2 : ℝ) ^ n * ((2 : ℝ) ^ (n / 2)) ^ 2 := by + calc + (∑ a : FABL.F₂Cube n, (walshTransform f a : ℝ) ^ 2) = + ∑ _a : FABL.F₂Cube n, ((2 : ℝ) ^ (n / 2)) ^ 2 := by + apply Finset.sum_congr rfl + intro a _ha + have ha : |(walshTransform f a : ℝ)| = + (2 : ℝ) ^ (n / 2) := by + have haCast := congrArg (fun k : ℕ ↦ (k : ℝ)) (h a) + simpa only [Nat.cast_natAbs, Int.cast_abs, Nat.cast_pow, + Nat.cast_ofNat] using haCast + rw [← sq_abs, ha] + _ = (2 : ℝ) ^ n * ((2 : ℝ) ^ (n / 2)) ^ 2 := by + rw [Finset.sum_const, Finset.card_univ, card_f₂Cube, + nsmul_eq_mul] + norm_num + rw [hsum] at hparseval + have hsquares : ((2 : ℝ) ^ (n / 2)) ^ 2 = (2 : ℝ) ^ n := by + apply mul_left_cancel₀ (by positivity : (2 : ℝ) ^ n ≠ 0) + calc + (2 : ℝ) ^ n * ((2 : ℝ) ^ (n / 2)) ^ 2 = + ((2 : ℝ) ^ n) ^ 2 := hparseval + _ = (2 : ℝ) ^ n * (2 : ℝ) ^ n := by ring + have hsquaresNat : ((2 : ℕ) ^ (n / 2)) ^ 2 = 2 ^ n := by + exact_mod_cast hsquares + have hnEq : 2 * (n / 2) = n := by + apply Nat.pow_right_injective (by omega : 2 ≤ 2) + calc + 2 ^ (2 * (n / 2)) = ((2 : ℕ) ^ (n / 2)) ^ 2 := by + rw [Nat.mul_comm, pow_mul] + _ = 2 ^ n := hsquaresNat + exact ⟨n / 2, by omega⟩ + intro a + rw [sqrt_two_pow_eq_pow_half hn] + have haCast := congrArg (fun k : ℕ ↦ (k : ℝ)) (h a) + simpa only [Nat.cast_natAbs, Int.cast_abs, Nat.cast_pow, + Nat.cast_ofNat] using haCast + +/-- Adding an affine Boolean function preserves bentness. -/ +theorem isBent_add_affineFunction_iff + (f : BooleanFunction n) (b : FABL.𝔽₂) (a : FABL.F₂Cube n) : + IsBent (f + FABL.affineFunction b a) ↔ IsBent f := by + rw [← nonlinearity_cast_eq_relation_36_iff_isBent, + ← nonlinearity_cast_eq_relation_36_iff_isBent, + nonlinearity_add_affineFunction] + +/-- Precomposition by an affine automorphism preserves bentness. -/ +theorem isBent_comp_affineEquiv_iff + (f : BooleanFunction n) + (L : FABL.F₂Cube n ≃ᵃ[FABL.𝔽₂] FABL.F₂Cube n) : + IsBent (f ∘ L) ↔ IsBent f := by + rw [← nonlinearity_cast_eq_relation_36_iff_isBent, + ← nonlinearity_cast_eq_relation_36_iff_isBent, + nonlinearity_comp_affineEquiv] + +/-- Every affine distance from a bent function differs from half the cube size by +`2^(n/2-1)`. -/ +theorem abs_hammingDistance_affine_sub_half_of_isBent + (f : BooleanFunction n) (hf : IsBent f) + (b : FABL.𝔽₂) (a : FABL.F₂Cube n) : + |(hammingDistance f (FABL.affineFunction b a) : ℝ) - + (2 : ℝ) ^ n / 2| = (2 : ℝ) ^ (n / 2) / 2 := by + rw [hammingDistance_cast_affineFunction_eq] + have hwalsh : |(walshTransform f a : ℝ)| = (2 : ℝ) ^ (n / 2) := by + have hwalshCast := congrArg (fun k : ℕ ↦ (k : ℝ)) + (natAbs_walshTransform_eq_two_pow_half_of_isBent f hf a) + simpa only [Nat.cast_natAbs, Int.cast_abs, Nat.cast_pow, + Nat.cast_ofNat] using hwalshCast + have hsign : |(bitSignInt b : ℝ)| = 1 := by + have hsignNat : (bitSignInt b).natAbs = 1 := by + rw [bitSignInt_eq_if_one] + split <;> simp + have hsignCast := congrArg (fun k : ℕ ↦ (k : ℝ)) hsignNat + simpa only [Nat.cast_natAbs, Int.cast_abs, Nat.cast_one] using hsignCast + rw [sub_sub_cancel_left, abs_neg, abs_div, abs_mul, hsign, one_mul, + hwalsh] + norm_num + +/-- Carlet Theorem 8: a Boolean function is bent exactly when every nonzero +directional derivative is balanced. -/ +theorem isBent_iff_forall_nonzero_derivative_isBalanced + (f : BooleanFunction n) : + IsBent f ↔ + ∀ a : FABL.F₂Cube n, a ≠ 0 → + IsBalanced (FABL.booleanDerivative f a) := by + rw [← absoluteIndicator_eq_zero_iff_isBent] + constructor + · intro habsolute a ha + apply (isBalanced_booleanDerivative_iff_autocorrelation_eq_zero f a).2 + have hle := abs_autocorrelation_le_absoluteIndicator f ha + rw [habsolute] at hle + exact abs_eq_zero.mp (le_antisymm hle (abs_nonneg _)) + · intro h + unfold absoluteIndicator + apply NNReal.coe_eq_zero.mpr + rw [Finset.sup_eq_zero] + intro a ha + have hne := (Finset.mem_erase.mp ha).1 + have hzero := + (isBalanced_booleanDerivative_iff_autocorrelation_eq_zero f a).1 (h a hne) + rw [hzero, abs_zero, Real.toNNReal_zero] + +/-- Carlet's `PC(n)` formulation of Theorem 8. -/ +theorem isBent_iff_satisfiesPropagationCriterion_dimension + (f : BooleanFunction n) : + IsBent f ↔ SatisfiesPropagationCriterion n f := by + rw [isBent_iff_forall_nonzero_derivative_isBalanced, + SatisfiesPropagationCriterion, SatisfiesPropagationCriterionOn] + constructor + · intro h a ha + exact h a ha.1 + · intro h a ha + have hcard : (FABL.f₂Support a).card ≤ n := by + simpa using Finset.card_le_card (Finset.subset_univ (FABL.f₂Support a)) + exact h a ⟨ha, hcard⟩ + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/CompleteQuadratic.lean b/CryptBoolean/Carlet/Chapter06/CompleteQuadratic.lean new file mode 100644 index 0000000..7c17e85 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/CompleteQuadratic.lean @@ -0,0 +1,337 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.QuadraticBent +public import FABL.Chapter06.F₂Polynomials.CompleteQuadraticDecomposition +public import Mathlib.Data.Sym.Card + +/-! +# Carlet Chapter 6 complete quadratic bent function + +Relation (56), its Hamming-weight description, and the triviality of the +polar radical in even dimension. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The complete quadratic function has algebraic degree at most two. -/ +theorem functionAlgebraicDegree_completeQuadraticBit_le_two : + FABL.functionAlgebraicDegree + (FABL.completeQuadraticBit : BooleanFunction n) ≤ 2 := by + classical + have hfunction : + (FABL.completeQuadraticBit : BooleanFunction n) = + ∑ i : Fin n, ∑ j ∈ Finset.Ioi i, + FABL.anfMonomial ({i, j} : Finset (Fin n)) := by + funext x + rw [FABL.completeQuadraticBit] + simp only [Finset.sum_apply] + apply Finset.sum_congr rfl + intro i _hi + apply Finset.sum_congr rfl + intro j hj + have hij : i ≠ j := ne_of_lt (Finset.mem_Ioi.mp hj) + rw [FABL.anfMonomial, Finset.prod_pair hij] + rw [hfunction] + apply FABL.functionAlgebraicDegree_finset_sum_le Finset.univ _ 2 + intro i _hi + apply FABL.functionAlgebraicDegree_finset_sum_le (Finset.Ioi i) _ 2 + intro j _hj + exact (FABL.functionAlgebraicDegree_anfMonomial_le_card + ({i, j} : Finset (Fin n))).trans Finset.card_le_two + +/-- Relation (56): the complete quadratic value is the parity of the number +of unordered pairs in the support, namely `choose(weight, 2)` modulo two. -/ +theorem completeQuadraticBit_eq_choose_support_card + (x : FABL.F₂Cube n) : + FABL.completeQuadraticBit x = + (Nat.choose (FABL.f₂Support x).card 2 : FABL.𝔽₂) := by + classical + let pairProduct : Sym2 (Fin n) → FABL.𝔽₂ := + Sym2.lift ⟨fun i j ↦ x i * x j, fun i j ↦ mul_comm (x i) (x j)⟩ + let allPairs : Finset (Sym2 (Fin n)) := + (Finset.univ : Finset (Fin n)).sym2.filter fun q ↦ ¬q.IsDiag + let supportPairs : Finset (Sym2 (Fin n)) := + (FABL.f₂Support x).sym2.filter fun q ↦ ¬q.IsDiag + have hsym : + FABL.completeQuadraticBit x = ∑ q ∈ allPairs, pairProduct q := by + dsimp only [allPairs] + rw [Finset.sum_sym2_filter_not_isDiag, FABL.completeQuadraticBit] + calc + (∑ i : Fin n, ∑ j ∈ Finset.Ioi i, x i * x j) = + ∑ i : Fin n, ∑ j : Fin n, + if i < j then x i * x j else 0 := by + apply Finset.sum_congr rfl + intro i _hi + rw [← Finset.sum_filter] + apply Finset.sum_congr + · ext j + simp + · intro j hj + simp only [Finset.mem_filter, Finset.mem_univ, true_and] at hj + rfl + _ = ∑ ij : Fin n × Fin n, + if ij.1 < ij.2 then x ij.1 * x ij.2 else 0 := by + rw [Fintype.sum_prod_type] + _ = ∑ ij ∈ + (Finset.univ : Finset (Fin n × Fin n)).filter + (fun ij ↦ ij.1 < ij.2), + pairProduct s(ij.1, ij.2) := by + rw [← Finset.sum_filter] + apply Finset.sum_congr rfl + intro ij _hij + by_cases hij : ij.1 < ij.2 + · simp [pairProduct] + · rfl + _ = ∑ ij ∈ + (Finset.univ : Finset (Fin n)).offDiag.filter + (fun ij ↦ ij.1 < ij.2), + pairProduct s(ij.1, ij.2) := by + congr 1 + ext ij + simp only [Finset.mem_filter, Finset.mem_univ, + Finset.mem_offDiag, true_and] + constructor + · intro hij + exact ⟨hij.ne, hij⟩ + · exact fun hij ↦ hij.2 + have hpairProduct (q : Sym2 (Fin n)) : + pairProduct q = + if q ∈ (FABL.f₂Support x).sym2 then 1 else 0 := by + induction q using Sym2.inductionOn with + | _ i j => + by_cases hi : x i = 0 + · simp [pairProduct, hi, FABL.mem_f₂Support] + · have hiOne : x i = 1 := Fin.eq_one_of_ne_zero (x i) hi + by_cases hj : x j = 0 + · simp [pairProduct, hi, hj, FABL.mem_f₂Support] + · have hjOne : x j = 1 := Fin.eq_one_of_ne_zero (x j) hj + simp [pairProduct, hiOne, hjOne, FABL.mem_f₂Support] + have hsum : + (∑ q ∈ allPairs, pairProduct q) = + ∑ _q ∈ supportPairs, (1 : FABL.𝔽₂) := by + calc + (∑ q ∈ allPairs, pairProduct q) = + ∑ q ∈ allPairs, + if q ∈ (FABL.f₂Support x).sym2 then 1 else 0 := by + apply Finset.sum_congr rfl + intro q _hq + exact hpairProduct q + _ = ∑ _q ∈ + allPairs.filter (fun q ↦ q ∈ (FABL.f₂Support x).sym2), + (1 : FABL.𝔽₂) := by + exact (Finset.sum_filter (s := allPairs) + (p := fun q ↦ q ∈ (FABL.f₂Support x).sym2) + (f := fun _q ↦ (1 : FABL.𝔽₂))).symm + _ = ∑ _q ∈ supportPairs, (1 : FABL.𝔽₂) := by + congr 1 + ext q + simpa only [allPairs, supportPairs, Finset.mem_filter, + Finset.sym2_univ, Finset.mem_univ, true_and] using + (and_comm : + (¬q.IsDiag ∧ q ∈ (FABL.f₂Support x).sym2) ↔ + q ∈ (FABL.f₂Support x).sym2 ∧ ¬q.IsDiag) + have hcard : + supportPairs.card = Nat.choose (FABL.f₂Support x).card 2 := by + dsimp only [supportPairs] + rw [Finset.sym2_eq_image, Sym2.filter_image_mk_not_isDiag, + Sym2.card_image_offDiag] + rw [hsym, hsum, ← hcard] + simp + +/-- The coefficient vector representing the polar form of the complete +quadratic function in its second argument. -/ +def completeQuadraticPolarFrequency (a : FABL.F₂Cube n) : FABL.F₂Cube n := + fun i ↦ ∑ j ∈ ({i} : Finset (Fin n))ᶜ, a j + +/-- The polar kernel of the complete quadratic function is the sum of its +mixed quadratic terms. -/ +theorem quadraticPolarKernel_completeQuadraticBit_eq_crossSum + (a b : FABL.F₂Cube n) : + quadraticPolarKernel + (FABL.completeQuadraticBit : BooleanFunction n) a b = + ∑ i : Fin n, ∑ j ∈ Finset.Ioi i, + (a i * b j + b i * a j) := by + rw [quadraticPolarKernel_eq] + simp only [FABL.completeQuadraticBit, Pi.add_apply, add_mul, mul_add, + Finset.sum_add_distrib, Pi.zero_apply, zero_mul, Finset.sum_const_zero, + add_zero] + ring_nf + simp only [CharTwo.two_eq_zero, mul_zero, zero_add, add_zero] + +/-- The polar form of the complete quadratic function is represented by the +sum of all coordinates other than the indexed coordinate. -/ +theorem quadraticPolarKernel_completeQuadraticBit_eq_dotProduct + (a b : FABL.F₂Cube n) : + quadraticPolarKernel + (FABL.completeQuadraticBit : BooleanFunction n) a b = + FABL.f₂DotProduct (completeQuadraticPolarFrequency a) b := by + classical + rw [quadraticPolarKernel_completeQuadraticBit_eq_crossSum, + FABL.f₂DotProduct, dotProduct] + simp only [completeQuadraticPolarFrequency] + have hupper : + (∑ i : Fin n, ∑ j ∈ Finset.Ioi i, b i * a j) = + ∑ i : Fin n, (∑ j ∈ Finset.Ioi i, a j) * b i := by + apply Finset.sum_congr rfl + intro i _hi + rw [← Finset.mul_sum] + ring + have hlower : + (∑ i : Fin n, ∑ j ∈ Finset.Ioi i, a i * b j) = + ∑ j : Fin n, (∑ i ∈ Finset.Iio j, a i) * b j := by + calc + (∑ i : Fin n, ∑ j ∈ Finset.Ioi i, a i * b j) = + ∑ i : Fin n, ∑ j : Fin n, + if i < j then a i * b j else 0 := by + apply Finset.sum_congr rfl + intro i _hi + rw [← Finset.sum_filter] + apply Finset.sum_congr + · ext j + simp + · intro j _hj + rfl + _ = ∑ j : Fin n, ∑ i : Fin n, + if i < j then a i * b j else 0 := by + rw [Finset.sum_comm] + _ = ∑ j : Fin n, (∑ i ∈ Finset.Iio j, a i) * b j := by + apply Finset.sum_congr rfl + intro j _hj + rw [← Finset.sum_filter] + have hfilter : + (Finset.univ.filter fun i : Fin n ↦ i < j) = + Finset.Iio j := by + ext i + simp + rw [hfilter, Finset.sum_mul] + calc + (∑ i : Fin n, ∑ j ∈ Finset.Ioi i, + (a i * b j + b i * a j)) = + (∑ i : Fin n, ∑ j ∈ Finset.Ioi i, b i * a j) + + ∑ i : Fin n, ∑ j ∈ Finset.Ioi i, a i * b j := by + simp only [Finset.sum_add_distrib] + abel + _ = ∑ i : Fin n, + ((∑ j ∈ Finset.Ioi i, a j) + + ∑ j ∈ Finset.Iio i, a j) * b i := by + rw [hupper, hlower, ← Finset.sum_add_distrib] + apply Finset.sum_congr rfl + intro i _hi + ring + _ = ∑ i : Fin n, + (∑ j ∈ ({i} : Finset (Fin n))ᶜ, a j) * b i := by + apply Finset.sum_congr rfl + intro i _hi + rw [← Finset.sum_disjUnion (Finset.disjoint_Ioi_Iio i), + Finset.Ioi_disjUnion_Iio] + +/-- In even dimension the polar-frequency map of the complete quadratic +function has trivial kernel. -/ +theorem completeQuadraticPolarFrequency_eq_zero_of_even + (hn : Even n) {a : FABL.F₂Cube n} + (ha : completeQuadraticPolarFrequency a = 0) : + a = 0 := by + classical + let total : FABL.𝔽₂ := ∑ i, a i + have haTotal (i : Fin n) : a i = total := by + have hi := congrFun ha i + change (∑ j ∈ ({i} : Finset (Fin n))ᶜ, a j) = 0 at hi + have huniv : + (∑ j : Fin n, a j) = + a i + ∑ j ∈ ({i} : Finset (Fin n))ᶜ, a j := by + rw [← Finset.sum_add_sum_compl ({i} : Finset (Fin n))] + simp + rw [hi, add_zero] at huniv + simpa only [total] using huniv.symm + have htotal : total = 0 := by + calc + total = ∑ i : Fin n, a i := rfl + _ = ∑ _i : Fin n, total := by + apply Finset.sum_congr rfl + intro i _hi + exact haTotal i + _ = n • total := by simp + _ = 0 := by + rcases hn with ⟨k, rfl⟩ + rw [add_nsmul] + exact CharTwo.add_self_eq_zero _ + funext i + rw [haTotal i, htotal] + rfl + +/-- In even dimension the polar radical of the complete quadratic function is +trivial. -/ +theorem quadraticRadical_completeQuadraticBit_eq_bot (hn : Even n) : + quadraticRadical + (FABL.completeQuadraticBit : BooleanFunction n) + functionAlgebraicDegree_completeQuadraticBit_le_two = ⊥ := by + classical + ext a + constructor + · intro ha + have hpolar := + (mem_quadraticRadical_iff + (FABL.completeQuadraticBit : BooleanFunction n) + functionAlgebraicDegree_completeQuadraticBit_le_two a).mp ha + have hfrequency : completeQuadraticPolarFrequency a = 0 := by + funext i + have hi := hpolar (Pi.single i (1 : FABL.𝔽₂)) + rw [quadraticPolarKernel_completeQuadraticBit_eq_dotProduct] at hi + simpa [FABL.f₂DotProduct, dotProduct_single] using hi + have haZero := + completeQuadraticPolarFrequency_eq_zero_of_even hn hfrequency + simp [haZero] + · intro ha + have haZero : a = 0 := by simpa using ha + subst a + exact Submodule.zero_mem _ + +/-- FABL's complete quadratic Boolean function is bent in every even +dimension, including the zero-dimensional boundary. -/ +theorem isBent_completeQuadraticBit (hn : Even n) : + IsBent (FABL.completeQuadraticBit : BooleanFunction n) := by + exact (isBent_iff_quadraticRadical_eq_bot + (FABL.completeQuadraticBit : BooleanFunction n) + functionAlgebraicDegree_completeQuadraticBit_le_two).2 + (quadraticRadical_completeQuadraticBit_eq_bot hn) + +/-- In dimension zero Relation (56) is the empty sum. -/ +@[simp] theorem completeQuadraticBit_zero_dimension + (x : FABL.F₂Cube 0) : + FABL.completeQuadraticBit x = 0 := by + simp [FABL.completeQuadraticBit] + +/-- The zero-dimensional complete quadratic function is bent under the +zero-dimensional convention for bent functions. -/ +theorem isBent_completeQuadraticBit_zero_dimension : + IsBent (FABL.completeQuadraticBit : BooleanFunction 0) := + isBent_completeQuadraticBit (Even.zero) + +/-- In dimension two Relation (56) consists of its single quadratic +monomial. -/ +@[simp] theorem completeQuadraticBit_two_dimension + (x : FABL.F₂Cube 2) : + FABL.completeQuadraticBit x = x 0 * x 1 := by + have hzero : Finset.Ioi (0 : Fin 2) = {1} := by decide + have hone : Finset.Ioi (1 : Fin 2) = ∅ := by decide + rw [FABL.completeQuadraticBit, Fin.sum_univ_two, hzero, hone] + simp + +/-- The first positive-dimensional instance of Relation (56) is bent. -/ +theorem isBent_completeQuadraticBit_two_dimension : + IsBent (FABL.completeQuadraticBit : BooleanFunction 2) := + isBent_completeQuadraticBit (by decide) + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/DegreeBounds.lean b/CryptBoolean/Carlet/Chapter06/DegreeBounds.lean new file mode 100644 index 0000000..a92c8c0 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/DegreeBounds.lean @@ -0,0 +1,46 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.Bentness +public import FABL.Chapter06.F₂Polynomials.BentDegree + +/-! +# Algebraic degree of bent functions + +Carlet Proposition 18: Rothaus' bound and the two-variable exceptional case. +-/ + +open scoped BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- Carlet Proposition 18: in even dimension at least four, the algebraic +degree of a bent Boolean function is at most half the dimension. -/ +theorem functionAlgebraicDegree_le_half_of_isBent + (f : BooleanFunction n) (hf : IsBent f) (hn : 4 ≤ n) : + FABL.functionAlgebraicDegree f ≤ n / 2 := + FABL.functionAlgebraicDegree_le_half_of_isBent f + (even_of_isBent f hf) (by omega) hf + +/-- Every two-variable bent Boolean function has algebraic degree two. -/ +theorem functionAlgebraicDegree_eq_two_of_isBent + (f : BooleanFunction 2) (hf : IsBent f) : + FABL.functionAlgebraicDegree f = 2 := by + apply Nat.le_antisymm (FABL.functionAlgebraicDegree_le_dimension f) + by_contra hdegree + have hdegreeOne : FABL.functionAlgebraicDegree f ≤ 1 := by omega + obtain ⟨b, a, hfa⟩ := + FABL.exists_affineFunction_of_functionAlgebraicDegree_le_one f hdegreeOne + have hrelation := (nonlinearity_cast_eq_relation_36_iff_isBent f).2 hf + rw [hfa, nonlinearity_affineFunction] at hrelation + norm_num at hrelation + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/DegreeRelation.lean b/CryptBoolean/Carlet/Chapter06/DegreeRelation.lean new file mode 100644 index 0000000..e5f7538 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/DegreeRelation.lean @@ -0,0 +1,388 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter04.AlgebraicImmunityBounds +public import CryptBoolean.Carlet.Chapter06.DegreeBounds +public import CryptBoolean.Carlet.Chapter06.DualPoisson +public import CryptBoolean.Carlet.Chapter06.GeometricCharacterization +public import CryptBoolean.Carlet.Chapter06.McElieceAx + +import FABL.Chapter05.DegreeOneWeight + +/-! +# Algebraic degrees of a bent function and its dual + +Carlet Proposition 19 and Relation (47), obtained from Poisson summation +and the McEliece--Ax divisibility theorem. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +attribute [local instance] submoduleFintype + +private theorem two_le_functionAlgebraicDegree_of_isBent + (f : BooleanFunction n) (hf : IsBent f) (hn : 2 ≤ n) : + 2 ≤ FABL.functionAlgebraicDegree f := by + by_contra hnot + have hdegreeOne : FABL.functionAlgebraicDegree f ≤ 1 := by omega + obtain ⟨b, a, hfa⟩ := + FABL.exists_affineFunction_of_functionAlgebraicDegree_le_one f hdegreeOne + have hnonlinearity := nonlinearity_eq_two_pow_sub_two_pow_half_of_isBent f hf hn + rw [hfa, nonlinearity_affineFunction] at hnonlinearity + have hhalfLt : n / 2 - 1 < n - 1 := by + have heven := even_of_isBent f hf + rcases heven with ⟨k, hk⟩ + omega + have hpowLt : 2 ^ (n / 2 - 1) < 2 ^ (n - 1) := + Nat.pow_lt_pow_right (by omega) hhalfLt + omega + +private noncomputable def perpendicularCoordinateZeroSubspacePowersetEquiv + (I : Finset (Fin n)) : + FABL.perpendicularSubspace + (FABL.F₂DecisionTree.coordinateZeroSubspace I) ≃ + ↥I.powerset := + Equiv.subtypeEquiv (FABL.f₂CubeEquivFinset n) fun x ↦ by + rw [FABL.mem_perpendicular_coordinateZeroSubspace_iff_f₂Support_subset, + Finset.mem_powerset, FABL.f₂CubeEquivFinset_apply] + +private theorem sum_bitSignInt_perpendicular_coordinateZeroSubspace_eq_powerset + (f : BooleanFunction n) (I : Finset (Fin n)) : + (∑ x : FABL.perpendicularSubspace + (FABL.F₂DecisionTree.coordinateZeroSubspace I), + bitSignInt (f x.1)) = + ∑ T ∈ I.powerset, bitSignInt (f (FABL.f₂CubeOfFinset T)) := by + classical + calc + (∑ x : FABL.perpendicularSubspace + (FABL.F₂DecisionTree.coordinateZeroSubspace I), + bitSignInt (f x.1)) = + ∑ T : ↥I.powerset, + bitSignInt (f (FABL.f₂CubeOfFinset T.1)) := by + apply Fintype.sum_equiv + (perpendicularCoordinateZeroSubspacePowersetEquiv I) + intro x + congr 2 + simpa [perpendicularCoordinateZeroSubspacePowersetEquiv] using + (FABL.f₂CubeEquivFinset n).symm_apply_apply x.1 |>.symm + _ = ∑ T ∈ I.powerset, + bitSignInt (f (FABL.f₂CubeOfFinset T)) := by + symm + exact Finset.sum_subtype I.powerset (fun T ↦ Iff.rfl) + (fun T ↦ bitSignInt (f (FABL.f₂CubeOfFinset T))) + +private def anfPowersetOneCount + (f : BooleanFunction n) (I : Finset (Fin n)) : ℕ := + (I.powerset.filter fun T ↦ f (FABL.f₂CubeOfFinset T) = 1).card + +private theorem odd_anfPowersetOneCount_of_anfCoeff_ne_zero + (f : BooleanFunction n) (I : Finset (Fin n)) + (hcoeff : FABL.anfCoeff f I ≠ 0) : + Odd (anfPowersetOneCount f I) := by + classical + have hcast : ((anfPowersetOneCount f I : ℕ) : FABL.𝔽₂) = + FABL.anfCoeff f I := by + rw [anfPowersetOneCount, Finset.card_filter] + change ((∑ T ∈ I.powerset, + if f (FABL.f₂CubeOfFinset T) = 1 then 1 else 0 : ℕ) : FABL.𝔽₂) = _ + push_cast + rw [FABL.anfCoeff] + apply Finset.sum_congr rfl + intro T _hT + by_cases hTzero : f (FABL.f₂CubeOfFinset T) = 0 + · simp [hTzero] + · have hTone : f (FABL.f₂CubeOfFinset T) = 1 := + Fin.eq_one_of_ne_zero _ hTzero + simp [hTone] + rw [← ZMod.natCast_ne_zero_iff_odd] + simpa [hcast] using hcoeff + +private theorem sum_bitSignInt_powerset_eq + (f : BooleanFunction n) (I : Finset (Fin n)) : + (∑ T ∈ I.powerset, bitSignInt (f (FABL.f₂CubeOfFinset T))) = + (2 : ℤ) ^ I.card - 2 * (anfPowersetOneCount f I : ℤ) := by + classical + simp_rw [bitSignInt_eq_one_sub_two_mul_bitValueInt] + rw [Finset.sum_sub_distrib, Finset.sum_const, Finset.card_powerset, + nsmul_eq_mul, mul_one, ← Finset.mul_sum] + have hcount : + (∑ T ∈ I.powerset, bitValueInt (f (FABL.f₂CubeOfFinset T))) = + (anfPowersetOneCount f I : ℤ) := by + rw [anfPowersetOneCount, Finset.card_filter] + change (∑ T ∈ I.powerset, bitValueInt (f (FABL.f₂CubeOfFinset T))) = + ((∑ T ∈ I.powerset, + if f (FABL.f₂CubeOfFinset T) = 1 then 1 else 0 : ℕ) : ℤ) + push_cast + apply Finset.sum_congr rfl + intro T _hT + by_cases hTone : f (FABL.f₂CubeOfFinset T) = 1 <;> + simp [bitValueInt, hTone] + rw [hcount] + norm_num + +private theorem exact_two_divisibility_perpendicular_coordinateZeroSubspace + (f : BooleanFunction n) (I : Finset (Fin n)) + (hcoeff : FABL.anfCoeff f I ≠ 0) (hIcard : 2 ≤ I.card) : + ((2 : ℤ) ∣ ∑ x : FABL.perpendicularSubspace + (FABL.F₂DecisionTree.coordinateZeroSubspace I), bitSignInt (f x.1)) ∧ + ¬((4 : ℤ) ∣ ∑ x : FABL.perpendicularSubspace + (FABL.F₂DecisionTree.coordinateZeroSubspace I), bitSignInt (f x.1)) := by + classical + let w := anfPowersetOneCount f I + have hodd : Odd w := odd_anfPowersetOneCount_of_anfCoeff_ne_zero f I hcoeff + have hsum : + (∑ x : FABL.perpendicularSubspace + (FABL.F₂DecisionTree.coordinateZeroSubspace I), bitSignInt (f x.1)) = + (2 : ℤ) ^ I.card - 2 * (w : ℤ) := by + rw [sum_bitSignInt_perpendicular_coordinateZeroSubspace_eq_powerset, + sum_bitSignInt_powerset_eq] + have hpowTwo : (2 : ℤ) ^ I.card = + 2 * (2 : ℤ) ^ (I.card - 1) := by + conv_lhs => + rw [show I.card = (I.card - 1) + 1 by omega] + rw [pow_succ] + ring + have hpowFour : (2 : ℤ) ^ I.card = + 4 * (2 : ℤ) ^ (I.card - 2) := by + conv_lhs => + rw [show I.card = (I.card - 2) + 2 by omega] + rw [pow_add] + norm_num + ring + constructor + · refine ⟨(2 : ℤ) ^ (I.card - 1) - (w : ℤ), ?_⟩ + rw [hsum, hpowTwo] + ring + · rintro ⟨z, hz⟩ + obtain ⟨q, hq⟩ := hodd + have hqInt : (w : ℤ) = 2 * (q : ℤ) + 1 := by + exact_mod_cast hq + rw [hsum, hpowFour, hqInt] at hz + omega + +private theorem bitSignInt_cast_eq_realSignView + (f : BooleanFunction n) (x : FABL.F₂Cube n) : + (bitSignInt (f x) : ℝ) = realSignView f x := by + rw [bitSignInt_cast] + simp [realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction, FABL.signValue_signEncode_eq_binarySign] + +private theorem bentDual_sum_coordinateZeroSubspace + (f : BooleanFunction n) (hf : IsBent f) (I : Finset (Fin n)) + (hIhalf : I.card ≤ n / 2) : + (∑ u : FABL.F₂DecisionTree.coordinateZeroSubspace I, + bitSignInt (bentDual f u.1)) = + (2 : ℤ) ^ (n / 2 - I.card) * + ∑ x : FABL.perpendicularSubspace + (FABL.F₂DecisionTree.coordinateZeroSubspace I), + bitSignInt (f x.1) := by + classical + let E := FABL.F₂DecisionTree.coordinateZeroSubspace I + have heven := even_of_isBent f hf + have hsplit : n = n / 2 + n / 2 := by + rcases heven with ⟨k, hk⟩ + omega + have hfinrank : Module.finrank FABL.𝔽₂ E = n - I.card := by + simpa [E] using finrank_coordinateZeroSubspace I + have hscalar : + ((2 : ℝ) ^ (n / 2))⁻¹ * (Fintype.card E : ℝ) = + (2 : ℝ) ^ (n / 2 - I.card) := by + rw [← Nat.card_eq_fintype_card, + FABL.card_submodule_eq_two_pow_finrank, hfinrank] + push_cast + rw [show n - I.card = n / 2 + (n / 2 - I.card) by omega, + pow_add] + field_simp + have hpoisson := bentDual_poissonSummationFormula f hf E 0 0 + have hreal : + (∑ u : E, realSignView (bentDual f) u.1) = + (2 : ℝ) ^ (n / 2 - I.card) * + ∑ x : FABL.perpendicularSubspace E, realSignView f x.1 := by + simpa [hscalar] using hpoisson + apply Int.cast_injective (α := ℝ) + push_cast + simpa [E, bitSignInt_cast_eq_realSignView] using hreal + +private theorem two_pow_ceilDiv_dualDegree_dvd_coordinateZeroSubspace_sum + (f : BooleanFunction n) (hf : IsBent f) (hn : 2 ≤ n) + (I : Finset (Fin n)) : + (2 : ℤ) ^ ((n - I.card) ⌈/⌉ + FABL.functionAlgebraicDegree (bentDual f)) ∣ + ∑ u : FABL.F₂DecisionTree.coordinateZeroSubspace I, + bitSignInt (bentDual f u.1) := by + classical + let E := FABL.F₂DecisionTree.coordinateZeroSubspace I + have hfinrank : Module.finrank FABL.𝔽₂ E = n - I.card := by + simpa [E] using finrank_coordinateZeroSubspace I + let e : FABL.F₂Cube (n - I.card) ≃ₗ[FABL.𝔽₂] E := + LinearEquiv.ofFinrankEq _ _ (by + rw [Module.finrank_fintype_fun_eq_card] + simpa using hfinrank.symm) + let L : FABL.F₂Cube (n - I.card) →ₗ[FABL.𝔽₂] FABL.F₂Cube n := + E.subtype.comp e.toLinearMap + let g : BooleanFunction (n - I.card) := fun y ↦ bentDual f (L y) + have hdegree : FABL.functionAlgebraicDegree g ≤ + FABL.functionAlgebraicDegree (bentDual f) := by + simpa [g, L, Function.comp_def] using + (functionAlgebraicDegree_comp_affineMap_le_general + (bentDual f) L.toAffineMap) + have hdegreePos : 0 < FABL.functionAlgebraicDegree (bentDual f) := + (two_le_functionAlgebraicDegree_of_isBent + (bentDual f) (isBent_bentDual f hf) hn).trans_lt' (by omega) + have hdiv := two_pow_ceilDiv_dvd_booleanCharacterSum_of_degree_le + g (FABL.functionAlgebraicDegree (bentDual f)) hdegreePos hdegree + have hsum : (∑ y, bitSignInt (g y)) = + ∑ u : E, bitSignInt (bentDual f u.1) := by + simpa [g, L] using + (Equiv.sum_comp e.toEquiv (fun u : E ↦ bitSignInt (bentDual f u.1))) + rw [hsum] at hdiv + exact hdiv + +private theorem exponent_le_of_two_pow_dvd_mul_of_not_four_dvd + (q s : ℕ) (R L : ℤ) + (hL : L = (2 : ℤ) ^ s * R) + (hdiv : (2 : ℤ) ^ q ∣ L) + (hnotFour : ¬(4 : ℤ) ∣ R) : + q ≤ s + 1 := by + by_contra hnot + have hsTwo : s + 2 ≤ q := by omega + have hhigh : (2 : ℤ) ^ (s + 2) ∣ L := + (pow_dvd_pow (2 : ℤ) hsTwo).trans hdiv + apply hnotFour + obtain ⟨z, hz⟩ := hhigh + refine ⟨z, ?_⟩ + apply mul_left_cancel₀ (by positivity : (2 : ℤ) ^ s ≠ 0) + calc + (2 : ℤ) ^ s * R = L := hL.symm + _ = (2 : ℤ) ^ (s + 2) * z := hz + _ = (2 : ℤ) ^ s * (4 * z) := by + rw [pow_add] + norm_num + ring + +private theorem ceilDiv_dualDegree_le_half_sub_degree_add_one + (f : BooleanFunction n) (hf : IsBent f) (hn : 2 ≤ n) : + (n - FABL.functionAlgebraicDegree f) ⌈/⌉ + FABL.functionAlgebraicDegree (bentDual f) ≤ + n / 2 - FABL.functionAlgebraicDegree f + 1 := by + have heven := even_of_isBent f hf + by_cases hnFour : 4 ≤ n + · have hfDegreeTwo := two_le_functionAlgebraicDegree_of_isBent f hf hn + have hfNe : f ≠ 0 := by + intro hfZero + subst f + simp at hfDegreeTwo + obtain ⟨I, hcoeff, hIdegree⟩ := FABL.exists_top_anfCoeff f hfNe + have hIhalf : I.card ≤ n / 2 := by + rw [hIdegree] + exact functionAlgebraicDegree_le_half_of_isBent f hf hnFour + have hL := bentDual_sum_coordinateZeroSubspace f hf I hIhalf + have hdiv := + two_pow_ceilDiv_dualDegree_dvd_coordinateZeroSubspace_sum f hf hn I + have hvaluation := + exact_two_divisibility_perpendicular_coordinateZeroSubspace + f I hcoeff (by simpa [hIdegree] using hfDegreeTwo) + have hbound := exponent_le_of_two_pow_dvd_mul_of_not_four_dvd + ((n - I.card) ⌈/⌉ FABL.functionAlgebraicDegree (bentDual f)) + (n / 2 - I.card) + (∑ x : FABL.perpendicularSubspace + (FABL.F₂DecisionTree.coordinateZeroSubspace I), bitSignInt (f x.1)) + (∑ u : FABL.F₂DecisionTree.coordinateZeroSubspace I, + bitSignInt (bentDual f u.1)) + hL hdiv hvaluation.2 + simpa [hIdegree] using hbound + · have hnTwo : n = 2 := by + rcases heven with ⟨k, hk⟩ + omega + subst n + rw [functionAlgebraicDegree_eq_two_of_isBent f hf, + functionAlgebraicDegree_eq_two_of_isBent + (bentDual f) (isBent_bentDual f hf)] + norm_num + +private theorem relation47_of_ceilDiv_le + (n d dualDegree : ℕ) + (hnEven : Even n) + (hdHalf : d ≤ n / 2) + (hdualTwo : 2 ≤ dualDegree) + (hceil : (n - d) ⌈/⌉ dualDegree ≤ n / 2 - d + 1) : + ((n : ℚ) / 2 - (d : ℚ)) ≥ + (((n : ℚ) / 2 - (dualDegree : ℚ)) / + ((dualDegree : ℚ) - 1)) := by + have hdualPos : 0 < dualDegree := by omega + have hmulNat : n - d ≤ dualDegree * (n / 2 - d + 1) := + (ceilDiv_le_iff_le_mul hdualPos).mp hceil + have hsplit : n = n / 2 + n / 2 := by + rcases hnEven with ⟨k, hk⟩ + omega + have hdn : d ≤ n := hdHalf.trans (Nat.div_le_self n 2) + have hmulQ : + ((n : ℚ) - (d : ℚ)) ≤ + (dualDegree : ℚ) * + (((n / 2 : ℕ) : ℚ) - (d : ℚ) + 1) := by + have hcast : ((n - d : ℕ) : ℚ) ≤ + ((dualDegree * (n / 2 - d + 1) : ℕ) : ℚ) := by + exact_mod_cast hmulNat + simpa [Nat.cast_sub hdn, Nat.cast_sub hdHalf] using hcast + have hsplitQ : (n : ℚ) = 2 * ((n / 2 : ℕ) : ℚ) := by + have hcast : (n : ℚ) = + ((n / 2 : ℕ) : ℚ) + ((n / 2 : ℕ) : ℚ) := by + exact_mod_cast hsplit + linarith + have hhalfQ : (n : ℚ) / 2 = ((n / 2 : ℕ) : ℚ) := by + rw [hsplitQ] + ring + have hproductQ : + ((n / 2 : ℕ) : ℚ) - (dualDegree : ℚ) ≤ + (((n / 2 : ℕ) : ℚ) - (d : ℚ)) * + ((dualDegree : ℚ) - 1) := by + nlinarith [hmulQ, hsplitQ] + have hdualTwoQ : (2 : ℚ) ≤ (dualDegree : ℚ) := by + exact_mod_cast hdualTwo + have hdenom : (0 : ℚ) < (dualDegree : ℚ) - 1 := by + linarith + apply (div_le_iff₀ hdenom).2 + rwa [hhalfQ] + +/-- Carlet Proposition 19, Relation (47): if `f` is bent in positive even +dimension, then the algebraic degrees of `f` and its dual satisfy +`n / 2 - deg(f) ≥ (n / 2 - deg(f̃)) / (deg(f̃) - 1)`. -/ +theorem bentDual_functionAlgebraicDegree_relation + (f : BooleanFunction n) (hf : IsBent f) (hn : 2 ≤ n) : + (n : ℚ) / 2 - (FABL.functionAlgebraicDegree f : ℚ) ≥ + ((n : ℚ) / 2 - + (FABL.functionAlgebraicDegree (bentDual f) : ℚ)) / + ((FABL.functionAlgebraicDegree (bentDual f) : ℚ) - 1) := by + have heven := even_of_isBent f hf + by_cases hnFour : 4 ≤ n + · let d := FABL.functionAlgebraicDegree f + let dDual := FABL.functionAlgebraicDegree (bentDual f) + have hdLe : d ≤ n / 2 := + functionAlgebraicDegree_le_half_of_isBent f hf hnFour + have hdDualTwo : 2 ≤ dDual := + two_le_functionAlgebraicDegree_of_isBent + (bentDual f) (isBent_bentDual f hf) hn + have hceil := ceilDiv_dualDegree_le_half_sub_degree_add_one f hf hn + exact relation47_of_ceilDiv_le n d dDual heven hdLe hdDualTwo + (by simpa [d, dDual] using hceil) + · have hnTwo : n = 2 := by + rcases heven with ⟨k, hk⟩ + omega + subst n + rw [functionAlgebraicDegree_eq_two_of_isBent f hf, + functionAlgebraicDegree_eq_two_of_isBent + (bentDual f) (isBent_bentDual f hf)] + norm_num + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/DirectSum.lean b/CryptBoolean/Carlet/Chapter06/DirectSum.lean new file mode 100644 index 0000000..0ed79d9 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/DirectSum.lean @@ -0,0 +1,87 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter04.OddDimensionBestNonlinearity +public import CryptBoolean.Carlet.Chapter06.Dual + +/-! +# Direct sums of bent Boolean functions + +Carlet Section 6.4.2: the raw Walsh transform of a Boolean direct sum factors, and the +direct sum of two bent functions is bent. +-/ + +open scoped BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n m : ℕ} + +/-- A function is decomposable with block sizes `n` and `m` when an affine +change of variables turns it into a sum of functions on the two disjoint +blocks. -/ +def IsDecomposable + (h : BooleanFunction (n + m)) : Prop := + ∃ f : BooleanFunction n, ∃ g : BooleanFunction m, + ∃ L : FABL.F₂Cube (n + m) ≃ᵃ[FABL.𝔽₂] FABL.F₂Cube (n + m), + h = booleanDirectSum f g ∘ L + +/-- Every direct sum is decomposable. -/ +theorem isDecomposable_booleanDirectSum + (f : BooleanFunction n) (g : BooleanFunction m) : + IsDecomposable (booleanDirectSum f g) := by + refine ⟨f, g, AffineEquiv.refl FABL.𝔽₂ (FABL.F₂Cube (n + m)), ?_⟩ + rfl + +/-- Carlet's direct-sum Walsh identity. -/ +theorem walshTransform_directSum + (f : BooleanFunction n) (g : BooleanFunction m) + (a : FABL.F₂Cube n) (b : FABL.F₂Cube m) : + walshTransform (booleanDirectSum f g) (Fin.append a b) = + walshTransform f a * walshTransform g b := + walshTransform_booleanDirectSum_append f g a b + +/-- The Boolean direct sum of two bent functions is bent. -/ +theorem isBent_booleanDirectSum + {f : BooleanFunction n} {g : BooleanFunction m} + (hf : IsBent f) (hg : IsBent g) : + IsBent (booleanDirectSum f g) := by + change FABL.IsBent (realSignView (booleanDirectSum f g)) + rw [realSignView_booleanDirectSum] + exact FABL.IsBent.directProduct + (even_of_isBent f hf) (even_of_isBent g hg) hf hg + +/-- The dual of a direct sum is the direct sum of the two duals. -/ +theorem bentDual_booleanDirectSum_append + {f : BooleanFunction n} {g : BooleanFunction m} + (hf : IsBent f) (hg : IsBent g) + (a : FABL.F₂Cube n) (b : FABL.F₂Cube m) : + bentDual (booleanDirectSum f g) (Fin.append a b) = + bentDual f a + bentDual g b := by + have hsum := isBent_booleanDirectSum hf hg + have hfactor := walshTransform_directSum f g a b + rw [walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf a, + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual g hg b] at hfactor + rw [walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + (booleanDirectSum f g) hsum (Fin.append a b)] at hfactor + have hhalf : (n + m) / 2 = n / 2 + m / 2 := by + rcases even_of_isBent f hf with ⟨r, hr⟩ + rcases even_of_isBent g hg with ⟨s, hs⟩ + omega + rw [hhalf, pow_add] at hfactor + have hsign : + bitSignInt (bentDual (booleanDirectSum f g) (Fin.append a b)) = + bitSignInt (bentDual f a) * bitSignInt (bentDual g b) := by + apply mul_right_cancel₀ + (by positivity : (2 ^ (n / 2) : ℤ) * 2 ^ (m / 2) ≠ 0) + simpa [mul_assoc, mul_left_comm, mul_comm] using hfactor + rw [← bitSignInt_add] at hsign + exact bitSignInt_injective hsign + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/Dual.lean b/CryptBoolean/Carlet/Chapter06/Dual.lean new file mode 100644 index 0000000..79cbeea --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/Dual.lean @@ -0,0 +1,137 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.Bentness +public import FABL.Chapter06.Constructions.BentDual + +/-! +# Duals of bent Boolean functions + +Carlet Section 6.1: the bit-valued dual, its raw Walsh relation, bentness, and involution. +-/ + +open scoped BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The bit-valued dual selected by the sign of the raw Walsh coefficient. -/ +noncomputable def bentDual (f : BooleanFunction n) : BooleanFunction n := + fun a ↦ if 0 ≤ walshTransform f a then 0 else 1 + +/-- For a bent function, the raw Walsh coefficient is its dual sign scaled by +`2^(n/2)`. -/ +theorem walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + (f : BooleanFunction n) (hf : IsBent f) (a : FABL.F₂Cube n) : + walshTransform f a = + (2 ^ (n / 2) : ℤ) * bitSignInt (bentDual f a) := by + have hmagnitude := + natAbs_walshTransform_eq_two_pow_half_of_isBent f hf a + rcases Int.natAbs_eq_iff.mp hmagnitude with hpositive | hnegative + · have hnonnegative : 0 ≤ walshTransform f a := by + rw [hpositive] + positivity + rw [bentDual, if_pos hnonnegative, hpositive] + simp [bitSignInt_eq_if_one] + · have hnegative' : ¬ 0 ≤ walshTransform f a := by + rw [hnegative] + have hpower : (0 : ℤ) < 2 ^ (n / 2) := by positivity + exact not_le.mpr (neg_neg_of_pos hpower) + rw [bentDual, if_neg hnegative', hnegative] + simp [bitSignInt_eq_if_one] + +/-- The real sign view of Carlet's bit-valued dual is FABL's normalized +Fourier dual. -/ +theorem realSignView_bentDual + (f : BooleanFunction n) (hf : IsBent f) : + realSignView (bentDual f) = FABL.bentDual (realSignView f) := by + funext a + have hn := even_of_isBent f hf + have hsplit : n = n / 2 + n / 2 := by + rcases hn with ⟨k, hk⟩ + omega + have hrawInt := + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf a + have hraw := congrArg (fun z : ℤ ↦ (z : ℝ)) hrawInt + have hsign : + (bitSignInt (bentDual f a) : ℝ) = realSignView (bentDual f) a := by + rw [bitSignInt_cast] + simp [realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction, FABL.signValue_signEncode_eq_binarySign] + simp only [Int.cast_mul, Int.cast_pow, Int.cast_ofNat] at hraw + rw [hsign] at hraw + have hfourier := walshTransform_eq_two_pow_mul_vectorFourierCoeff f a + have hpow : + (2 : ℝ) ^ n = (2 : ℝ) ^ (n / 2) * (2 : ℝ) ^ (n / 2) := by + calc + (2 : ℝ) ^ n = (2 : ℝ) ^ (n / 2 + n / 2) := + congrArg (fun k : ℕ ↦ (2 : ℝ) ^ k) hsplit + _ = (2 : ℝ) ^ (n / 2) * (2 : ℝ) ^ (n / 2) := pow_add _ _ _ + apply mul_left_cancel₀ (by positivity : (2 : ℝ) ^ (n / 2) ≠ 0) + calc + (2 : ℝ) ^ (n / 2) * realSignView (bentDual f) a = + (walshTransform f a : ℝ) := hraw.symm + _ = (2 : ℝ) ^ n * FABL.vectorFourierCoeff (realSignView f) a := + hfourier + _ = (2 : ℝ) ^ (n / 2) * + ((2 : ℝ) ^ (n / 2) * + FABL.vectorFourierCoeff (realSignView f) a) := by + rw [hpow] + ring + _ = (2 : ℝ) ^ (n / 2) * FABL.bentDual (realSignView f) a := rfl + +/-- The dual of a bent Boolean function is bent. -/ +theorem isBent_bentDual + (f : BooleanFunction n) (hf : IsBent f) : IsBent (bentDual f) := by + change FABL.IsBent (realSignView (bentDual f)) + rw [realSignView_bentDual f hf] + exact (FABL.IsBent.bentDual (even_of_isBent f hf) hf + (FABL.isSignValued_realSignEncodedFunction f)).2 + +/-- The raw Walsh transform of the dual recovers the original sign. -/ +theorem walshTransform_bentDual + (f : BooleanFunction n) (hf : IsBent f) (a : FABL.F₂Cube n) : + walshTransform (bentDual f) a = + (2 ^ (n / 2) : ℤ) * bitSignInt (f a) := by + apply Int.cast_injective (α := ℝ) + rw [walshTransform_eq_two_pow_mul_vectorFourierCoeff, + realSignView_bentDual f hf, + FABL.vectorFourierCoeff_bentDual (even_of_isBent f hf)] + have hsign : (bitSignInt (f a) : ℝ) = realSignView f a := by + rw [bitSignInt_cast] + simp [realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction, FABL.signValue_signEncode_eq_binarySign] + have hsplit : n = n / 2 + n / 2 := by + rcases even_of_isBent f hf with ⟨k, hk⟩ + omega + have hpow : + (2 : ℝ) ^ n = (2 : ℝ) ^ (n / 2) * (2 : ℝ) ^ (n / 2) := by + calc + (2 : ℝ) ^ n = (2 : ℝ) ^ (n / 2 + n / 2) := + congrArg (fun k : ℕ ↦ (2 : ℝ) ^ k) hsplit + _ = (2 : ℝ) ^ (n / 2) * (2 : ℝ) ^ (n / 2) := pow_add _ _ _ + simp only [Int.cast_mul, Int.cast_pow, Int.cast_ofNat] + rw [hsign] + rw [hpow] + field_simp + +/-- Duality is an involution on bent Boolean functions. -/ +theorem bentDual_bentDual + (f : BooleanFunction n) (hf : IsBent f) : bentDual (bentDual f) = f := by + funext a + rw [bentDual, walshTransform_bentDual f hf a] + by_cases hfa : f a = 1 + · simp [hfa, bitSignInt_eq_if_one] + · have hfaZero : f a = 0 := by + by_contra hzero + exact hfa (Fin.eq_one_of_ne_zero (f a) hzero) + simp [hfaZero, bitSignInt_eq_if_one] + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/DualAffine.lean b/CryptBoolean/Carlet/Chapter06/DualAffine.lean new file mode 100644 index 0000000..298b47b --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/DualAffine.lean @@ -0,0 +1,159 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.DualIsometry +import CryptBoolean.Carlet.Chapter05.Affine + +/-! +# Bent duals under affine input and output shifts + +Carlet Section 6.1: the affine action on bent duals and Relation (45). +-/ + +open scoped BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- Translating the input of a bent Boolean function preserves bentness. -/ +theorem isBent_domainTranslate + (f : BooleanFunction n) (hf : IsBent f) (b : FABL.F₂Cube n) : + IsBent (FABL.domainTranslate f b) := by + have h := (isBent_comp_affineEquiv_iff f + (AffineEquiv.constVAdd FABL.𝔽₂ (FABL.F₂Cube n) b)).2 hf + convert h using 1 + funext x + simp [FABL.domainTranslate_apply, add_comm] + +/-- Translating a bent function and adding a linear function preserves bentness. -/ +theorem isBent_domainTranslate_add_linear + (f : BooleanFunction n) (hf : IsBent f) (b a : FABL.F₂Cube n) : + IsBent (FABL.domainTranslate f b + FABL.affineFunction 0 a) := + (isBent_add_affineFunction_iff (FABL.domainTranslate f b) 0 a).2 + (isBent_domainTranslate f hf b) + +/-- Carlet's affine action on bent duals. -/ +theorem bentDual_domainTranslate_add_linear + (f : BooleanFunction n) (hf : IsBent f) (b a x : FABL.F₂Cube n) : + bentDual (FABL.domainTranslate f b + FABL.affineFunction 0 a) x = + bentDual f (x + a) + FABL.f₂DotProduct b (x + a) := by + let g := FABL.domainTranslate f b + FABL.affineFunction 0 a + have hg : IsBent g := isBent_domainTranslate_add_linear f hf b a + have hshift : + walshTransform g x = + walshTransform (FABL.domainTranslate f b) (x + a) := by + dsimp [g] + rw [walshTransform_add_affineFunction] + simp [bitSignInt_eq_if_one] + have hshiftReal : + (walshTransform g x : ℝ) = + (walshTransform (FABL.domainTranslate f b) (x + a) : ℝ) := + congrArg (fun z : ℤ ↦ (z : ℝ)) hshift + have htranslate := walshTransform_domainTranslate_cast f b (x + a) + have hdualG := congrArg (fun z : ℤ ↦ (z : ℝ)) + (walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual g hg x) + have hdualF := congrArg (fun z : ℤ ↦ (z : ℝ)) + (walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf (x + a)) + simp only [Int.cast_mul, Int.cast_pow, Int.cast_ofNat] at hdualG hdualF + have hcharacter : + FABL.vectorWalshCharacter (x + a) b = + (bitSignInt (FABL.f₂DotProduct b (x + a)) : ℝ) := by + rw [FABL.vectorWalshCharacter_apply] + rw [show FABL.f₂DotProduct (x + a) b = + FABL.f₂DotProduct b (x + a) by exact dotProduct_comm _ _] + exact (bitSignInt_cast _).symm + have hscaled : + (2 : ℝ) ^ (n / 2) * (bitSignInt (bentDual g x) : ℝ) = + (2 : ℝ) ^ (n / 2) * + (bitSignInt + (bentDual f (x + a) + FABL.f₂DotProduct b (x + a)) : ℝ) := by + calc + (2 : ℝ) ^ (n / 2) * (bitSignInt (bentDual g x) : ℝ) = + (walshTransform g x : ℝ) := hdualG.symm + _ = (walshTransform (FABL.domainTranslate f b) (x + a) : ℝ) := hshiftReal + _ = FABL.vectorWalshCharacter (x + a) b * + (walshTransform f (x + a) : ℝ) := htranslate + _ = (bitSignInt (FABL.f₂DotProduct b (x + a)) : ℝ) * + ((2 : ℝ) ^ (n / 2) * + (bitSignInt (bentDual f (x + a)) : ℝ)) := by + rw [hcharacter, hdualF] + _ = (2 : ℝ) ^ (n / 2) * + ((bitSignInt (bentDual f (x + a)) : ℝ) * + (bitSignInt (FABL.f₂DotProduct b (x + a)) : ℝ)) := by + ring + _ = (2 : ℝ) ^ (n / 2) * + (bitSignInt + (bentDual f (x + a) + FABL.f₂DotProduct b (x + a)) : ℝ) := by + rw [bitSignInt_add] + push_cast + rfl + have hsignReal : + (bitSignInt (bentDual g x) : ℝ) = + (bitSignInt + (bentDual f (x + a) + FABL.f₂DotProduct b (x + a)) : ℝ) := + mul_left_cancel₀ (by positivity : (2 : ℝ) ^ (n / 2) ≠ 0) hscaled + apply bitSignInt_injective + exact_mod_cast hsignReal + +/-- Carlet Relation (45): the two derivative-linear sums have equal imbalance. -/ +theorem walshTransform_zero_bentDual_derivative_add_linear + (f : BooleanFunction n) (hf : IsBent f) (a b : FABL.F₂Cube n) : + walshTransform + (FABL.booleanDerivative (bentDual f) a + FABL.affineFunction 0 b) 0 = + walshTransform (FABL.booleanDerivative f b + FABL.affineFunction 0 a) 0 := by + let translated := FABL.domainTranslate f b + let linearShift := f + FABL.affineFunction 0 a + have htranslated : IsBent translated := isBent_domainTranslate f hf b + have hlinearShift : IsBent linearShift := + (isBent_add_affineFunction_iff f 0 a).2 hf + have hrelation := walshTransform_zero_bentDual_add + translated linearShift htranslated hlinearShift + have hdualTranslated : + bentDual translated = bentDual f + FABL.affineFunction 0 b := by + funext x + have h := bentDual_domainTranslate_add_linear f hf b 0 x + have hinput : + FABL.domainTranslate f b + FABL.affineFunction 0 0 = + FABL.domainTranslate f b := by + funext y + simp [FABL.affineFunction, FABL.f₂DotProduct] + rw [hinput] at h + simpa [translated, FABL.affineFunction] using h + have hdualLinearShift : + bentDual linearShift = FABL.domainTranslate (bentDual f) a := by + funext x + have h := bentDual_domainTranslate_add_linear f hf 0 a x + have hinput : + FABL.domainTranslate f 0 + FABL.affineFunction 0 a = + f + FABL.affineFunction 0 a := by + funext y + simp [FABL.domainTranslate_apply] + rw [hinput] at h + simpa [linearShift, FABL.affineFunction, FABL.domainTranslate, + FABL.f₂DotProduct] using h + have hleft : + bentDual translated + bentDual linearShift = + FABL.booleanDerivative (bentDual f) a + FABL.affineFunction 0 b := by + funext x + rw [hdualTranslated, hdualLinearShift] + simp only [Pi.add_apply, FABL.booleanDerivative, FABL.domainTranslate_apply, + FABL.affineFunction, zero_add] + ac_rfl + have hright : + translated + linearShift = + FABL.booleanDerivative f b + FABL.affineFunction 0 a := by + funext x + simp only [translated, linearShift, Pi.add_apply, FABL.domainTranslate_apply, + FABL.booleanDerivative, FABL.affineFunction, zero_add] + ac_rfl + rw [hleft, hright] at hrelation + exact hrelation + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/DualCoefficientDivisibility.lean b/CryptBoolean/Carlet/Chapter06/DualCoefficientDivisibility.lean new file mode 100644 index 0000000..b2dd33c --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/DualCoefficientDivisibility.lean @@ -0,0 +1,428 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.DualNNF +public import CryptBoolean.Carlet.Chapter06.NNFCharacterization + +/-! +# Numerical and algebraic coefficients of the bent dual + +Carlet Proposition 17 and the complementary half-degree ANF coefficient +relation between a bent function and its dual. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +private theorem nnfCoefficient_divisibility_of_isBent + (f : BooleanFunction n) (hf : IsBent f) + (I : Finset (Fin n)) (hI : I ≠ Finset.univ) + (hIhalf : n / 2 < I.card) : + (2 : ℤ) ^ (I.card - n / 2) ∣ + FABL.booleanNumericalCoeffInt f I := by + have hIcardLe : I.card ≤ n := by + simpa using Finset.card_le_univ I + have hIcardLt : I.card < n := by + apply lt_of_le_of_ne hIcardLe + intro hcard + apply hI + apply Finset.eq_univ_of_card + simpa using hcard + have hnTwo : 2 ≤ n := by omega + exact ((isBent_iff_nnfCoefficientConditions f + (even_of_isBent f hf) hnTwo).mp hf).1 I hIhalf hIcardLt + +/-- Carlet Proposition 17: away from the top monomial, every NNF +coefficient above half dimension has the stated power-of-two divisor, for +both a bent function and its dual. -/ +theorem bentDual_and_self_nnfCoefficient_divisibility + (f : BooleanFunction n) (hf : IsBent f) + (I : Finset (Fin n)) (hI : I ≠ Finset.univ) + (hIhalf : n / 2 < I.card) : + ((2 : ℤ) ^ (I.card - n / 2) ∣ + FABL.booleanNumericalCoeffInt (bentDual f) I) ∧ + ((2 : ℤ) ^ (I.card - n / 2) ∣ + FABL.booleanNumericalCoeffInt f I) := by + exact ⟨nnfCoefficient_divisibility_of_isBent + (bentDual f) (isBent_bentDual f hf) I hI hIhalf, + nnfCoefficient_divisibility_of_isBent f hf I hI hIhalf⟩ + +private theorem numericalCoeff_rawFourierTransform_numericalEval + (c : FABL.NumericalCoefficients n) (I : Finset (Fin n)) : + FABL.numericalCoeff + (rawFourierTransform (FABL.numericalEval c)) I = + (-1 : ℝ) ^ I.card * + ∑ S : Finset (Fin n), + (2 : ℝ) ^ (I ∩ S).card * + ((2 : ℝ) ^ (n - S.card) * c S) := by + classical + rw [FABL.numericalCoeff_eq_mobius_sum] + simp_rw [rawFourierTransform_numericalEval] + have hsupport (T : Finset (Fin n)) : + FABL.f₂Support (FABL.f₂CubeOfFinset T) = T := + (FABL.f₂CubeEquivFinset n).right_inv T + simp_rw [hsupport] + simp_rw [mul_sum, Finset.sum_filter] + rw [Finset.sum_comm] + apply Finset.sum_congr rfl + intro S _hS + have hsign (T : Finset (Fin n)) (hT : T ∈ I.powerset) : + (-1 : ℝ) ^ (I.card - T.card) * (-1 : ℝ) ^ T.card = + (-1 : ℝ) ^ I.card := by + rw [← pow_add] + congr 1 + exact Nat.sub_add_cancel + (Finset.card_le_card (Finset.mem_powerset.mp hT)) + rw [← Finset.sum_filter] + have hfilter : + I.powerset.filter (fun T : Finset (Fin n) ↦ T ⊆ S) = + (I ∩ S).powerset := by + ext T + simp only [Finset.mem_filter, Finset.mem_powerset] + constructor + · intro h x hx + exact Finset.mem_inter.mpr ⟨h.1 hx, h.2 hx⟩ + · intro h + exact ⟨fun x hx ↦ (Finset.mem_inter.mp (h hx)).1, + fun x hx ↦ (Finset.mem_inter.mp (h hx)).2⟩ + rw [hfilter] + calc + ∑ T ∈ (I ∩ S).powerset, + (-1 : ℝ) ^ (I.card - T.card) * + ((-1 : ℝ) ^ T.card * + ((2 : ℝ) ^ (n - S.card) * c S)) = + ∑ _T ∈ (I ∩ S).powerset, + (-1 : ℝ) ^ I.card * + ((2 : ℝ) ^ (n - S.card) * c S) := by + apply Finset.sum_congr rfl + intro T hT + have hTI : T ∈ I.powerset := Finset.mem_powerset.mpr + ((Finset.mem_powerset.mp hT).trans Finset.inter_subset_left) + rw [← mul_assoc, hsign T hTI] + _ = _ := by + rw [Finset.sum_const, Finset.card_powerset] + simp only [nsmul_eq_mul, Nat.cast_pow, Nat.cast_ofNat] + ring + +private theorem numericalCoeff_bentDual_eq_rawFourierTransform + (f : BooleanFunction n) (hf : IsBent f) + (I : Finset (Fin n)) (hI : I ≠ ∅) : + FABL.numericalCoeff + (FABL.booleanRealEmbedding (bentDual f)) I = + -((-1 : ℝ) ^ I.card * ((2 : ℝ) ^ (n / 2) / 2)) + + FABL.numericalCoeff + (rawFourierTransform (FABL.booleanRealEmbedding f)) I / + (2 : ℝ) ^ (n / 2) := by + classical + have hsupport (T : Finset (Fin n)) : + FABL.f₂Support (FABL.f₂CubeOfFinset T) = T := + (FABL.f₂CubeEquivFinset n).right_inv T + have hzero (T : Finset (Fin n)) : + FABL.f₂CubeOfFinset T = 0 ↔ T = ∅ := by + constructor + · intro h + have := congrArg FABL.f₂Support h + rw [hsupport T] at this + simpa [FABL.f₂Support] using this + · intro h + subst T + ext i + simp [FABL.f₂CubeOfFinset_apply] + have hsign (T : Finset (Fin n)) (hT : T ∈ I.powerset) : + (-1 : ℝ) ^ (I.card - T.card) * (-1 : ℝ) ^ T.card = + (-1 : ℝ) ^ I.card := by + rw [← pow_add] + congr 1 + exact Nat.sub_add_cancel + (Finset.card_le_card (Finset.mem_powerset.mp hT)) + have hsign' (T : Finset (Fin n)) (hT : T ∈ I.powerset) : + (-1 : ℝ) ^ (I.card - T.card) = + (-1 : ℝ) ^ I.card * (-1 : ℝ) ^ T.card := by + calc + (-1 : ℝ) ^ (I.card - T.card) = + (-1 : ℝ) ^ (I.card - T.card) * 1 := by ring + _ = (-1 : ℝ) ^ (I.card - T.card) * + (((-1 : ℝ) ^ T.card) * ((-1 : ℝ) ^ T.card)) := by + rw [← mul_pow] + norm_num + _ = ((-1 : ℝ) ^ (I.card - T.card) * + (-1 : ℝ) ^ T.card) * (-1 : ℝ) ^ T.card := by ring + _ = (-1 : ℝ) ^ I.card * (-1 : ℝ) ^ T.card := by + rw [hsign T hT] + have hsumSign : + (∑ T ∈ I.powerset, (-1 : ℝ) ^ (I.card - T.card)) = 0 := by + calc + (∑ T ∈ I.powerset, (-1 : ℝ) ^ (I.card - T.card)) = + ∑ T ∈ I.powerset, + (-1 : ℝ) ^ I.card * (-1 : ℝ) ^ T.card := by + apply Finset.sum_congr rfl + intro T hT + exact hsign' T hT + _ = (-1 : ℝ) ^ I.card * + ∑ T ∈ I.powerset, (-1 : ℝ) ^ T.card := by + rw [Finset.mul_sum] + _ = 0 := by + have hsumZ := Finset.sum_powerset_neg_one_pow_card + (x := I) + rw [if_neg hI] at hsumZ + have hsumR : + (∑ T ∈ I.powerset, (-1 : ℝ) ^ T.card) = 0 := by + exact_mod_cast hsumZ + rw [hsumR, mul_zero] + rw [FABL.numericalCoeff_eq_mobius_sum] + simp_rw [booleanRealEmbedding_bentDual_eq_rawFourierTransform f hf] + simp_rw [hzero] + have hconst : + (∑ T ∈ I.powerset, + (-1 : ℝ) ^ (I.card - T.card) * ((1 : ℝ) / 2)) = 0 := by + rw [← Finset.sum_mul, hsumSign, zero_mul] + have hdelta : + (∑ T ∈ I.powerset, + (-1 : ℝ) ^ (I.card - T.card) * + (if T = ∅ then (2 : ℝ) ^ (n / 2) / 2 else 0)) = + (-1 : ℝ) ^ I.card * ((2 : ℝ) ^ (n / 2) / 2) := by + simp_rw [mul_ite, mul_zero] + rw [Finset.sum_ite_eq'] + simp + have hraw : + (∑ T ∈ I.powerset, + (-1 : ℝ) ^ (I.card - T.card) * + (rawFourierTransform (FABL.booleanRealEmbedding f) + (FABL.f₂CubeOfFinset T) / (2 : ℝ) ^ (n / 2))) = + FABL.numericalCoeff + (rawFourierTransform (FABL.booleanRealEmbedding f)) I / + (2 : ℝ) ^ (n / 2) := by + rw [FABL.numericalCoeff_eq_mobius_sum, Finset.sum_div] + apply Finset.sum_congr rfl + intro T _hT + ring + simp_rw [mul_add, mul_sub] + rw [Finset.sum_add_distrib, Finset.sum_sub_distrib, + hconst, hdelta, hraw] + ring + +private theorem numericalCoeff_bentDual_half_eq + (f : BooleanFunction n) (hf : IsBent f) (hn : 4 ≤ n) + (I : Finset (Fin n)) (hIcard : I.card = n / 2) : + FABL.numericalCoeff + (FABL.booleanRealEmbedding (bentDual f)) I = + (-1 : ℝ) ^ I.card * + (-((2 : ℝ) ^ (n / 2 - 1)) + + ∑ S : Finset (Fin n), + (2 : ℝ) ^ (n / 2 - (S \ I).card) * + FABL.numericalCoeff (FABL.booleanRealEmbedding f) S) := by + classical + have hsplit : n = n / 2 + n / 2 := by + rcases even_of_isBent f hf with ⟨k, hk⟩ + omega + have hhalfTwo : 2 ≤ n / 2 := by omega + have hI : I ≠ ∅ := by + intro h + subst I + simp at hIcard + omega + rw [numericalCoeff_bentDual_eq_rawFourierTransform f hf I hI] + nth_rewrite 1 [← FABL.numericalEval_numericalCoeff + (FABL.booleanRealEmbedding f)] + rw [numericalCoeff_rawFourierTransform_numericalEval + (c := FABL.numericalCoeff (FABL.booleanRealEmbedding f)) I] + have hpowHalf : (2 : ℝ) ^ (n / 2) / 2 = + (2 : ℝ) ^ (n / 2 - 1) := by + conv_lhs => + rw [show n / 2 = (n / 2 - 1) + 1 by omega] + rw [pow_succ] + ring + rw [hpowHalf] + have hterm (S : Finset (Fin n)) : + (2 : ℝ) ^ (I ∩ S).card * + ((2 : ℝ) ^ (n - S.card) * + FABL.numericalCoeff (FABL.booleanRealEmbedding f) S) / + (2 : ℝ) ^ (n / 2) = + (2 : ℝ) ^ (n / 2 - (S \ I).card) * + FABL.numericalCoeff (FABL.booleanRealEmbedding f) S := by + have hScard : S.card ≤ n := by + simpa using Finset.card_le_univ S + have hdecomp : (S ∩ I).card + (S \ I).card = S.card := by + exact Finset.card_inter_add_card_sdiff S I + have hdiffLe : (S \ I).card ≤ n / 2 := by + have hsubset : S \ I ⊆ Finset.univ \ I := by + intro x hx + exact Finset.mem_sdiff.mpr ⟨Finset.mem_univ x, + (Finset.mem_sdiff.mp hx).2⟩ + have hcard := Finset.card_le_card hsubset + rw [Finset.card_sdiff_of_subset (Finset.subset_univ I), + Finset.card_univ, Fintype.card_fin, hIcard] at hcard + omega + have hexp : + (I ∩ S).card + (n - S.card) = + n / 2 + (n / 2 - (S \ I).card) := by + rw [Finset.inter_comm] at hdecomp + omega + calc + (2 : ℝ) ^ (I ∩ S).card * + ((2 : ℝ) ^ (n - S.card) * + FABL.numericalCoeff (FABL.booleanRealEmbedding f) S) / + (2 : ℝ) ^ (n / 2) = + ((2 : ℝ) ^ ((I ∩ S).card + (n - S.card)) / + (2 : ℝ) ^ (n / 2)) * + FABL.numericalCoeff (FABL.booleanRealEmbedding f) S := by + rw [pow_add] + ring + _ = (((2 : ℝ) ^ (n / 2) * + (2 : ℝ) ^ (n / 2 - (S \ I).card)) / + (2 : ℝ) ^ (n / 2)) * + FABL.numericalCoeff (FABL.booleanRealEmbedding f) S := by + rw [hexp, pow_add] + _ = _ := by + field_simp + rw [mul_div_assoc, Finset.sum_div] + simp_rw [hterm] + ring + +private theorem booleanNumericalCoeffInt_bentDual_half_eq + (f : BooleanFunction n) (hf : IsBent f) (hn : 4 ≤ n) + (I : Finset (Fin n)) (hIcard : I.card = n / 2) : + FABL.booleanNumericalCoeffInt (bentDual f) I = + (-1 : ℤ) ^ I.card * + (-((2 : ℤ) ^ (n / 2 - 1)) + + ∑ S : Finset (Fin n), + (2 : ℤ) ^ (n / 2 - (S \ I).card) * + FABL.booleanNumericalCoeffInt f S) := by + apply Int.cast_injective (α := ℝ) + simp only [Int.cast_mul, Int.cast_add, Int.cast_neg, Int.cast_pow, + Int.cast_sum, Int.cast_ofNat] + simp_rw [← FABL.numericalCoeff_booleanRealEmbedding_eq_intCast] + simpa using numericalCoeff_bentDual_half_eq f hf hn I hIcard + +/-- For a bent function in dimension at least four, the half-degree ANF +coefficient of the dual is the coefficient of the complementary monomial of +the original function. -/ +theorem anfCoeff_bentDual_eq_complement_of_card_eq_half + (f : BooleanFunction n) (hf : IsBent f) (hn : 4 ≤ n) + (I : Finset (Fin n)) (hIcard : I.card = n / 2) : + FABL.anfCoeff (bentDual f) I = + FABL.anfCoeff f (Finset.univ \ I) := by + rw [← FABL.booleanNumericalCoeffInt_cast_f₂_eq_anfCoeff, + ← FABL.booleanNumericalCoeffInt_cast_f₂_eq_anfCoeff] + have hInt := booleanNumericalCoeffInt_bentDual_half_eq + f hf hn I hIcard + have hcast := congrArg (fun z : ℤ ↦ (z : FABL.𝔽₂)) hInt + simp only [Int.cast_mul, Int.cast_add, Int.cast_neg, Int.cast_pow, + Int.cast_sum, Int.cast_ofNat, Int.cast_one] at hcast + have hsplit : n = n / 2 + n / 2 := by + rcases even_of_isBent f hf with ⟨k, hk⟩ + omega + have hhalfTwo : 2 ≤ n / 2 := by omega + have htwoPow : (2 : FABL.𝔽₂) ^ (n / 2 - 1) = 0 := by + rw [show (2 : FABL.𝔽₂) = 0 by decide] + simp [show n / 2 - 1 ≠ 0 by omega] + have hsign : (-((1 : FABL.𝔽₂))) ^ I.card = 1 := by + simp + rw [hsign, one_mul, htwoPow, neg_zero, zero_add] at hcast + let J : Finset (Fin n) := Finset.univ \ I + have hJcard : J.card = n / 2 := by + dsimp [J] + rw [Finset.card_sdiff_of_subset (Finset.subset_univ I), + Finset.card_univ, Fintype.card_fin, hIcard] + omega + have hJdiff : (J \ I).card = n / 2 := by + rw [show J \ I = J by + ext x + simp [J]] + exact hJcard + have hconditions := (isBent_iff_nnfCoefficientConditions f + (even_of_isBent f hf) (by omega)).mp hf + have hterm (S : Finset (Fin n)) (hS : S ≠ J) : + (2 : FABL.𝔽₂) ^ (n / 2 - (S \ I).card) * + (FABL.booleanNumericalCoeffInt f S : FABL.𝔽₂) = 0 := by + have hdiffSubset : S \ I ⊆ J := by + intro x hx + exact Finset.mem_sdiff.mpr ⟨Finset.mem_univ x, + (Finset.mem_sdiff.mp hx).2⟩ + have hdiffLe : (S \ I).card ≤ n / 2 := by + rw [← hJcard] + exact Finset.card_le_card hdiffSubset + by_cases hdiffLt : (S \ I).card < n / 2 + · rw [show (2 : FABL.𝔽₂) = 0 by decide] + simp [show n / 2 - (S \ I).card ≠ 0 by omega] + · have hdiffEq : (S \ I).card = n / 2 := by omega + have hsdiffEq : S \ I = J := by + apply Finset.eq_of_subset_of_card_le hdiffSubset + rw [hJcard, hdiffEq] + have hJsubS : J ⊆ S := by + rw [← hsdiffEq] + exact Finset.sdiff_subset + have hJssubS : J ⊂ S := hJsubS.ssubset_of_ne hS.symm + by_cases hSuniv : S = Finset.univ + · subst S + have htop := hconditions.2 + rw [Int.modEq_iff_dvd] at htop + have htwoHalf : (2 : ℤ) ∣ (2 : ℤ) ^ (n / 2) := by + simpa using + (pow_dvd_pow (2 : ℤ) (show 1 ≤ n / 2 by omega)) + have htwoHalfPred : (2 : ℤ) ∣ + (2 : ℤ) ^ (n / 2 - 1) := by + simpa using + (pow_dvd_pow (2 : ℤ) (show 1 ≤ n / 2 - 1 by omega)) + have htwoDiff : (2 : ℤ) ∣ + (2 : ℤ) ^ (n / 2 - 1) - + FABL.booleanNumericalCoeffInt f Finset.univ := + dvd_trans htwoHalf htop + have htwoCoeff : (2 : ℤ) ∣ + FABL.booleanNumericalCoeffInt f Finset.univ := by + have := dvd_sub htwoHalfPred htwoDiff + simpa only [sub_sub_cancel] using this + obtain ⟨z, hz⟩ := htwoCoeff + rw [hz] + simp only [Int.cast_mul, Int.cast_ofNat] + rw [show (2 : FABL.𝔽₂) = 0 by decide] + simp + · have hScardLt : S.card < n := by + have hle : S.card ≤ n := by + simpa using Finset.card_le_univ S + apply lt_of_le_of_ne hle + intro hcard + apply hSuniv + exact Finset.eq_univ_of_card S (by simpa using hcard) + have hScardHalf : n / 2 < S.card := by + rw [← hJcard] + exact Finset.card_lt_card hJssubS + obtain ⟨z, hz⟩ := hconditions.1 S hScardHalf hScardLt + rw [hz] + have hpowPos : 0 < S.card - n / 2 := by omega + simp only [Int.cast_mul, Int.cast_pow, Int.cast_ofNat] + rw [show (2 : FABL.𝔽₂) = 0 by decide] + simp [hpowPos.ne'] + rw [hcast] + change (∑ S : Finset (Fin n), + (2 : FABL.𝔽₂) ^ (n / 2 - (S \ I).card) * + (FABL.booleanNumericalCoeffInt f S : FABL.𝔽₂)) = + (FABL.booleanNumericalCoeffInt f J : FABL.𝔽₂) + rw [Finset.sum_eq_single J] + · rw [hJdiff, Nat.sub_self, pow_zero, one_mul] + · intro S _hS hSJ + exact hterm S hSJ + · simp + +/-- The complementary half-degree ANF coefficient relation is symmetric +between a bent function and its dual. -/ +theorem anfCoeff_eq_bentDual_complement_of_card_eq_half + (f : BooleanFunction n) (hf : IsBent f) (hn : 4 ≤ n) + (I : Finset (Fin n)) (hIcard : I.card = n / 2) : + FABL.anfCoeff f I = + FABL.anfCoeff (bentDual f) (Finset.univ \ I) := by + simpa [bentDual_bentDual f hf] using + anfCoeff_bentDual_eq_complement_of_card_eq_half + (bentDual f) (isBent_bentDual f hf) hn I hIcard + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/DualIsometry.lean b/CryptBoolean/Carlet/Chapter06/DualIsometry.lean new file mode 100644 index 0000000..7a33395 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/DualIsometry.lean @@ -0,0 +1,120 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter02.FourierOperations +public import CryptBoolean.Carlet.Chapter06.Dual + +/-! +# Isometry of bent duality + +Carlet Relation (44): duality preserves pairwise Hamming distance. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The sign view sends binary addition to pointwise multiplication. -/ +theorem realSignView_add + (f g : BooleanFunction n) (x : FABL.F₂Cube n) : + realSignView (f + g) x = realSignView f x * realSignView g x := by + simp only [realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction, FABL.signValue_signEncode_eq_binarySign] + exact AddChar.map_add_eq_mul FABL.binarySign (f x) (g x) + +/-- Carlet Relation (44): the imbalance of the sum of two bent duals equals +the imbalance of the original sum. -/ +theorem walshTransform_zero_bentDual_add + (f g : BooleanFunction n) (hf : IsBent f) (hg : IsBent g) : + walshTransform (bentDual f + bentDual g) 0 = + walshTransform (f + g) 0 := by + classical + let p : ℝ := (2 : ℝ) ^ (n / 2) + have hn := even_of_isBent f hf + have hsplit : n = n / 2 + n / 2 := by + rcases hn with ⟨k, hk⟩ + omega + have hpow : p ^ 2 = (2 : ℝ) ^ n := by + dsimp [p] + rw [pow_two] + calc + (2 : ℝ) ^ (n / 2) * (2 : ℝ) ^ (n / 2) = + (2 : ℝ) ^ (n / 2 + n / 2) := (pow_add _ _ _).symm + _ = (2 : ℝ) ^ n := + congrArg (fun k : ℕ ↦ (2 : ℝ) ^ k) hsplit.symm + have hp : (2 : ℝ) ^ n ≠ 0 := by positivity + have hrawFourier (h : BooleanFunction n) (u : FABL.F₂Cube n) : + rawFourierTransform (realSignView h) u = + (walshTransform h u : ℝ) := by + rw [rawFourierTransform_eq_two_pow_mul_vectorFourierCoeff, + walshTransform_eq_two_pow_mul_vectorFourierCoeff] + have hwalshF (u : FABL.F₂Cube n) : + (walshTransform f u : ℝ) = p * realSignView (bentDual f) u := by + have h := congrArg (fun z : ℤ ↦ (z : ℝ)) + (walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf u) + have hsign : + (bitSignInt (bentDual f u) : ℝ) = realSignView (bentDual f) u := by + rw [bitSignInt_cast] + simp [realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction, FABL.signValue_signEncode_eq_binarySign] + simpa only [Int.cast_mul, Int.cast_pow, Int.cast_ofNat, hsign, p] using h + have hwalshG (u : FABL.F₂Cube n) : + (walshTransform g u : ℝ) = p * realSignView (bentDual g) u := by + have h := congrArg (fun z : ℤ ↦ (z : ℝ)) + (walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual g hg u) + have hsign : + (bitSignInt (bentDual g u) : ℝ) = realSignView (bentDual g) u := by + rw [bitSignInt_cast] + simp [realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction, FABL.signValue_signEncode_eq_binarySign] + simpa only [Int.cast_mul, Int.cast_pow, Int.cast_ofNat, hsign, p] using h + have hplancherel := + sum_rawFourierTransform_mul (realSignView f) (realSignView g) + simp_rw [hrawFourier, hwalshF, hwalshG] at hplancherel + have hscaled : + p ^ 2 * + (∑ x, realSignView (bentDual f) x * realSignView (bentDual g) x) = + (2 : ℝ) ^ n * + ∑ x, realSignView f x * realSignView g x := by + calc + p ^ 2 * + (∑ x, realSignView (bentDual f) x * realSignView (bentDual g) x) = + ∑ x, (p * realSignView (bentDual f) x) * + (p * realSignView (bentDual g) x) := by + rw [Finset.mul_sum] + apply Finset.sum_congr rfl + intro x _hx + ring + _ = (2 : ℝ) ^ n * ∑ x, realSignView f x * realSignView g x := + hplancherel + rw [hpow] at hscaled + have hsums : + (∑ x, realSignView (bentDual f) x * realSignView (bentDual g) x) = + ∑ x, realSignView f x * realSignView g x := + mul_left_cancel₀ hp hscaled + apply Int.cast_injective (α := ℝ) + rw [walshTransform_cast_eq_sum_realSignView_mul_character, + walshTransform_cast_eq_sum_realSignView_mul_character] + simp_rw [realSignView_add] + simpa using hsums + +/-- Bent duality preserves Hamming distance. -/ +theorem hammingDistance_bentDual + (f g : BooleanFunction n) (hf : IsBent f) (hg : IsBent g) : + hammingDistance (bentDual f) (bentDual g) = hammingDistance f g := by + rw [hammingDistance_eq_hammingWeight_add, + hammingDistance_eq_hammingWeight_add] + have hzero := walshTransform_zero_bentDual_add f g hf hg + rw [walshTransform_zero_eq_two_pow_sub_two_weight, + walshTransform_zero_eq_two_pow_sub_two_weight] at hzero + omega + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/DualNNF.lean b/CryptBoolean/Carlet/Chapter06/DualNNF.lean new file mode 100644 index 0000000..4897261 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/DualNNF.lean @@ -0,0 +1,94 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter02.FourierNNF +public import CryptBoolean.Carlet.Chapter06.Dual +public import CryptBoolean.Carlet.Chapter06.ThreeFunctionIdentity + +/-! +# Numerical normal form of the bent dual + +Carlet Section 6.1: the pointwise relation deriving the numerical normal form +of the dual from the numerical coefficients of a bent function. +-/ + +open scoped BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The zero-one embedding of the dual is an affine rescaling of the raw +Fourier transform of the zero-one embedding of the original bent function. -/ +theorem booleanRealEmbedding_bentDual_eq_rawFourierTransform + (f : BooleanFunction n) (hf : IsBent f) (x : FABL.F₂Cube n) : + FABL.booleanRealEmbedding (bentDual f) x = + (1 : ℝ) / 2 - + (if x = 0 then (2 : ℝ) ^ (n / 2) / 2 else 0) + + rawFourierTransform (FABL.booleanRealEmbedding f) x / + (2 : ℝ) ^ (n / 2) := by + have hn := even_of_isBent f hf + have hsplit : n = n / 2 + n / 2 := by + rcases hn with ⟨k, hk⟩ + omega + have hpow : (2 : ℝ) ^ n = + (2 : ℝ) ^ (n / 2) * (2 : ℝ) ^ (n / 2) := by + calc + (2 : ℝ) ^ n = (2 : ℝ) ^ (n / 2 + n / 2) := + congrArg (fun k : ℕ ↦ (2 : ℝ) ^ k) hsplit + _ = (2 : ℝ) ^ (n / 2) * (2 : ℝ) ^ (n / 2) := pow_add _ _ _ + have hrawInt := + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf x + have hraw := congrArg (fun z : ℤ ↦ (z : ℝ)) hrawInt + simp only [Int.cast_mul, Int.cast_pow, Int.cast_ofNat] at hraw + have hsign : + (bitSignInt (bentDual f x) : ℝ) = realSignView (bentDual f) x := by + rw [bitSignInt_cast] + simp [realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction, FABL.signValue_signEncode_eq_binarySign] + rw [hsign] at hraw + have hdualEmbedding := congrFun + (FABL.realSignEncodedFunction_eq_one_sub_two_booleanRealEmbedding + (bentDual f)) x + change realSignView (bentDual f) x = + 1 - 2 * FABL.booleanRealEmbedding (bentDual f) x at hdualEmbedding + rw [hdualEmbedding] at hraw + have hwalsh := + walshTransform_cast_eq_rawFourierTransform_sub_two_mul f x + rw [rawFourierTransform_one] at hwalsh + by_cases hx : x = 0 + · rw [if_pos hx] at hwalsh ⊢ + rw [hpow] at hwalsh + rw [hwalsh] at hraw + field_simp + nlinarith + · rw [if_neg hx] at hwalsh ⊢ + rw [hwalsh] at hraw + field_simp + nlinarith + +/-- Carlet's dual-NNF relation in the canonical coefficient notation. -/ +theorem booleanRealEmbedding_bentDual_eq_numericalCoeff_sum + (f : BooleanFunction n) (hf : IsBent f) (x : FABL.F₂Cube n) : + FABL.booleanRealEmbedding (bentDual f) x = + (1 : ℝ) / 2 - + (if x = 0 then (2 : ℝ) ^ (n / 2) / 2 else 0) + + ((-1 : ℝ) ^ (FABL.f₂Support x).card * + ∑ S ∈ (Finset.univ.filter fun S : Finset (Fin n) ↦ + FABL.f₂Support x ⊆ S), + (2 : ℝ) ^ (n - S.card) * + FABL.numericalCoeff (FABL.booleanRealEmbedding f) S) / + (2 : ℝ) ^ (n / 2) := by + rw [booleanRealEmbedding_bentDual_eq_rawFourierTransform f hf x] + have heval := + FABL.numericalEval_numericalCoeff (FABL.booleanRealEmbedding f) + nth_rewrite 1 [← heval] + rw [rawFourierTransform_numericalEval] + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/DualPoisson.lean b/CryptBoolean/Carlet/Chapter06/DualPoisson.lean new file mode 100644 index 0000000..c8999c8 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/DualPoisson.lean @@ -0,0 +1,99 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter02.Subspaces +public import CryptBoolean.Carlet.Chapter06.Dual + +/-! +# Poisson summation for a bent function and its dual + +Carlet Relation (46). +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +attribute [local instance] submoduleFintype + +/-- Carlet Relation (46): Poisson summation exchanges a bent function and +its dual across perpendicular affine subspaces. -/ +theorem bentDual_poissonSummationFormula + (f : BooleanFunction n) (hf : IsBent f) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (a b : FABL.F₂Cube n) : + (∑ u : E, + realSignView (bentDual f) (a + u.1) * + FABL.vectorWalshCharacter b (a + u.1)) = + ((2 : ℝ) ^ (n / 2))⁻¹ * (Nat.card E : ℝ) * + FABL.vectorWalshCharacter b a * + ∑ x : FABL.perpendicularSubspace E, + realSignView f (b + x.1) * + FABL.vectorWalshCharacter a (b + x.1) := by + classical + let p : ℝ := (2 : ℝ) ^ (n / 2) + have hp : p ≠ 0 := by + dsimp [p] + positivity + have hrawFourier (u : FABL.F₂Cube n) : + rawFourierTransform (realSignView f) u = + (walshTransform f u : ℝ) := by + rw [rawFourierTransform_eq_two_pow_mul_vectorFourierCoeff, + walshTransform_eq_two_pow_mul_vectorFourierCoeff] + have hwalsh (u : FABL.F₂Cube n) : + (walshTransform f u : ℝ) = p * realSignView (bentDual f) u := by + have hraw := congrArg (fun z : ℤ ↦ (z : ℝ)) + (walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf u) + have hsign : + (bitSignInt (bentDual f u) : ℝ) = realSignView (bentDual f) u := by + rw [bitSignInt_cast] + simp [realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction, FABL.signValue_signEncode_eq_binarySign] + simpa only [Int.cast_mul, Int.cast_pow, Int.cast_ofNat, hsign, p] using hraw + have hpoisson := rawPoissonSummationFormula (realSignView f) E a b + simp_rw [hrawFourier, hwalsh] at hpoisson + have hscaled : + p * (∑ u : E, + realSignView (bentDual f) (a + u.1) * + FABL.vectorWalshCharacter b (a + u.1)) = + (Nat.card E : ℝ) * FABL.vectorWalshCharacter b a * + ∑ x : FABL.perpendicularSubspace E, + realSignView f (b + x.1) * + FABL.vectorWalshCharacter a (b + x.1) := by + calc + p * (∑ u : E, + realSignView (bentDual f) (a + u.1) * + FABL.vectorWalshCharacter b (a + u.1)) = + ∑ u : E, + FABL.vectorWalshCharacter b (a + u.1) * + (p * realSignView (bentDual f) (a + u.1)) := by + rw [Finset.mul_sum] + apply Finset.sum_congr rfl + intro u _hu + ring + _ = (Nat.card E : ℝ) * FABL.vectorWalshCharacter b a * + ∑ x : FABL.perpendicularSubspace E, + FABL.vectorWalshCharacter a (b + x.1) * + realSignView f (b + x.1) := hpoisson + _ = (Nat.card E : ℝ) * FABL.vectorWalshCharacter b a * + ∑ x : FABL.perpendicularSubspace E, + realSignView f (b + x.1) * + FABL.vectorWalshCharacter a (b + x.1) := by + apply congrArg + apply Finset.sum_congr rfl + intro x _hx + ring + apply mul_left_cancel₀ hp + rw [hscaled] + simp only [p] + field_simp + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/FlatSwitching.lean b/CryptBoolean/Carlet/Chapter06/FlatSwitching.lean new file mode 100644 index 0000000..f262122 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/FlatSwitching.lean @@ -0,0 +1,891 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter02.RestrictionSquareIdentity +public import CryptBoolean.Carlet.Chapter02.WalshDivisibility +public import CryptBoolean.Carlet.Chapter04.HigherOrderNonlinearity +public import CryptBoolean.Carlet.Chapter04.KthNonhomomorphicity +public import CryptBoolean.Carlet.Chapter04.OtherComplexity +public import CryptBoolean.Carlet.Chapter05.FlatIndicators +public import CryptBoolean.Carlet.Chapter05.RestrictionNonlinearity +public import CryptBoolean.Carlet.Chapter06.Bentness +public import CryptBoolean.Carlet.Chapter06.DegreeBounds +public import CryptBoolean.Carlet.Chapter06.DualIsometry +public import CryptBoolean.Carlet.Chapter06.DualPoisson +public import CryptBoolean.Carlet.Chapter06.WalshCongruence + +/-! +# Switching a bent function on an affine flat + +Carlet Chapter 6, Theorem 9. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n k : ℕ} + +noncomputable local instance flatSwitchingSubmoduleFintype + (S : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) : Fintype S := + Fintype.ofFinite S + +noncomputable local instance flatSwitchingMembershipDecidable + (S : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) : + DecidablePred (fun x ↦ x ∈ S) := + Classical.decPred _ + +/-- The Boolean function obtained by complementing `f` on the affine flat +`b + E`. -/ +noncomputable def flatSwitch + (f : BooleanFunction n) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) : BooleanFunction n := + f + affineFlatIndicator E b + +/-- Balancedness of the restriction of a Boolean function to an affine flat, +expressed without choosing coordinates on its direction subspace. -/ +def IsBalancedOnAffineFlat + (f : BooleanFunction n) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) : Prop := + affineSubspaceRestrictionImbalance f E b = 0 + +/-- A Boolean function is constant or balanced on an affine flat exactly +when its signed restriction sum is extremal or zero. -/ +def IsConstantOrBalancedOnAffineFlat + (f : BooleanFunction n) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) : Prop := + IsBalancedOnAffineFlat f E b ∨ + |affineSubspaceRestrictionImbalance f E b| = Nat.card E + +/-- The signed Walsh sum of `f` over the affine flat `b + E`. -/ +noncomputable def affineFlatWalshSum + (f : BooleanFunction n) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b a : FABL.F₂Cube n) : ℤ := + ∑ x : E, walshTerm f a (x.1 + b) + +private noncomputable def affineFlatSubtypeEquiv + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) : + E ≃ {x : FABL.F₂Cube n // x ∈ FABL.binaryAffineSubspace E b} where + toFun x := ⟨x.1 + b, by + rw [FABL.mem_binaryAffineSubspace_iff_add_mem, add_assoc, + ZModModule.add_self, add_zero] + exact x.2⟩ + invFun x := ⟨x.1 + b, + (FABL.mem_binaryAffineSubspace_iff_add_mem E b x.1).1 x.2⟩ + left_inv x := by + ext i + simp [add_assoc, ZModModule.add_self] + right_inv x := by + ext i + simp [add_assoc, ZModModule.add_self] + +private theorem sum_mul_setIndicator_affineFlat + (φ : FABL.F₂Cube n → ℝ) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) : + (∑ x, φ x * FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x) = + ∑ x : E, φ (x.1 + b) := by + classical + calc + (∑ x, φ x * FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x) = + ∑ x ∈ (Finset.univ.filter fun x : FABL.F₂Cube n ↦ + x ∈ FABL.binaryAffineSubspace E b), φ x := by + rw [Finset.sum_filter] + apply Finset.sum_congr rfl + intro x _hx + by_cases hxb : x ∈ FABL.binaryAffineSubspace E b <;> + simp [FABL.setIndicator, hxb] + _ = ∑ x : {x : FABL.F₂Cube n // + x ∈ FABL.binaryAffineSubspace E b}, φ x.1 := by + simpa using + (Finset.sum_subtype + (p := fun x : FABL.F₂Cube n ↦ + x ∈ FABL.binaryAffineSubspace E b) + (Finset.univ.filter fun x : FABL.F₂Cube n ↦ + x ∈ FABL.binaryAffineSubspace E b) + (by simp) φ) + _ = ∑ x : E, φ (x.1 + b) := by + simpa [affineFlatSubtypeEquiv] using + (Equiv.sum_comp (affineFlatSubtypeEquiv E b) + (fun x : {x : FABL.F₂Cube n // + x ∈ FABL.binaryAffineSubspace E b} ↦ φ x.1)).symm + +private theorem setIndicator_affineFlat_mul_translate_eq_zero + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b a x : FABL.F₂Cube n) (ha : a ∉ E) : + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) (x + a) = 0 := by + classical + by_cases hx : x ∈ FABL.binaryAffineSubspace E b + · have hxa : x + a ∉ FABL.binaryAffineSubspace E b := by + intro hxa + have hxE := (FABL.mem_binaryAffineSubspace_iff_add_mem E b x).1 hx + have hxaE := + (FABL.mem_binaryAffineSubspace_iff_add_mem E b (x + a)).1 hxa + apply ha + have hsum := E.add_mem hxE hxaE + have heq : (x + b) + (x + a + b) = a := by + calc + (x + b) + (x + a + b) = (x + x) + (b + b) + a := by abel + _ = a := by + rw [ZModModule.add_self, ZModModule.add_self, zero_add, zero_add] + simpa only [heq] using hsum + simp [FABL.setIndicator, hx, hxa] + · simp [FABL.setIndicator, hx] + +private theorem sum_derivativeSign_mul_setIndicator_translate + (f : BooleanFunction n) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b a : FABL.F₂Cube n) : + (∑ x, realSignView (FABL.booleanDerivative f a) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) (x + a)) = + affineSubspaceRestrictionImbalance + (FABL.booleanDerivative f a) E b := by + classical + calc + (∑ x, realSignView (FABL.booleanDerivative f a) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) (x + a)) = + ∑ x, realSignView (FABL.booleanDerivative f a) (x + a) * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x := by + simpa [add_assoc, ZModModule.add_self] using + (Equiv.sum_comp (Equiv.addRight a) + (fun x : FABL.F₂Cube n ↦ + realSignView (FABL.booleanDerivative f a) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) + (x + a))).symm + _ = ∑ x, realSignView (FABL.booleanDerivative f a) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x := by + apply Finset.sum_congr rfl + intro x _hx + rw [realSignView_booleanDerivative, + realSignView_booleanDerivative] + simp only [add_assoc, ZModModule.add_self, add_zero] + ring + _ = affineSubspaceRestrictionImbalance + (FABL.booleanDerivative f a) E b := by + rw [sum_mul_setIndicator_affineFlat] + rfl + +/-- Complementing on an affine flat changes a Walsh coefficient by twice +the signed Walsh sum over that flat. -/ +theorem walshTransform_sub_flatSwitch + (f : BooleanFunction n) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b a : FABL.F₂Cube n) : + walshTransform f a - walshTransform (flatSwitch f E b) a = + 2 * affineFlatWalshSum f E b a := by + classical + rw [walshTransform, walshTransform, ← Finset.sum_sub_distrib] + calc + (∑ x, (walshTerm f a x - walshTerm (flatSwitch f E b) a x)) = + ∑ x ∈ (Finset.univ.filter fun x : FABL.F₂Cube n ↦ + x ∈ FABL.binaryAffineSubspace E b), 2 * walshTerm f a x := by + rw [Finset.sum_filter] + apply Finset.sum_congr rfl + intro x _hx + by_cases hxb : x ∈ FABL.binaryAffineSubspace E b + · simp only [if_pos hxb, flatSwitch, Pi.add_apply, + affineFlatIndicator, walshTerm] + have hflip : + bitSignInt ((f x + FABL.f₂DotProduct a x) + 1) = + -bitSignInt (f x + FABL.f₂DotProduct a x) := by + rw [bitSignInt_add] + norm_num [bitSignInt] + rw [show f x + 1 + FABL.f₂DotProduct a x = + (f x + FABL.f₂DotProduct a x) + 1 by abel, + hflip] + ring + · simp only [if_neg hxb, flatSwitch, Pi.add_apply, + affineFlatIndicator, walshTerm, add_zero, sub_self] + _ = ∑ x : {x : FABL.F₂Cube n // + x ∈ FABL.binaryAffineSubspace E b}, 2 * walshTerm f a x.1 := by + simpa using + (Finset.sum_subtype + (p := fun x : FABL.F₂Cube n ↦ + x ∈ FABL.binaryAffineSubspace E b) + (Finset.univ.filter fun x : FABL.F₂Cube n ↦ + x ∈ FABL.binaryAffineSubspace E b) + (by simp) (fun x ↦ 2 * walshTerm f a x)) + _ = ∑ x : E, 2 * walshTerm f a (x.1 + b) := by + simpa [affineFlatSubtypeEquiv] using + (Equiv.sum_comp (affineFlatSubtypeEquiv E b) + (fun x : {x : FABL.F₂Cube n // + x ∈ FABL.binaryAffineSubspace E b} ↦ + 2 * walshTerm f a x.1)).symm + _ = 2 * affineFlatWalshSum f E b a := by + rw [affineFlatWalshSum, Finset.mul_sum] + +/-- In coordinates on `E`, the signed Walsh sum on `b + E` is the local +Walsh coefficient, up to the sign contributed by the translate. -/ +theorem affineFlatWalshSum_eq_bitSignInt_mul_walshTransform_restriction + (f : BooleanFunction n) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b a : FABL.F₂Cube n) + (e : FABL.F₂Cube k ≃ₗ[FABL.𝔽₂] E) + (c : FABL.F₂Cube k) + (ha : ∀ y : FABL.F₂Cube k, + FABL.f₂DotProduct a (e y).1 = FABL.f₂DotProduct c y) : + affineFlatWalshSum f E b a = + bitSignInt (FABL.f₂DotProduct a b) * + walshTransform (coordinateAffineSubspaceRestriction f E b e) c := by + classical + rw [affineFlatWalshSum, + ← Fintype.sum_equiv e.toEquiv + (fun y : FABL.F₂Cube k ↦ walshTerm f a ((e y).1 + b)) + (fun x : E ↦ walshTerm f a (x.1 + b)) + (fun _ ↦ rfl), walshTransform, Finset.mul_sum] + apply Finset.sum_congr rfl + intro y _hy + rw [walshTerm, walshTerm, coordinateAffineSubspaceRestriction_apply] + change + bitSignInt (f ((e y).1 + b) + + (a ⬝ᵥ ((e y).1 + b))) = + bitSignInt (a ⬝ᵥ b) * + bitSignInt (f ((e y).1 + b) + c ⬝ᵥ y) + rw [dotProduct_add] + change + bitSignInt (f ((e y).1 + b) + + ((a ⬝ᵥ (e y).1) + a ⬝ᵥ b)) = + bitSignInt (a ⬝ᵥ b) * + bitSignInt (f ((e y).1 + b) + c ⬝ᵥ y) + rw [show a ⬝ᵥ (e y).1 = c ⬝ᵥ y from ha y] + simp_rw [bitSignInt_add] + ring + +/-- Poisson summation identifies the imbalance of the dual-plus-linear +restriction on `a + Eᵖ` with the signed Walsh sum of `f` on `b + E`. -/ +theorem affineSubspaceRestrictionImbalance_bentDual_add_linear + (f : BooleanFunction n) (hf : IsBent f) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (a b : FABL.F₂Cube n) : + affineSubspaceRestrictionImbalance + (bentDual f + FABL.affineFunction 0 b) + (FABL.perpendicularSubspace E) a = + ((2 : ℝ) ^ (n / 2))⁻¹ * + (Nat.card (FABL.perpendicularSubspace E) : ℝ) * + FABL.vectorWalshCharacter b a * + (affineFlatWalshSum f E b a : ℝ) := by + classical + have hpoisson := bentDual_poissonSummationFormula f hf + (FABL.perpendicularSubspace E) a b + rw [FABL.perpendicularSubspace_perpendicularSubspace] at hpoisson + calc + affineSubspaceRestrictionImbalance + (bentDual f + FABL.affineFunction 0 b) + (FABL.perpendicularSubspace E) a = + ∑ u : FABL.perpendicularSubspace E, + realSignView (bentDual f) (a + u.1) * + FABL.vectorWalshCharacter b (a + u.1) := by + unfold affineSubspaceRestrictionImbalance + apply Finset.sum_congr rfl + intro u _hu + rw [FABL.affineSubspaceRestriction_apply, add_comm u.1 a, + realSignView_add, realSignView_affineFunction] + simp + _ = ((2 : ℝ) ^ (n / 2))⁻¹ * + (Nat.card (FABL.perpendicularSubspace E) : ℝ) * + FABL.vectorWalshCharacter b a * + ∑ x : E, realSignView f (b + x.1) * + FABL.vectorWalshCharacter a (b + x.1) := hpoisson + _ = ((2 : ℝ) ^ (n / 2))⁻¹ * + (Nat.card (FABL.perpendicularSubspace E) : ℝ) * + FABL.vectorWalshCharacter b a * + (affineFlatWalshSum f E b a : ℝ) := by + congr 1 + rw [affineFlatWalshSum, Int.cast_sum] + apply Finset.sum_congr rfl + intro x _hx + rw [walshTerm_cast_eq_realSignView_mul_character, add_comm x.1 b] + +/-- Absolute-value form of the dual Poisson identity used in Carlet +Theorem 9, Condition 2. -/ +theorem abs_affineSubspaceRestrictionImbalance_bentDual_add_linear + (f : BooleanFunction n) (hf : IsBent f) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (a b : FABL.F₂Cube n) : + |affineSubspaceRestrictionImbalance + (bentDual f + FABL.affineFunction 0 b) + (FABL.perpendicularSubspace E) a| = + ((2 : ℝ) ^ (n / 2))⁻¹ * + (Nat.card (FABL.perpendicularSubspace E) : ℝ) * + |(affineFlatWalshSum f E b a : ℝ)| := by + have hcard : + 0 ≤ (Nat.card (FABL.perpendicularSubspace E) : ℝ) := by positivity + rw [affineSubspaceRestrictionImbalance_bentDual_add_linear f hf E a b] + rw [abs_mul, abs_mul, abs_mul, abs_inv, abs_pow, + abs_of_nonneg hcard, FABL.abs_vectorWalshCharacter] + norm_num + +private theorem flatWalshSum_eq_zero_or_abs_eq_two_pow_half + (f : BooleanFunction n) (hf : IsBent f) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) + (hswitch : IsBent (flatSwitch f E b)) + (a : FABL.F₂Cube n) : + affineFlatWalshSum f E b a = 0 ∨ + |(affineFlatWalshSum f E b a : ℝ)| = (2 : ℝ) ^ (n / 2) := by + have hdifference := walshTransform_sub_flatSwitch f E b a + rw [walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf a, + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + (flatSwitch f E b) hswitch a] at hdifference + rw [bitSignInt_eq_if_one, bitSignInt_eq_if_one] at hdifference + by_cases hs : bentDual f a = 1 + · by_cases ht : bentDual (flatSwitch f E b) a = 1 + · left + simp only [if_pos hs, if_pos ht] at hdifference + nlinarith + · right + simp only [if_pos hs, if_neg ht] at hdifference + have hsum : affineFlatWalshSum f E b a = -((2 : ℤ) ^ (n / 2)) := by + nlinarith + rw [hsum] + norm_num + · by_cases ht : bentDual (flatSwitch f E b) a = 1 + · right + simp only [if_neg hs, if_pos ht] at hdifference + have hsum : affineFlatWalshSum f E b a = (2 : ℤ) ^ (n / 2) := by + nlinarith + rw [hsum] + norm_num + · left + simp only [if_neg hs, if_neg ht] at hdifference + nlinarith + +/-- The autocorrelation change under affine-flat switching. In directions +outside `E`, the correction is four times the imbalance of the restricted +derivative. -/ +theorem autocorrelation_flatSwitch + (f : BooleanFunction n) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b a : FABL.F₂Cube n) : + autocorrelation (flatSwitch f E b) a = + if a ∈ E then autocorrelation f a + else autocorrelation f a - + 4 * affineSubspaceRestrictionImbalance + (FABL.booleanDerivative f a) E b := by + classical + by_cases ha : a ∈ E + · rw [if_pos ha, autocorrelation, autocorrelation] + apply Finset.sum_congr rfl + intro x _hx + rw [flatSwitch, booleanDerivative_add, realSignView_add] + have hindicator : + FABL.booleanDerivative (affineFlatIndicator E b) a x = 0 := by + rw [FABL.booleanDerivative] + have hmem : + x ∈ FABL.binaryAffineSubspace E b ↔ + x + a ∈ FABL.binaryAffineSubspace E b := by + rw [FABL.mem_binaryAffineSubspace_iff_add_mem, + FABL.mem_binaryAffineSubspace_iff_add_mem] + constructor + · intro hxE + simpa [add_assoc, add_comm a b] using E.add_mem hxE ha + · intro hxaE + have := E.add_mem hxaE ha + simpa [add_assoc, add_comm a b, ZModModule.add_self] using this + by_cases hx : x ∈ FABL.binaryAffineSubspace E b + · have hxa := hmem.mp hx + simp [affineFlatIndicator, hx, hxa] + · have hxa : x + a ∉ FABL.binaryAffineSubspace E b := + fun h ↦ hx (hmem.mpr h) + simp [affineFlatIndicator, hx, hxa] + have hsign : + realSignView (FABL.booleanDerivative (affineFlatIndicator E b) a) x = + 1 := by + simp only [realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction, hindicator] + norm_num + rw [hsign, mul_one] + · rw [if_neg ha, autocorrelation, autocorrelation] + have hfirst : + (∑ x, realSignView (FABL.booleanDerivative f a) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x) = + affineSubspaceRestrictionImbalance + (FABL.booleanDerivative f a) E b := + sum_mul_setIndicator_affineFlat + (realSignView (FABL.booleanDerivative f a)) E b + have hsecond := sum_derivativeSign_mul_setIndicator_translate f E b a + calc + (∑ x, realSignView + (FABL.booleanDerivative (flatSwitch f E b) a) x) = + ∑ x, realSignView (FABL.booleanDerivative f a) x * + ((1 - 2 * FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x) * + (1 - 2 * FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) + (x + a))) := by + apply Finset.sum_congr rfl + intro x _hx + rw [flatSwitch, booleanDerivative_add, realSignView_add, + realSignView_booleanDerivative f a x, + realSignView_booleanDerivative (affineFlatIndicator E b) a x, + realSignView_affineFlatIndicator, + realSignView_affineFlatIndicator] + _ = (∑ x, realSignView (FABL.booleanDerivative f a) x) - + 2 * (∑ x, realSignView (FABL.booleanDerivative f a) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x) - + 2 * (∑ x, realSignView (FABL.booleanDerivative f a) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) + (x + a)) := by + calc + (∑ x, realSignView (FABL.booleanDerivative f a) x * + ((1 - 2 * FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x) * + (1 - 2 * FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) + (x + a)))) = + ∑ x, (realSignView (FABL.booleanDerivative f a) x - + 2 * (realSignView (FABL.booleanDerivative f a) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x) - + 2 * (realSignView (FABL.booleanDerivative f a) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) + (x + a))) := by + apply Finset.sum_congr rfl + intro x _hx + have hzero := + setIndicator_affineFlat_mul_translate_eq_zero E b a x ha + calc + realSignView (FABL.booleanDerivative f a) x * + ((1 - 2 * FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x) * + (1 - 2 * FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) + (x + a))) = + (realSignView (FABL.booleanDerivative f a) x - + 2 * (realSignView (FABL.booleanDerivative f a) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x) - + 2 * (realSignView (FABL.booleanDerivative f a) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) + (x + a))) + + 4 * realSignView (FABL.booleanDerivative f a) x * + (FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) x * + FABL.setIndicator + (FABL.binaryAffineSubspace E b : Set (FABL.F₂Cube n)) + (x + a)) := by ring + _ = _ := by rw [hzero]; ring + _ = _ := by + rw [Finset.sum_sub_distrib, Finset.sum_sub_distrib, + ← Finset.mul_sum, ← Finset.mul_sum] + _ = (∑ x, realSignView (FABL.booleanDerivative f a) x) - + 4 * affineSubspaceRestrictionImbalance + (FABL.booleanDerivative f a) E b := by + rw [hfirst, hsecond] + ring + +/-- Carlet Theorem 9, Condition 1: switching a bent function on `b + E` +is bent exactly when every derivative in a direction outside `E` is balanced +on that flat. -/ +theorem isBent_flatSwitch_iff_derivative_balanced_on_affineFlat + (f : BooleanFunction n) (hf : IsBent f) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) : + IsBent (flatSwitch f E b) ↔ + ∀ a : FABL.F₂Cube n, a ∉ E → + IsBalancedOnAffineFlat (FABL.booleanDerivative f a) E b := by + constructor + · intro hswitch a ha + have haNe : a ≠ 0 := by + intro haZero + apply ha + subst a + exact E.zero_mem + have hfAuto : autocorrelation f a = 0 := + (isBalanced_booleanDerivative_iff_autocorrelation_eq_zero f a).1 + ((isBent_iff_forall_nonzero_derivative_isBalanced f).1 hf a haNe) + have hswitchAuto : autocorrelation (flatSwitch f E b) a = 0 := + (isBalanced_booleanDerivative_iff_autocorrelation_eq_zero + (flatSwitch f E b) a).1 + ((isBent_iff_forall_nonzero_derivative_isBalanced + (flatSwitch f E b)).1 hswitch a haNe) + rw [autocorrelation_flatSwitch, if_neg ha, hfAuto] at hswitchAuto + change affineSubspaceRestrictionImbalance + (FABL.booleanDerivative f a) E b = 0 + linarith + · intro hcondition + apply (isBent_iff_forall_nonzero_derivative_isBalanced + (flatSwitch f E b)).2 + intro a haNe + apply (isBalanced_booleanDerivative_iff_autocorrelation_eq_zero + (flatSwitch f E b) a).2 + have hfAuto : autocorrelation f a = 0 := + (isBalanced_booleanDerivative_iff_autocorrelation_eq_zero f a).1 + ((isBent_iff_forall_nonzero_derivative_isBalanced f).1 hf a haNe) + by_cases ha : a ∈ E + · rw [autocorrelation_flatSwitch, if_pos ha, hfAuto] + · have hflat := hcondition a ha + change affineSubspaceRestrictionImbalance + (FABL.booleanDerivative f a) E b = 0 at hflat + rw [autocorrelation_flatSwitch, if_neg ha, hfAuto, hflat] + norm_num + +/-- Carlet Theorem 9, Condition 2: switching a bent function on `b + E` +is bent exactly when `bentDual f + b · x` is constant or balanced on every +coset of `Eᵖ`. -/ +theorem isBent_flatSwitch_iff_bentDual_add_linear_constant_or_balanced + (f : BooleanFunction n) (hf : IsBent f) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) : + IsBent (flatSwitch f E b) ↔ + ∀ a : FABL.F₂Cube n, + IsConstantOrBalancedOnAffineFlat + (bentDual f + FABL.affineFunction 0 b) + (FABL.perpendicularSubspace E) a := by + constructor + · intro hswitch a + rw [IsConstantOrBalancedOnAffineFlat] + rcases flatWalshSum_eq_zero_or_abs_eq_two_pow_half + f hf E b hswitch a with hzero | habs + · left + rw [IsBalancedOnAffineFlat, + affineSubspaceRestrictionImbalance_bentDual_add_linear + f hf E a b, hzero] + norm_num + · right + rw [abs_affineSubspaceRestrictionImbalance_bentDual_add_linear + f hf E a b, habs] + have hp : (2 : ℝ) ^ (n / 2) ≠ 0 := by positivity + calc + ((2 : ℝ) ^ (n / 2))⁻¹ * + (Nat.card (FABL.perpendicularSubspace E) : ℝ) * + (2 : ℝ) ^ (n / 2) = + (Nat.card (FABL.perpendicularSubspace E) : ℝ) * + (((2 : ℝ) ^ (n / 2))⁻¹ * (2 : ℝ) ^ (n / 2)) := by ring + _ = Nat.card (FABL.perpendicularSubspace E) := by + rw [inv_mul_cancel₀ hp, mul_one] + · intro hcondition + have hnEven := even_of_isBent f hf + by_cases hnTwo : 2 ≤ n + · apply (isBent_iff_forall_walshTransform_modeq + (flatSwitch f E b) hnEven hnTwo).2 + intro a + have hflat : affineFlatWalshSum f E b a = 0 ∨ + |(affineFlatWalshSum f E b a : ℝ)| = (2 : ℝ) ^ (n / 2) := by + rcases hcondition a with hbalanced | hextremal + · left + rw [IsBalancedOnAffineFlat] at hbalanced + have hrelation := + affineSubspaceRestrictionImbalance_bentDual_add_linear + f hf E a b + rw [hbalanced] at hrelation + have hpInv : ((2 : ℝ) ^ (n / 2))⁻¹ ≠ 0 := by positivity + have hcard : + (Nat.card (FABL.perpendicularSubspace E) : ℝ) ≠ 0 := by + exact_mod_cast (Nat.card_pos.ne' : + Nat.card (FABL.perpendicularSubspace E) ≠ 0) + have hcharacter : FABL.vectorWalshCharacter b a ≠ 0 := by + intro hzero + have habs := FABL.abs_vectorWalshCharacter b a + rw [hzero, abs_zero] at habs + norm_num at habs + have hcoefficient : + ((2 : ℝ) ^ (n / 2))⁻¹ * + (Nat.card (FABL.perpendicularSubspace E) : ℝ) * + FABL.vectorWalshCharacter b a ≠ 0 := + mul_ne_zero (mul_ne_zero hpInv hcard) hcharacter + have hcast : (affineFlatWalshSum f E b a : ℝ) = 0 := + (mul_eq_zero.mp hrelation.symm).resolve_left hcoefficient + exact_mod_cast hcast + · right + have habsRelation := + abs_affineSubspaceRestrictionImbalance_bentDual_add_linear + f hf E a b + rw [hextremal] at habsRelation + have hp : (2 : ℝ) ^ (n / 2) ≠ 0 := by positivity + have hcard : + (Nat.card (FABL.perpendicularSubspace E) : ℝ) ≠ 0 := by + exact_mod_cast (Nat.card_pos.ne' : + Nat.card (FABL.perpendicularSubspace E) ≠ 0) + have hcancel : + 1 = ((2 : ℝ) ^ (n / 2))⁻¹ * + |(affineFlatWalshSum f E b a : ℝ)| := by + apply mul_left_cancel₀ hcard + calc + (Nat.card (FABL.perpendicularSubspace E) : ℝ) * 1 = + Nat.card (FABL.perpendicularSubspace E) := by ring + _ = ((2 : ℝ) ^ (n / 2))⁻¹ * + (Nat.card (FABL.perpendicularSubspace E) : ℝ) * + |(affineFlatWalshSum f E b a : ℝ)| := habsRelation + _ = (Nat.card (FABL.perpendicularSubspace E) : ℝ) * + (((2 : ℝ) ^ (n / 2))⁻¹ * + |(affineFlatWalshSum f E b a : ℝ)|) := by ring + calc + |(affineFlatWalshSum f E b a : ℝ)| = + (2 : ℝ) ^ (n / 2) * + (((2 : ℝ) ^ (n / 2))⁻¹ * + |(affineFlatWalshSum f E b a : ℝ)|) := by + rw [← mul_assoc, mul_inv_cancel₀ hp, one_mul] + _ = (2 : ℝ) ^ (n / 2) * 1 := by rw [← hcancel] + _ = (2 : ℝ) ^ (n / 2) := by ring + have hdifference := walshTransform_sub_flatSwitch f E b a + have hdiv : (2 : ℤ) ^ (n / 2 + 1) ∣ + walshTransform f a - walshTransform (flatSwitch f E b) a := by + rcases hflat with hzero | habs + · rw [hdifference, hzero] + exact dvd_zero _ + · rcases eq_or_eq_neg_of_abs_eq habs with hpositive | hnegative + · have hpositiveInt : + affineFlatWalshSum f E b a = (2 : ℤ) ^ (n / 2) := by + exact_mod_cast hpositive + refine ⟨1, ?_⟩ + rw [hdifference, hpositiveInt, pow_succ, mul_one] + ring + · have hnegativeInt : + affineFlatWalshSum f E b a = -((2 : ℤ) ^ (n / 2)) := by + exact_mod_cast hnegative + refine ⟨-1, ?_⟩ + rw [hdifference, hnegativeInt, pow_succ] + ring + have hswitchMod : + Int.ModEq (2 ^ (n / 2 + 1)) + (walshTransform (flatSwitch f E b) a) (walshTransform f a) := + Int.modEq_iff_dvd.mpr hdiv + exact hswitchMod.trans + (((isBent_iff_forall_walshTransform_modeq f hnEven hnTwo).1 hf) a) + · apply (isBent_flatSwitch_iff_derivative_balanced_on_affineFlat + f hf E b).2 + intro a ha + exfalso + apply ha + have hnZero : n = 0 := by + rcases hnEven with ⟨m, hm⟩ + omega + subst n + have haZero : a = 0 := Subsingleton.elim _ _ + simpa [haZero] using E.zero_mem + +/-- The two criteria in Carlet Theorem 9 are equivalent. -/ +theorem derivative_balanced_on_affineFlat_iff_bentDual_add_linear_constant_or_balanced + (f : BooleanFunction n) (hf : IsBent f) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) : + (∀ a : FABL.F₂Cube n, a ∉ E → + IsBalancedOnAffineFlat (FABL.booleanDerivative f a) E b) ↔ + ∀ a : FABL.F₂Cube n, + IsConstantOrBalancedOnAffineFlat + (bentDual f + FABL.affineFunction 0 b) + (FABL.perpendicularSubspace E) a := + (isBent_flatSwitch_iff_derivative_balanced_on_affineFlat f hf E b).symm.trans + (isBent_flatSwitch_iff_bentDual_add_linear_constant_or_balanced f hf E b) + +private theorem bitSignInt_mul_self_flatSwitching (z : FABL.𝔽₂) : + bitSignInt z * bitSignInt z = 1 := by + fin_cases z <;> rfl + +private theorem exists_bitSignInt_sub_eq_two_mul + (s t : FABL.𝔽₂) : + ∃ z : ℤ, bitSignInt s - bitSignInt t = 2 * z := by + fin_cases s <;> fin_cases t <;> + first | exact ⟨0, by rfl⟩ | exact ⟨1, by rfl⟩ | exact ⟨-1, by rfl⟩ + +/-- If both the original function and its affine-flat switch are bent, every +Walsh coefficient of the restriction to the switched flat is divisible by +`2^(n/2)`. -/ +theorem two_pow_half_dvd_walshTransform_affineFlatRestriction + (f : BooleanFunction n) (hf : IsBent f) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) + (hswitch : IsBent (flatSwitch f E b)) + (e : FABL.F₂Cube k ≃ₗ[FABL.𝔽₂] E) + (c : FABL.F₂Cube k) : + (2 : ℤ) ^ (n / 2) ∣ + walshTransform (coordinateAffineSubspaceRestriction f E b e) c := by + obtain ⟨a, ha⟩ := exists_ambientFrequency_restricts_to_subspace E e c + have hdifference := walshTransform_sub_flatSwitch f E b a + rw [affineFlatWalshSum_eq_bitSignInt_mul_walshTransform_restriction + f E b a e c ha, + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf a, + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + (flatSwitch f E b) hswitch a] at hdifference + obtain ⟨z, hz⟩ := exists_bitSignInt_sub_eq_two_mul + (bentDual f a) (bentDual (flatSwitch f E b) a) + have hcancel : + (2 : ℤ) ^ (n / 2) * z = + bitSignInt (FABL.f₂DotProduct a b) * + walshTransform (coordinateAffineSubspaceRestriction f E b e) c := by + rw [← mul_sub, hz] at hdifference + nlinarith + refine ⟨bitSignInt (FABL.f₂DotProduct a b) * z, ?_⟩ + calc + walshTransform (coordinateAffineSubspaceRestriction f E b e) c = + (bitSignInt (FABL.f₂DotProduct a b) * + bitSignInt (FABL.f₂DotProduct a b)) * + walshTransform (coordinateAffineSubspaceRestriction f E b e) c := by + rw [bitSignInt_mul_self_flatSwitching, one_mul] + _ = bitSignInt (FABL.f₂DotProduct a b) * + (bitSignInt (FABL.f₂DotProduct a b) * + walshTransform (coordinateAffineSubspaceRestriction f E b e) c) := by + ring + _ = bitSignInt (FABL.f₂DotProduct a b) * + ((2 : ℤ) ^ (n / 2) * z) := by rw [← hcancel] + _ = (2 : ℤ) ^ (n / 2) * + (bitSignInt (FABL.f₂DotProduct a b) * z) := by ring + +/-- Carlet Theorem 9: if a bent function remains bent after switching on +`b + E`, then `E` has dimension at least `n/2`. -/ +theorem half_dimension_le_finrank_of_isBent_flatSwitch + (f : BooleanFunction n) (hf : IsBent f) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) + (hswitch : IsBent (flatSwitch f E b)) : + n / 2 ≤ Module.finrank FABL.𝔽₂ E := by + let e : FABL.F₂Cube (Module.finrank FABL.𝔽₂ E) ≃ₗ[FABL.𝔽₂] E := + LinearEquiv.ofFinrankEq _ _ (by + rw [Module.finrank_fintype_fun_eq_card] + simp) + let h := coordinateAffineSubspaceRestriction f E b e + obtain ⟨c, hc⟩ := exists_walshTransform_ne_zero h + have hdiv : (2 : ℤ) ^ (n / 2) ∣ walshTransform h c := by + exact two_pow_half_dvd_walshTransform_affineFlatRestriction + f hf E b hswitch e c + obtain ⟨z, hz⟩ := hdiv + have hzNe : z ≠ 0 := by + intro hzZero + apply hc + rw [hz, hzZero, mul_zero] + have hzAbs : 1 ≤ z.natAbs := by + exact Int.natAbs_pos.mpr hzNe + have hlower : + 2 ^ (n / 2) ≤ (walshTransform h c).natAbs := by + rw [hz, Int.natAbs_mul] + norm_num + exact hzAbs + have hboundReal := abs_walshTransform_le_two_pow h c + have hbound : + (walshTransform h c).natAbs ≤ + 2 ^ Module.finrank FABL.𝔽₂ E := by + have hcast : + ((walshTransform h c).natAbs : ℝ) ≤ + (2 ^ Module.finrank FABL.𝔽₂ E : ℝ) := by + simpa only [Nat.cast_natAbs, Int.cast_abs, Nat.cast_pow, + Nat.cast_ofNat] using hboundReal + exact_mod_cast hcast + exact (Nat.pow_le_pow_iff_right (by omega : 1 < (2 : ℕ))).mp + (hlower.trans hbound) + +/-- Carlet Theorem 9: when the switch is bent, the algebraic degree of the +restriction to `b + E` is at most `dim(E) - n/2 + 1`. -/ +theorem functionAlgebraicDegree_affineFlatRestriction_le_of_isBent_flatSwitch + (f : BooleanFunction n) (hf : IsBent f) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) + (hswitch : IsBent (flatSwitch f E b)) + (e : FABL.F₂Cube k ≃ₗ[FABL.𝔽₂] E) : + FABL.functionAlgebraicDegree + (coordinateAffineSubspaceRestriction f E b e) ≤ + k - n / 2 + 1 := by + have hdim : Module.finrank FABL.𝔽₂ E = k := by + have heq := LinearEquiv.finrank_eq e + rw [Module.finrank_fintype_fun_eq_card] at heq + simpa using heq.symm + have hhalf : n / 2 ≤ k := by + rw [← hdim] + exact half_dimension_le_finrank_of_isBent_flatSwitch f hf E b hswitch + by_cases hhalfZero : n / 2 = 0 + · exact (FABL.functionAlgebraicDegree_le_dimension + (coordinateAffineSubspaceRestriction f E b e)).trans (by omega) + have hhalfPos : 1 ≤ n / 2 := by omega + by_cases hkTwo : 2 ≤ k + · exact functionAlgebraicDegree_le_of_two_pow_dvd_walshTransform + (coordinateAffineSubspaceRestriction f E b e) (n / 2) + hkTwo hhalfPos hhalf + (two_pow_half_dvd_walshTransform_affineFlatRestriction + f hf E b hswitch e) + · exact (FABL.functionAlgebraicDegree_le_dimension + (coordinateAffineSubspaceRestriction f E b e)).trans (by omega) + +/-- Carlet Theorem 9, converse: if `E` has dimension `n/2` and the +restriction of a bent function to `b + E` is affine, switching on that flat +is bent. -/ +theorem isBent_flatSwitch_of_half_dimension_of_restriction_degree_le_one + (f : BooleanFunction n) (hf : IsBent f) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (b : FABL.F₂Cube n) + (e : FABL.F₂Cube k ≃ₗ[FABL.𝔽₂] E) + (hk : k = n / 2) + (hdegree : FABL.functionAlgebraicDegree + (coordinateAffineSubspaceRestriction f E b e) ≤ 1) : + IsBent (flatSwitch f E b) := by + have hnEven := even_of_isBent f hf + by_cases hnTwo : 2 ≤ n + · obtain ⟨d, u, hrestriction⟩ := + FABL.exists_affineFunction_of_functionAlgebraicDegree_le_one + (coordinateAffineSubspaceRestriction f E b e) hdegree + apply (isBent_iff_forall_walshTransform_modeq + (flatSwitch f E b) hnEven hnTwo).2 + intro a + let c := coordinateRestrictedAffineFrequency E e a + have hfrequency : ∀ y : FABL.F₂Cube k, + FABL.f₂DotProduct a (e y).1 = FABL.f₂DotProduct c y := by + intro y + exact (f₂DotProduct_coordinateRestrictedAffineFrequency E e a y).symm + have hdifference := walshTransform_sub_flatSwitch f E b a + rw [affineFlatWalshSum_eq_bitSignInt_mul_walshTransform_restriction + f E b a e c hfrequency, hrestriction, + walshTransform_affineFunction] at hdifference + have hdiffDiv : + (2 : ℤ) ^ (n / 2 + 1) ∣ + walshTransform f a - walshTransform (flatSwitch f E b) a := by + by_cases hcu : c = u + · rw [if_pos hcu, hk] at hdifference + refine ⟨bitSignInt (FABL.f₂DotProduct a b) * bitSignInt d, ?_⟩ + calc + walshTransform f a - walshTransform (flatSwitch f E b) a = + 2 * (bitSignInt (FABL.f₂DotProduct a b) * + (bitSignInt d * (2 ^ (n / 2) : ℤ))) := by + rw [hdifference] + _ = (2 : ℤ) ^ (n / 2 + 1) * + (bitSignInt (FABL.f₂DotProduct a b) * bitSignInt d) := by + rw [pow_succ] + ring + · rw [if_neg hcu] at hdifference + refine ⟨0, ?_⟩ + rw [mul_zero] + linarith + have hswitchMod : + Int.ModEq (2 ^ (n / 2 + 1)) + (walshTransform (flatSwitch f E b) a) (walshTransform f a) := + Int.modEq_iff_dvd.mpr hdiffDiv + exact hswitchMod.trans + (((isBent_iff_forall_walshTransform_modeq f hnEven hnTwo).1 hf) a) + · apply (isBent_flatSwitch_iff_derivative_balanced_on_affineFlat + f hf E b).2 + intro a ha + exfalso + apply ha + have hnZero : n = 0 := by + rcases hnEven with ⟨m, hm⟩ + omega + subst n + have haZero : a = 0 := Subsingleton.elim _ _ + simpa [haZero] using E.zero_mem + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/FourierUncertainty.lean b/CryptBoolean/Carlet/Chapter06/FourierUncertainty.lean new file mode 100644 index 0000000..ee8c50a --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/FourierUncertainty.lean @@ -0,0 +1,610 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter02.SpectralSupport + +import Mathlib.Algebra.Order.Chebyshev + +/-! +# Fourier uncertainty for pseudo-Boolean functions + +Carlet Proposition 27: a nonzero pseudo-Boolean function and its raw Fourier +transform cannot both have small support. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +open FABL + +variable {n : ℕ} + +/-- The finite support of a pseudo-Boolean function. -/ +noncomputable def pseudoBooleanSupport (φ : PseudoBooleanFunction n) : + Finset (FABL.F₂Cube n) := + Finset.univ.filter fun x ↦ φ x ≠ 0 + +@[simp] theorem mem_pseudoBooleanSupport (φ : PseudoBooleanFunction n) + (x : FABL.F₂Cube n) : + x ∈ pseudoBooleanSupport φ ↔ φ x ≠ 0 := by + classical + simp [pseudoBooleanSupport] + +private theorem sum_pseudoBooleanSupport_pow_eq_sum + (φ : PseudoBooleanFunction n) (k : ℕ) (hk : k ≠ 0) : + (∑ x ∈ pseudoBooleanSupport φ, φ x ^ k) = ∑ x, φ x ^ k := by + apply Finset.sum_subset (Finset.subset_univ _) + intro x _hx hnot + have hzero : φ x = 0 := by + exact not_ne_iff.mp (by simpa only [mem_pseudoBooleanSupport] using hnot) + simp [hzero, hk] + +private theorem sum_rawFourierSupport_pow_eq_sum + (φ : PseudoBooleanFunction n) (k : ℕ) (hk : k ≠ 0) : + (∑ u ∈ rawFourierSupport φ, rawFourierTransform φ u ^ k) = + ∑ u, rawFourierTransform φ u ^ k := by + apply Finset.sum_subset (Finset.subset_univ _) + intro u _hu hnot + have hzero : rawFourierTransform φ u = 0 := by + exact not_ne_iff.mp (by simpa only [mem_rawFourierSupport] using hnot) + simp [hzero, hk] + +private theorem sum_sq_pos_of_pseudoBoolean_ne_zero + (φ : PseudoBooleanFunction n) (hφ : φ ≠ 0) : + 0 < ∑ x, φ x ^ 2 := by + classical + obtain ⟨x, hx⟩ := Function.ne_iff.mp hφ + exact Finset.sum_pos' + (fun y _hy ↦ sq_nonneg (φ y)) + ⟨x, Finset.mem_univ x, sq_pos_of_ne_zero hx⟩ + +private theorem rawFourierTransform_sq_le_card_support_mul_sum_sq + (φ : PseudoBooleanFunction n) (u : FABL.F₂Cube n) : + rawFourierTransform φ u ^ 2 ≤ + ((pseudoBooleanSupport φ).card : ℝ) * ∑ x, φ x ^ 2 := by + classical + have hsum : + (∑ x ∈ pseudoBooleanSupport φ, + φ x * FABL.vectorWalshCharacter u x) = + ∑ x, φ x * FABL.vectorWalshCharacter u x := by + apply Finset.sum_subset (Finset.subset_univ _) + intro x _hx hnot + have hzero : φ x = 0 := by + exact not_ne_iff.mp (by simpa only [mem_pseudoBooleanSupport] using hnot) + simp [hzero] + have hcauchy := sq_sum_le_card_mul_sum_sq + (s := pseudoBooleanSupport φ) + (f := fun x ↦ φ x * FABL.vectorWalshCharacter u x) + calc + rawFourierTransform φ u ^ 2 = + (∑ x ∈ pseudoBooleanSupport φ, + φ x * FABL.vectorWalshCharacter u x) ^ 2 := by + rw [rawFourierTransform, hsum] + _ ≤ ((pseudoBooleanSupport φ).card : ℝ) * + ∑ x ∈ pseudoBooleanSupport φ, + (φ x * FABL.vectorWalshCharacter u x) ^ 2 := hcauchy + _ = ((pseudoBooleanSupport φ).card : ℝ) * + ∑ x ∈ pseudoBooleanSupport φ, φ x ^ 2 := by + congr 1 + apply Finset.sum_congr rfl + intro x _hx + rw [mul_pow] + have hcharacter : FABL.vectorWalshCharacter u x ^ 2 = 1 := by + rw [← sq_abs, FABL.abs_vectorWalshCharacter, one_pow] + rw [hcharacter, mul_one] + _ = ((pseudoBooleanSupport φ).card : ℝ) * ∑ x, φ x ^ 2 := by + rw [sum_pseudoBooleanSupport_pow_eq_sum φ 2 (by norm_num)] + +private theorem eq_on_of_sq_sum_eq_card_mul_sum_sq + {α : Type*} (s : Finset α) (q : α → ℝ) + (hs : s.Nonempty) + (heq : (∑ x ∈ s, q x) ^ 2 = (s.card : ℝ) * ∑ x ∈ s, q x ^ 2) : + ∀ x ∈ s, ∀ y ∈ s, q x = q y := by + classical + let mean : ℝ := (∑ x ∈ s, q x) / (s.card : ℝ) + have hcard : (s.card : ℝ) ≠ 0 := by + exact_mod_cast Finset.card_ne_zero.mpr hs + have hvariance : ∑ x ∈ s, (q x - mean) ^ 2 = 0 := by + have hpoint (x : α) : + (q x - mean) ^ 2 = q x ^ 2 - 2 * mean * q x + mean ^ 2 := by + ring + simp_rw [hpoint, Finset.sum_add_distrib, Finset.sum_sub_distrib] + have hmiddle : + (∑ x ∈ s, 2 * mean * q x) = 2 * mean * ∑ x ∈ s, q x := by + rw [Finset.mul_sum] + rw [hmiddle] + simp only [Finset.sum_const, nsmul_eq_mul] + dsimp [mean] + field_simp [hcard] + nlinarith [heq] + have hterm (x : α) (hx : x ∈ s) : q x = mean := by + have hxzero := (Finset.sum_eq_zero_iff_of_nonneg + (fun y _hy ↦ sq_nonneg (q y - mean))).mp hvariance x hx + nlinarith [sq_nonneg (q x - mean)] + intro x hx y hy + rw [hterm x hx, hterm y hy] + +private theorem rawFourierTransform_sq_eq_card_support_mul_sum_sq_of_eq + (φ : PseudoBooleanFunction n) + (hproduct : + (pseudoBooleanSupport φ).card * (rawFourierSupport φ).card = 2 ^ n) + (u : FABL.F₂Cube n) (hu : u ∈ rawFourierSupport φ) : + rawFourierTransform φ u ^ 2 = + ((pseudoBooleanSupport φ).card : ℝ) * ∑ x, φ x ^ 2 := by + classical + let energy : ℝ := ∑ x, φ x ^ 2 + have hproductReal : + (((pseudoBooleanSupport φ).card * (rawFourierSupport φ).card : ℕ) : ℝ) = + (2 : ℝ) ^ n := by + exact_mod_cast hproduct + have hparseval : + ∑ v, rawFourierTransform φ v ^ 2 = (2 : ℝ) ^ n * energy := by + simpa only [pow_two, energy] using sum_rawFourierTransform_mul φ φ + have hsums : + (∑ v ∈ rawFourierSupport φ, rawFourierTransform φ v ^ 2) = + ∑ _v ∈ rawFourierSupport φ, + ((pseudoBooleanSupport φ).card : ℝ) * energy := by + calc + (∑ v ∈ rawFourierSupport φ, rawFourierTransform φ v ^ 2) = + ∑ v, rawFourierTransform φ v ^ 2 := + sum_rawFourierSupport_pow_eq_sum φ 2 (by norm_num) + _ = (2 : ℝ) ^ n * energy := hparseval + _ = (((pseudoBooleanSupport φ).card * + (rawFourierSupport φ).card : ℕ) : ℝ) * energy := by + rw [hproductReal] + _ = ∑ _v ∈ rawFourierSupport φ, + ((pseudoBooleanSupport φ).card : ℝ) * energy := by + simp only [Finset.sum_const, nsmul_eq_mul, Nat.cast_mul] + ring + exact (Finset.sum_eq_sum_iff_of_le + (fun v _hv ↦ rawFourierTransform_sq_le_card_support_mul_sum_sq φ v)).mp + hsums u hu + +private theorem support_modulated_value_eq_of_uncertainty_eq + (φ : PseudoBooleanFunction n) (hφ : φ ≠ 0) + (hproduct : + (pseudoBooleanSupport φ).card * (rawFourierSupport φ).card = 2 ^ n) + (u x y : FABL.F₂Cube n) + (hu : u ∈ rawFourierSupport φ) + (hx : x ∈ pseudoBooleanSupport φ) + (hy : y ∈ pseudoBooleanSupport φ) : + φ x * FABL.vectorWalshCharacter u x = + φ y * FABL.vectorWalshCharacter u y := by + classical + let q : FABL.F₂Cube n → ℝ := fun z ↦ + φ z * FABL.vectorWalshCharacter u z + have hsupportNonempty : (pseudoBooleanSupport φ).Nonempty := by + obtain ⟨z, hz⟩ := Function.ne_iff.mp hφ + exact ⟨z, (mem_pseudoBooleanSupport φ z).mpr hz⟩ + have hsum : + (∑ z ∈ pseudoBooleanSupport φ, q z) = rawFourierTransform φ u := by + dsimp [q] + rw [rawFourierTransform] + apply Finset.sum_subset (Finset.subset_univ _) + intro z _hz hnot + have hzero : φ z = 0 := by + exact not_ne_iff.mp (by simpa only [mem_pseudoBooleanSupport] using hnot) + simp [hzero] + have hsumSq : + (∑ z ∈ pseudoBooleanSupport φ, q z ^ 2) = ∑ z, φ z ^ 2 := by + calc + (∑ z ∈ pseudoBooleanSupport φ, q z ^ 2) = + ∑ z ∈ pseudoBooleanSupport φ, φ z ^ 2 := by + apply Finset.sum_congr rfl + intro z _hz + dsimp [q] + rw [mul_pow] + have hcharacter : FABL.vectorWalshCharacter u z ^ 2 = 1 := by + rw [← sq_abs, FABL.abs_vectorWalshCharacter, one_pow] + rw [hcharacter, mul_one] + _ = ∑ z, φ z ^ 2 := + sum_pseudoBooleanSupport_pow_eq_sum φ 2 (by norm_num) + apply eq_on_of_sq_sum_eq_card_mul_sum_sq + (pseudoBooleanSupport φ) q hsupportNonempty + · rw [hsum, hsumSq] + exact rawFourierTransform_sq_eq_card_support_mul_sum_sq_of_eq + φ hproduct u hu + · exact hx + · exact hy + +/-- Carlet Proposition 27's uncertainty inequality: for every nonzero +pseudo-Boolean function, the product of its value-support size and raw +Fourier-support size is at least the size of the binary cube. -/ +theorem two_pow_le_card_pseudoBooleanSupport_mul_card_rawFourierSupport + (φ : PseudoBooleanFunction n) (hφ : φ ≠ 0) : + 2 ^ n ≤ (pseudoBooleanSupport φ).card * (rawFourierSupport φ).card := by + classical + let energy : ℝ := ∑ x, φ x ^ 2 + have henergy : 0 < energy := + sum_sq_pos_of_pseudoBoolean_ne_zero φ hφ + have hparseval : + ∑ u, rawFourierTransform φ u ^ 2 = (2 : ℝ) ^ n * energy := by + simpa only [pow_two, energy] using + sum_rawFourierTransform_mul φ φ + have hscaled : + (2 : ℝ) ^ n * energy ≤ + (((pseudoBooleanSupport φ).card * (rawFourierSupport φ).card : ℕ) : ℝ) * + energy := by + calc + (2 : ℝ) ^ n * energy = + ∑ u, rawFourierTransform φ u ^ 2 := hparseval.symm + _ = ∑ u ∈ rawFourierSupport φ, rawFourierTransform φ u ^ 2 := by + rw [sum_rawFourierSupport_pow_eq_sum φ 2 (by norm_num)] + _ ≤ ∑ _u ∈ rawFourierSupport φ, + ((pseudoBooleanSupport φ).card : ℝ) * energy := by + apply Finset.sum_le_sum + intro u _hu + exact rawFourierTransform_sq_le_card_support_mul_sum_sq φ u + _ = (((pseudoBooleanSupport φ).card * + (rawFourierSupport φ).card : ℕ) : ℝ) * energy := by + simp only [Finset.sum_const, nsmul_eq_mul, Nat.cast_mul] + ring + have hcast : + (2 ^ n : ℝ) ≤ + (((pseudoBooleanSupport φ).card * (rawFourierSupport φ).card : ℕ) : ℝ) := + le_of_mul_le_mul_right hscaled henergy + exact_mod_cast hcast + +/-- A pseudo-Boolean function is a modulated affine-flat indicator when it is +a nonzero real multiple of one Walsh character on an affine flat and vanishes +off that flat. -/ +def IsModulatedAffineFlatIndicator (φ : PseudoBooleanFunction n) : Prop := + ∃ c : ℝ, c ≠ 0 ∧ + ∃ H : Submodule FABL.𝔽₂ (FABL.F₂Cube n), + ∃ a u : FABL.F₂Cube n, + φ = fun x ↦ c * FABL.vectorWalshCharacter u x * + FABL.setIndicator + (FABL.binaryAffineSubspace H a : Set (FABL.F₂Cube n)) x + +private theorem card_pseudoBooleanSupport_le_card_submodule_of_affineFlatIndicator + (φ : PseudoBooleanFunction n) (c : ℝ) + (H : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (a u : FABL.F₂Cube n) + (hφ : φ = fun x ↦ c * FABL.vectorWalshCharacter u x * + FABL.setIndicator + (FABL.binaryAffineSubspace H a : Set (FABL.F₂Cube n)) x) : + (pseudoBooleanSupport φ).card ≤ Nat.card H := by + classical + letI : Fintype H := Fintype.ofFinite H + have support_mem_flat (x : pseudoBooleanSupport φ) : + x.1 ∈ FABL.binaryAffineSubspace H a := by + by_contra hx + have hzero : + FABL.setIndicator + (FABL.binaryAffineSubspace H a : Set (FABL.F₂Cube n)) x.1 = 0 := by + simp [FABL.setIndicator, hx] + have hxne : φ x.1 ≠ 0 := (mem_pseudoBooleanSupport φ x.1).mp x.2 + have hφx := congrFun hφ x.1 + rw [hφx, hzero, mul_zero] at hxne + exact hxne rfl + let toDirection : pseudoBooleanSupport φ → H := fun x ↦ + ⟨x.1 + a, + (FABL.mem_binaryAffineSubspace_iff_add_mem H a x.1).mp + (support_mem_flat x)⟩ + have hinjective : Function.Injective toDirection := by + intro x y hxy + apply Subtype.ext + have hvalue := congrArg Subtype.val hxy + exact add_right_cancel hvalue + have hcard : + Fintype.card (pseudoBooleanSupport φ) ≤ Fintype.card H := + Fintype.card_le_of_injective toDirection hinjective + simpa only [Fintype.card_coe, Nat.card_eq_fintype_card] using hcard + +private theorem card_rawFourierSupport_le_card_perpendicular_of_affineFlatIndicator + (φ : PseudoBooleanFunction n) (c : ℝ) + (H : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (a u : FABL.F₂Cube n) + (hφ : φ = fun x ↦ c * FABL.vectorWalshCharacter u x * + FABL.setIndicator + (FABL.binaryAffineSubspace H a : Set (FABL.F₂Cube n)) x) : + (rawFourierSupport φ).card ≤ + Nat.card (FABL.perpendicularSubspace H) := by + classical + letI : Fintype (FABL.perpendicularSubspace H) := Fintype.ofFinite _ + have support_shift_mem (v : rawFourierSupport φ) : + u + v.1 ∈ FABL.perpendicularSubspace H := by + have hv : FABL.vectorFourierCoeff φ v.1 ≠ 0 := + (mem_rawFourierSupport_iff_vectorFourierCoeff_ne_zero φ v.1).mp v.2 + have hcoefficient : + FABL.vectorFourierCoeff φ v.1 = + c * FABL.vectorFourierCoeff + (FABL.setIndicator + (FABL.binaryAffineSubspace H a : Set (FABL.F₂Cube n))) + (u + v.1) := by + calc + FABL.vectorFourierCoeff φ v.1 = + FABL.vectorFourierCoeff + (fun x ↦ c * FABL.vectorWalshCharacter u x * + FABL.setIndicator + (FABL.binaryAffineSubspace H a : Set (FABL.F₂Cube n)) x) + v.1 := congrArg (fun ψ : PseudoBooleanFunction n ↦ + FABL.vectorFourierCoeff ψ v.1) hφ + _ = FABL.vectorFourierCoeff + (fun x ↦ c * + (FABL.vectorWalshCharacter u x * + FABL.setIndicator + (FABL.binaryAffineSubspace H a : Set (FABL.F₂Cube n)) x)) v.1 := by + congr 1 + funext x + ring + _ = _ := by + rw [FABL.vectorFourierCoeff_const_mul, + vectorFourierCoeff_mul_vectorWalshCharacter] + rw [hcoefficient] at hv + have hindicator : + FABL.vectorFourierCoeff + (FABL.setIndicator + (FABL.binaryAffineSubspace H a : Set (FABL.F₂Cube n))) + (u + v.1) ≠ 0 := + (mul_ne_zero_iff.mp hv).2 + exact (FABL.vectorFourierCoeff_setIndicator_binaryAffineSubspace_ne_zero_iff + H a (u + v.1)).mp hindicator + let toPerpendicular : rawFourierSupport φ → FABL.perpendicularSubspace H := + fun v ↦ ⟨u + v.1, support_shift_mem v⟩ + have hinjective : Function.Injective toPerpendicular := by + intro v w hvw + apply Subtype.ext + have hvalue := congrArg Subtype.val hvw + exact add_left_cancel hvalue + have hcard : + Fintype.card (rawFourierSupport φ) ≤ + Fintype.card (FABL.perpendicularSubspace H) := + Fintype.card_le_of_injective toPerpendicular hinjective + simpa only [Fintype.card_coe, Nat.card_eq_fintype_card] using hcard + +private theorem card_submodule_mul_card_perpendicular + (H : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) : + Nat.card H * Nat.card (FABL.perpendicularSubspace H) = 2 ^ n := by + have hrank : Module.finrank FABL.𝔽₂ H ≤ n := by + simpa using H.finrank_le + rw [FABL.card_submodule_eq_two_pow_finrank, + FABL.card_submodule_eq_two_pow_finrank, + FABL.finrank_perpendicularSubspace, ← pow_add, + Nat.add_sub_of_le hrank] + +/-- Every nonzero modulated affine-flat indicator attains equality in the +Fourier uncertainty bound. -/ +theorem IsModulatedAffineFlatIndicator.card_support_mul_card_rawFourierSupport_eq + {φ : PseudoBooleanFunction n} (hφ : IsModulatedAffineFlatIndicator φ) : + (pseudoBooleanSupport φ).card * (rawFourierSupport φ).card = 2 ^ n := by + rcases hφ with ⟨c, hc, H, a, u, hrepresentation⟩ + have hφne : φ ≠ 0 := by + apply Function.ne_iff.mpr + refine ⟨a, ?_⟩ + have ha : a ∈ FABL.binaryAffineSubspace H a := by + rw [FABL.mem_binaryAffineSubspace_iff_add_mem, + ZModModule.add_self] + exact H.zero_mem + rw [hrepresentation] + simp only [FABL.setIndicator, Set.indicator_of_mem ha, mul_one] + apply mul_ne_zero hc + rcases FABL.vectorWalshCharacter_eq_neg_one_or_one u a with h | h <;> + simp [h] + have hlower := + two_pow_le_card_pseudoBooleanSupport_mul_card_rawFourierSupport φ hφne + have hvalueSupport := + card_pseudoBooleanSupport_le_card_submodule_of_affineFlatIndicator + φ c H a u hrepresentation + have hfrequencySupport := + card_rawFourierSupport_le_card_perpendicular_of_affineFlatIndicator + φ c H a u hrepresentation + have hupper : + (pseudoBooleanSupport φ).card * (rawFourierSupport φ).card ≤ 2 ^ n := by + rw [← card_submodule_mul_card_perpendicular H] + exact Nat.mul_le_mul hvalueSupport hfrequencySupport + omega + +/-- Equality in the Fourier uncertainty bound forces the value support to be +an affine flat and the function to be a nonzero scalar multiple of one Walsh +character on that flat. -/ +theorem isModulatedAffineFlatIndicator_of_card_support_mul_card_rawFourierSupport_eq + (φ : PseudoBooleanFunction n) (hφ : φ ≠ 0) + (hproduct : + (pseudoBooleanSupport φ).card * (rawFourierSupport φ).card = 2 ^ n) : + IsModulatedAffineFlatIndicator φ := by + classical + have hproductPos : + 0 < (pseudoBooleanSupport φ).card * (rawFourierSupport φ).card := by + rw [hproduct] + positivity + have hvalueSupportPos : 0 < (pseudoBooleanSupport φ).card := by + apply Nat.pos_of_ne_zero + intro hzero + rw [hzero, zero_mul] at hproductPos + exact (Nat.lt_irrefl 0 hproductPos).elim + have hfrequencySupportPos : 0 < (rawFourierSupport φ).card := by + apply Nat.pos_of_ne_zero + intro hzero + rw [hzero, mul_zero] at hproductPos + exact (Nat.lt_irrefl 0 hproductPos).elim + obtain ⟨a, ha⟩ := Finset.card_pos.mp hvalueSupportPos + obtain ⟨u, hu⟩ := Finset.card_pos.mp hfrequencySupportPos + let c : ℝ := φ a * FABL.vectorWalshCharacter u a + have hc : c ≠ 0 := by + dsimp [c] + apply mul_ne_zero ((mem_pseudoBooleanSupport φ a).mp ha) + rcases FABL.vectorWalshCharacter_eq_neg_one_or_one u a with h | h <;> + simp [h] + have hcharacterSq (v x : FABL.F₂Cube n) : + FABL.vectorWalshCharacter v x ^ 2 = 1 := by + rw [← sq_abs, FABL.abs_vectorWalshCharacter, one_pow] + have hrepresentationOnSupport + (x : FABL.F₂Cube n) (hx : x ∈ pseudoBooleanSupport φ) : + φ x = c * FABL.vectorWalshCharacter u x := by + have heq := support_modulated_value_eq_of_uncertainty_eq + φ hφ hproduct u x a hu hx ha + have hcharacterMul : + FABL.vectorWalshCharacter u x * FABL.vectorWalshCharacter u x = 1 := by + simpa [pow_two] using hcharacterSq u x + calc + φ x = φ x * 1 := by ring + _ = φ x * (FABL.vectorWalshCharacter u x * + FABL.vectorWalshCharacter u x) := by rw [hcharacterMul] + _ = (φ x * FABL.vectorWalshCharacter u x) * + FABL.vectorWalshCharacter u x := by ring + _ = (φ a * FABL.vectorWalshCharacter u a) * + FABL.vectorWalshCharacter u x := by rw [heq] + _ = c * FABL.vectorWalshCharacter u x := rfl + let H : Submodule FABL.𝔽₂ (FABL.F₂Cube n) := + ⨅ v : rawFourierSupport φ, + LinearMap.ker + ((dotProductEquiv FABL.𝔽₂ (Fin n)) (u + v.1)) + have hsupportDifferenceMem + (x : FABL.F₂Cube n) (hx : x ∈ pseudoBooleanSupport φ) : + x + a ∈ H := by + rw [show H = ⨅ v : rawFourierSupport φ, + LinearMap.ker + ((dotProductEquiv FABL.𝔽₂ (Fin n)) (u + v.1)) by rfl] + simp only [Submodule.mem_iInf, LinearMap.mem_ker] + intro v + have hvEq := support_modulated_value_eq_of_uncertainty_eq + φ hφ hproduct v.1 x a v.2 hx ha + rw [hrepresentationOnSupport x hx, + hrepresentationOnSupport a ha] at hvEq + have hmulX := congrArg + (fun χ : AddChar (FABL.F₂Cube n) ℝ ↦ χ x) + (FABL.vectorWalshCharacter_mul u v.1) + have hmulA := congrArg + (fun χ : AddChar (FABL.F₂Cube n) ℝ ↦ χ a) + (FABL.vectorWalshCharacter_mul u v.1) + change FABL.vectorWalshCharacter u x * + FABL.vectorWalshCharacter v.1 x = + FABL.vectorWalshCharacter (u + v.1) x at hmulX + change FABL.vectorWalshCharacter u a * + FABL.vectorWalshCharacter v.1 a = + FABL.vectorWalshCharacter (u + v.1) a at hmulA + have hfrequency : + FABL.vectorWalshCharacter (u + v.1) x = + FABL.vectorWalshCharacter (u + v.1) a := by + apply mul_left_cancel₀ hc + calc + c * FABL.vectorWalshCharacter (u + v.1) x = + (c * FABL.vectorWalshCharacter u x) * + FABL.vectorWalshCharacter v.1 x := by rw [← hmulX]; ring + _ = (c * FABL.vectorWalshCharacter u a) * + FABL.vectorWalshCharacter v.1 a := hvEq + _ = c * FABL.vectorWalshCharacter (u + v.1) a := by rw [← hmulA]; ring + have hcharacterOne : + FABL.vectorWalshCharacter (u + v.1) (x + a) = 1 := by + rw [AddChar.map_add_eq_mul, hfrequency] + simpa [pow_two] using hcharacterSq (u + v.1) a + have hdotZero : FABL.f₂DotProduct (u + v.1) (x + a) = 0 := + (FABL.binarySign_eq_one_iff _).mp (by + rw [← FABL.vectorWalshCharacter_apply] + exact hcharacterOne) + rw [dotProductEquiv_apply_apply] + simpa only [FABL.f₂DotProduct] using hdotZero + let toDirection : pseudoBooleanSupport φ → H := fun x ↦ + ⟨x.1 + a, hsupportDifferenceMem x.1 x.2⟩ + have toDirection_injective : Function.Injective toDirection := by + intro x y hxy + apply Subtype.ext + exact add_right_cancel (congrArg Subtype.val hxy) + have hvalueSupport_le : + (pseudoBooleanSupport φ).card ≤ Nat.card H := by + letI : Fintype H := Fintype.ofFinite H + have hcard : + Fintype.card (pseudoBooleanSupport φ) ≤ Fintype.card H := + Fintype.card_le_of_injective toDirection toDirection_injective + simpa only [Fintype.card_coe, Nat.card_eq_fintype_card] using hcard + have hfrequencyShiftMem (v : rawFourierSupport φ) : + u + v.1 ∈ FABL.perpendicularSubspace H := by + rw [FABL.mem_perpendicularSubspace_iff] + intro d hd + rw [show H = ⨅ w : rawFourierSupport φ, + LinearMap.ker + ((dotProductEquiv FABL.𝔽₂ (Fin n)) (u + w.1)) by rfl] at hd + have hd' : ∀ w : rawFourierSupport φ, + ((dotProductEquiv FABL.𝔽₂ (Fin n)) (u + w.1)) d = 0 := by + simpa only [Submodule.mem_iInf, LinearMap.mem_ker] using hd + simpa [FABL.f₂DotProduct, dotProductEquiv_apply_apply] using hd' v + let toPerpendicular : rawFourierSupport φ → FABL.perpendicularSubspace H := + fun v ↦ ⟨u + v.1, hfrequencyShiftMem v⟩ + have toPerpendicular_injective : Function.Injective toPerpendicular := by + intro v w hvw + apply Subtype.ext + exact add_left_cancel (congrArg Subtype.val hvw) + have hfrequencySupport_le : + (rawFourierSupport φ).card ≤ + Nat.card (FABL.perpendicularSubspace H) := by + letI : Fintype (FABL.perpendicularSubspace H) := Fintype.ofFinite _ + have hcard : + Fintype.card (rawFourierSupport φ) ≤ + Fintype.card (FABL.perpendicularSubspace H) := + Fintype.card_le_of_injective toPerpendicular toPerpendicular_injective + simpa only [Fintype.card_coe, Nat.card_eq_fintype_card] using hcard + have hvalueSupportCard : (pseudoBooleanSupport φ).card = Nat.card H := by + apply Nat.le_antisymm hvalueSupport_le + by_contra hnot + have hstrict : (pseudoBooleanSupport φ).card < Nat.card H := + Nat.lt_of_not_ge hnot + have hperpendicularPos : 0 < Nat.card (FABL.perpendicularSubspace H) := + Nat.card_pos + have hproductLe : + (pseudoBooleanSupport φ).card * (rawFourierSupport φ).card ≤ + (pseudoBooleanSupport φ).card * + Nat.card (FABL.perpendicularSubspace H) := + Nat.mul_le_mul_left _ hfrequencySupport_le + have hproductLt : + (pseudoBooleanSupport φ).card * + Nat.card (FABL.perpendicularSubspace H) < + Nat.card H * Nat.card (FABL.perpendicularSubspace H) := + Nat.mul_lt_mul_of_pos_right hstrict hperpendicularPos + have := hproductLe.trans_lt hproductLt + rw [hproduct, card_submodule_mul_card_perpendicular H] at this + exact (Nat.lt_irrefl _ this).elim + letI : Fintype H := Fintype.ofFinite H + have htoDirectionCard : + Fintype.card (pseudoBooleanSupport φ) = Fintype.card H := by + simpa only [Fintype.card_coe, Nat.card_eq_fintype_card] using + hvalueSupportCard + have toDirection_surjective : Function.Surjective toDirection := + ((Fintype.bijective_iff_injective_and_card toDirection).mpr + ⟨toDirection_injective, htoDirectionCard⟩).2 + have hflat_iff_support (x : FABL.F₂Cube n) : + x ∈ FABL.binaryAffineSubspace H a ↔ x ∈ pseudoBooleanSupport φ := by + constructor + · intro hx + have hxa : x + a ∈ H := + (FABL.mem_binaryAffineSubspace_iff_add_mem H a x).mp hx + obtain ⟨y, hy⟩ := toDirection_surjective ⟨x + a, hxa⟩ + have hyValue := congrArg Subtype.val hy + have hyx : y.1 = x := add_right_cancel hyValue + simpa [hyx] using y.2 + · intro hx + exact (FABL.mem_binaryAffineSubspace_iff_add_mem H a x).mpr + (hsupportDifferenceMem x hx) + refine ⟨c, hc, H, a, u, ?_⟩ + funext x + by_cases hx : x ∈ pseudoBooleanSupport φ + · have hxflat := (hflat_iff_support x).mpr hx + rw [hrepresentationOnSupport x hx] + simp [FABL.setIndicator, hxflat] + · have hxzero : φ x = 0 := by + exact not_ne_iff.mp (by simpa only [mem_pseudoBooleanSupport] using hx) + have hxflat : x ∉ FABL.binaryAffineSubspace H a := by + exact fun h ↦ hx ((hflat_iff_support x).mp h) + rw [hxzero] + simp [FABL.setIndicator, hxflat] + +/-- Carlet Proposition 27's equality classification. The coefficient is +explicitly nonzero, as forced by the theorem's nonzero-function hypothesis. -/ +theorem card_support_mul_card_rawFourierSupport_eq_two_pow_iff + (φ : PseudoBooleanFunction n) (hφ : φ ≠ 0) : + (pseudoBooleanSupport φ).card * (rawFourierSupport φ).card = 2 ^ n ↔ + IsModulatedAffineFlatIndicator φ := by + constructor + · exact isModulatedAffineFlatIndicator_of_card_support_mul_card_rawFourierSupport_eq + φ hφ + · exact IsModulatedAffineFlatIndicator.card_support_mul_card_rawFourierSupport_eq + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/GeometricCharacterization.lean b/CryptBoolean/Carlet/Chapter06/GeometricCharacterization.lean new file mode 100644 index 0000000..ce2fc7a --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/GeometricCharacterization.lean @@ -0,0 +1,1327 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter04.HigherOrderLowWeightFlats +public import CryptBoolean.Carlet.Chapter05.CoveringSequences +public import CryptBoolean.Carlet.Chapter06.Dual +public import CryptBoolean.Carlet.Chapter06.NNFCharacterization +import Mathlib.LinearAlgebra.Dual.Lemmas + +/-! +# Geometric characterization of bent functions + +Carlet Theorem 12 and Lemma 3: representations modulo `2^(n/2)` by +indicators of half-dimensional linear subspaces, and the perpendicular-space +formula for the dual of an exact generalized partial-spread representation. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +local instance geometricDualFinite + (V : Type*) [Finite V] [AddCommGroup V] [Module FABL.𝔽₂ V] : + Finite (Module.Dual FABL.𝔽₂ V) := + Finite.of_injective + (fun ell : Module.Dual FABL.𝔽₂ V ↦ (ell : V → FABL.𝔽₂)) + LinearMap.coe_injective + +noncomputable local instance geometricDualFintype + (V : Type*) [Finite V] [AddCommGroup V] [Module FABL.𝔽₂ V] : + Fintype (Module.Dual FABL.𝔽₂ V) := + Fintype.ofFinite _ + +/-- The integer indicator of a binary linear subspace. -/ +noncomputable def linearSubspaceIndicatorInt + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (x : FABL.F₂Cube n) : ℤ := by + classical + exact if x ∈ E then 1 else 0 + +/-- An integer combination of all half-dimensional subspace indicators. -/ +noncomputable def halfSubspaceCombination + (c : Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ) + (x : FABL.F₂Cube n) : ℤ := + ∑ E ∈ binaryLinearSubspaces (n / 2) n, + c E * linearSubspaceIndicatorInt E x + +/-- The integer indicator of the origin. -/ +def originIndicatorInt (x : FABL.F₂Cube n) : ℤ := + if x = 0 then 1 else 0 + +/-- The right-hand side of Carlet Relation (51). -/ +noncomputable def geometricBentExpression + (c : Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ) + (x : FABL.F₂Cube n) : ℤ := + halfSubspaceCombination c x - + (2 : ℤ) ^ (n / 2 - 1) * originIndicatorInt x + +/-- The expression obtained by replacing every half-dimensional subspace by +its perpendicular subspace. -/ +noncomputable def perpendicularGeometricBentExpression + (c : Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ) + (x : FABL.F₂Cube n) : ℤ := + (∑ E ∈ binaryLinearSubspaces (n / 2) n, + c E * linearSubspaceIndicatorInt (FABL.perpendicularSubspace E) x) - + (2 : ℤ) ^ (n / 2 - 1) * originIndicatorInt x + +/-- Carlet Relation (16) in the integral normalization: the integer Fourier +transform of a subspace indicator is its cardinality on the perpendicular +subspace. -/ +theorem integerWalshTransform_linearSubspaceIndicatorInt + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (u : FABL.F₂Cube n) : + integerWalshTransform (linearSubspaceIndicatorInt E) u = + (2 : ℤ) ^ Module.finrank FABL.𝔽₂ E * + linearSubspaceIndicatorInt (FABL.perpendicularSubspace E) u := by + classical + apply Int.cast_injective (α := ℝ) + have hleft : + (integerWalshTransform (linearSubspaceIndicatorInt E) u : ℝ) = + rawFourierTransform + (FABL.setIndicator (E : Set (FABL.F₂Cube n))) u := by + rw [integerWalshTransform, rawFourierTransform] + push_cast + apply Finset.sum_congr rfl + intro x _hx + rw [FABL.vectorWalshCharacter_apply, ← bitSignInt_cast] + rw [show FABL.f₂DotProduct x u = FABL.f₂DotProduct u x by + exact dotProduct_comm x u] + by_cases hxE : x ∈ E <;> + simp [linearSubspaceIndicatorInt, FABL.setIndicator, hxE] + rw [hleft, rawFourierTransform_setIndicator_submodule, + FABL.card_submodule_eq_two_pow_finrank] + by_cases hu : u ∈ FABL.perpendicularSubspace E <;> + simp [linearSubspaceIndicatorInt, hu] + +/-- The integer Fourier transform of the origin indicator is identically one. -/ +@[simp] theorem integerWalshTransform_originIndicatorInt + (u : FABL.F₂Cube n) : + integerWalshTransform originIndicatorInt u = 1 := by + classical + rw [integerWalshTransform] + rw [Fintype.sum_eq_single 0] + · simp [originIndicatorInt, FABL.f₂DotProduct, bitSignInt] + · intro x hx + simp [originIndicatorInt, hx] + +/-- The integral Fourier transform of the zero-one embedding agrees with the +integral coefficient supplied by the numerical normal form. -/ +theorem integerWalshTransform_bitValueInt_eq_booleanNNFFourierCoeffInt + (f : BooleanFunction n) (u : FABL.F₂Cube n) : + integerWalshTransform (fun x ↦ bitValueInt (f x)) u = + booleanNNFFourierCoeffInt f u := by + apply Int.cast_injective (α := ℝ) + rw [booleanNNFFourierCoeffInt_cast] + rw [integerWalshTransform, rawFourierTransform] + push_cast + apply Finset.sum_congr rfl + intro x _hx + rw [FABL.vectorWalshCharacter_apply, ← bitSignInt_cast] + rw [show FABL.f₂DotProduct x u = FABL.f₂DotProduct u x by + exact dotProduct_comm x u] + by_cases hfx : f x = 1 <;> + simp [bitValueInt, FABL.booleanRealEmbedding, hfx] + +/-- Fourier transformation sends a half-dimensional indicator combination to +the same coefficient combination on perpendicular subspaces, scaled by +`2^(n/2)`. -/ +theorem integerWalshTransform_halfSubspaceCombination + (c : Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ) + (u : FABL.F₂Cube n) : + integerWalshTransform (halfSubspaceCombination c) u = + (2 : ℤ) ^ (n / 2) * + ∑ E ∈ binaryLinearSubspaces (n / 2) n, + c E * linearSubspaceIndicatorInt + (FABL.perpendicularSubspace E) u := by + classical + unfold integerWalshTransform halfSubspaceCombination + calc + (∑ x, (∑ E ∈ binaryLinearSubspaces (n / 2) n, + c E * linearSubspaceIndicatorInt E x) * + bitSignInt (FABL.f₂DotProduct x u)) = + ∑ E ∈ binaryLinearSubspaces (n / 2) n, + c E * ∑ x, linearSubspaceIndicatorInt E x * + bitSignInt (FABL.f₂DotProduct x u) := by + simp_rw [Finset.sum_mul] + rw [Finset.sum_comm] + apply Finset.sum_congr rfl + intro E _hE + rw [Finset.mul_sum] + apply Finset.sum_congr rfl + intro x _hx + ring + _ = ∑ E ∈ binaryLinearSubspaces (n / 2) n, + c E * ((2 : ℤ) ^ (n / 2) * + linearSubspaceIndicatorInt (FABL.perpendicularSubspace E) u) := by + apply Finset.sum_congr rfl + intro E hE + change c E * integerWalshTransform + (linearSubspaceIndicatorInt E) u = _ + rw [integerWalshTransform_linearSubspaceIndicatorInt, + (mem_binaryLinearSubspaces E).mp hE] + _ = (2 : ℤ) ^ (n / 2) * + ∑ E ∈ binaryLinearSubspaces (n / 2) n, + c E * linearSubspaceIndicatorInt + (FABL.perpendicularSubspace E) u := by + rw [Finset.mul_sum] + apply Finset.sum_congr rfl + intro E _hE + ring + +/-- The integral transform of Relation (51). -/ +theorem integerWalshTransform_geometricBentExpression + (c : Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ) + (u : FABL.F₂Cube n) : + integerWalshTransform (geometricBentExpression c) u = + (2 : ℤ) ^ (n / 2) * + ∑ E ∈ binaryLinearSubspaces (n / 2) n, + c E * linearSubspaceIndicatorInt + (FABL.perpendicularSubspace E) u - + (2 : ℤ) ^ (n / 2 - 1) := by + classical + unfold geometricBentExpression + rw [integerWalshTransform] + simp_rw [sub_mul] + rw [Finset.sum_sub_distrib, ← integerWalshTransform, + integerWalshTransform_halfSubspaceCombination] + have horigin : + (∑ x, ((2 : ℤ) ^ (n / 2 - 1) * originIndicatorInt x) * + bitSignInt (FABL.f₂DotProduct x u)) = + (2 : ℤ) ^ (n / 2 - 1) := by + calc + (∑ x, ((2 : ℤ) ^ (n / 2 - 1) * originIndicatorInt x) * + bitSignInt (FABL.f₂DotProduct x u)) = + (2 : ℤ) ^ (n / 2 - 1) * + ∑ x, originIndicatorInt x * + bitSignInt (FABL.f₂DotProduct x u) := by + rw [Finset.mul_sum] + apply Finset.sum_congr rfl + intro x _hx + ring + _ = (2 : ℤ) ^ (n / 2 - 1) * + integerWalshTransform originIndicatorInt u := rfl + _ = (2 : ℤ) ^ (n / 2 - 1) := by + rw [integerWalshTransform_originIndicatorInt, mul_one] + rw [horigin] + +/-- A Boolean function satisfies Carlet Relation (51) when its integer +zero-one embedding is pointwise congruent to a geometric expression modulo +`2^(n/2)`. -/ +def HasGeometricBentCongruence (f : BooleanFunction n) : Prop := + ∃ c : Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ, + ∀ x : FABL.F₂Cube n, + Int.ModEq ((2 : ℤ) ^ (n / 2)) + (bitValueInt (f x)) (geometricBentExpression c x) + +/-- The sufficient direction of Carlet Theorem 12: every function satisfying +the geometric congruence is bent. -/ +theorem isBent_of_hasGeometricBentCongruence + (f : BooleanFunction n) (hn : Even n) (hnTwo : 2 ≤ n) + (hf : HasGeometricBentCongruence f) : IsBent f := by + obtain ⟨c, hc⟩ := hf + apply (isBent_iff_forall_booleanNNFFourierCoeffInt_modeq f hn hnTwo).2 + intro u + have htransform : + Int.ModEq ((2 : ℤ) ^ (n / 2)) + (integerWalshTransform (fun x ↦ bitValueInt (f x)) u) + (integerWalshTransform (geometricBentExpression c) u) := by + rw [Int.modEq_iff_dvd] + unfold integerWalshTransform + rw [← Finset.sum_sub_distrib] + apply Finset.dvd_sum + intro x _hx + have hx := (hc x).dvd.mul_right + (bitSignInt (FABL.f₂DotProduct x u)) + convert hx using 1 + ring + have hhalfPos : 1 ≤ n / 2 := by + rcases hn with ⟨k, hk⟩ + omega + have hdouble : (2 : ℤ) ^ (n / 2) = + 2 * (2 : ℤ) ^ (n / 2 - 1) := by + conv_lhs => rw [show n / 2 = (n / 2 - 1) + 1 by omega] + rw [pow_succ] + ring + have hexpression : + Int.ModEq ((2 : ℤ) ^ (n / 2)) + (integerWalshTransform (geometricBentExpression c) u) + ((2 : ℤ) ^ (n / 2 - 1)) := by + rw [integerWalshTransform_geometricBentExpression, + Int.modEq_iff_dvd] + refine ⟨1 - ∑ E ∈ binaryLinearSubspaces (n / 2) n, + c E * linearSubspaceIndicatorInt + (FABL.perpendicularSubspace E) u, ?_⟩ + rw [hdouble] + ring + have hcoefficient := htransform.trans hexpression + rwa [integerWalshTransform_bitValueInt_eq_booleanNNFFourierCoeffInt] + at hcoefficient + +/-- An exact generalized partial-spread representation is Relation (51) +without reduction modulo `2^(n/2)`. -/ +def HasExactGPSRepresentation + (f : BooleanFunction n) + (c : Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ) : Prop := + ∀ x : FABL.F₂Cube n, + bitValueInt (f x) = geometricBentExpression c x + +/-- Carlet Theorem 12, exact case: a generalized partial-spread +representation is bent, and its dual is obtained by replacing every subspace +with its perpendicular subspace. -/ +theorem isBent_and_bitValueInt_bentDual_of_exactGPSRepresentation + (f : BooleanFunction n) + (c : Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ) + (hn : Even n) (hnTwo : 2 ≤ n) + (hf : HasExactGPSRepresentation f c) : + IsBent f ∧ + ∀ u : FABL.F₂Cube n, + bitValueInt (bentDual f u) = + perpendicularGeometricBentExpression c u := by + have hcongruence : HasGeometricBentCongruence f := by + refine ⟨c, fun x ↦ ?_⟩ + rw [hf x] + have hbent := isBent_of_hasGeometricBentCongruence f hn hnTwo hcongruence + refine ⟨hbent, ?_⟩ + intro u + let S : ℤ := + ∑ E ∈ binaryLinearSubspaces (n / 2) n, + c E * linearSubspaceIndicatorInt + (FABL.perpendicularSubspace E) u + have hsplit : n = n / 2 + n / 2 := by + rcases hn with ⟨k, hk⟩ + omega + have hhalfPos : 1 ≤ n / 2 := by omega + have hdouble : (2 : ℤ) ^ (n / 2) = + 2 * (2 : ℤ) ^ (n / 2 - 1) := by + conv_lhs => rw [show n / 2 = (n / 2 - 1) + 1 by omega] + rw [pow_succ] + ring + have hpower : (2 : ℤ) ^ n = + (2 : ℤ) ^ (n / 2) * (2 : ℤ) ^ (n / 2) := by + calc + (2 : ℤ) ^ n = (2 : ℤ) ^ (n / 2 + n / 2) := + congrArg (fun k : ℕ ↦ (2 : ℤ) ^ k) hsplit + _ = (2 : ℤ) ^ (n / 2) * (2 : ℤ) ^ (n / 2) := by + rw [pow_add] + have htransform : + integerWalshTransform (fun x ↦ bitValueInt (f x)) u = + integerWalshTransform (geometricBentExpression c) u := by + unfold integerWalshTransform + apply Finset.sum_congr rfl + intro x _hx + exact congrArg + (fun z : ℤ ↦ z * bitSignInt (FABL.f₂DotProduct x u)) (hf x) + have hcoefficient : booleanNNFFourierCoeffInt f u = + (2 : ℤ) ^ (n / 2) * S - + (2 : ℤ) ^ (n / 2 - 1) := by + rw [← integerWalshTransform_bitValueInt_eq_booleanNNFFourierCoeffInt, + htransform, integerWalshTransform_geometricBentExpression] + have hwalsh := + walshTransform_eq_indicator_sub_two_mul_booleanNNFFourierCoeffInt f u + rw [hcoefficient] at hwalsh + have hwalshExpression : + walshTransform f u = + (2 : ℤ) ^ (n / 2) * + (1 - 2 * perpendicularGeometricBentExpression c u) := by + rw [hwalsh] + unfold perpendicularGeometricBentExpression originIndicatorInt + change _ = (2 : ℤ) ^ (n / 2) * + (1 - 2 * (S - (2 : ℤ) ^ (n / 2 - 1) * + (if u = 0 then 1 else 0))) + by_cases hu : u = 0 + · simp only [if_pos hu] + rw [hpower, hdouble] + ring + · simp only [if_neg hu] + rw [hdouble] + ring + have hdualWalsh := + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hbent u + rw [hwalshExpression] at hdualWalsh + have hsign : bitSignInt (bentDual f u) = + 1 - 2 * perpendicularGeometricBentExpression c u := by + exact mul_left_cancel₀ (by positivity : (2 : ℤ) ^ (n / 2) ≠ 0) + hdualWalsh.symm + rw [bitSignInt_eq_one_sub_two_mul_bitValueInt] at hsign + omega + +/-- The ambient image of the kernel of a linear functional on a subspace. -/ +noncomputable def ambientFunctionalKernel + (F : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (ell : Module.Dual FABL.𝔽₂ F) : + Submodule FABL.𝔽₂ (FABL.F₂Cube n) := + (LinearMap.ker ell).map F.subtype + +theorem mem_ambientFunctionalKernel_iff + (F : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (ell : Module.Dual FABL.𝔽₂ F) + (x : FABL.F₂Cube n) (hx : x ∈ F) : + x ∈ ambientFunctionalKernel F ell ↔ ell ⟨x, hx⟩ = 0 := by + constructor + · intro h + rcases h with ⟨y, hy, hxy⟩ + have hyx : y = ⟨x, hx⟩ := by + apply Subtype.ext + exact hxy + rw [← hyx] + exact hy + · intro h + exact ⟨⟨x, hx⟩, h, rfl⟩ + +theorem finrank_ambientFunctionalKernel + (F : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (ell : Module.Dual FABL.𝔽₂ F) (hell : ell ≠ 0) : + Module.finrank FABL.𝔽₂ (ambientFunctionalKernel F ell) + 1 = + Module.finrank FABL.𝔽₂ F := by + rw [ambientFunctionalKernel, Submodule.finrank_map_subtype_eq] + exact Module.Dual.finrank_ker_add_one_of_ne_zero hell + +/-- The finite set of nonzero linear functionals on a subspace. -/ +noncomputable def nonzeroDualFinset + (V : Type*) [Finite V] [AddCommGroup V] [Module FABL.𝔽₂ V] : + Finset (Module.Dual FABL.𝔽₂ V) := by + classical + exact Finset.univ.filter fun ell ↦ ell ≠ 0 + +@[simp] theorem mem_nonzeroDualFinset + (V : Type*) [Finite V] [AddCommGroup V] [Module FABL.𝔽₂ V] + (ell : Module.Dual FABL.𝔽₂ V) : + ell ∈ nonzeroDualFinset V ↔ ell ≠ 0 := by + classical + simp [nonzeroDualFinset] + +theorem card_nonzeroDualFinset + (V : Type*) [Finite V] [AddCommGroup V] [Module FABL.𝔽₂ V] : + (nonzeroDualFinset V).card = + 2 ^ Module.finrank FABL.𝔽₂ V - 1 := by + classical + letI : Fintype V := Fintype.ofFinite V + have hfinset : nonzeroDualFinset V = + (Finset.univ : Finset (Module.Dual FABL.𝔽₂ V)).erase 0 := by + ext ell + simp [nonzeroDualFinset] + rw [hfinset, Finset.card_erase_of_mem (Finset.mem_univ 0)] + change Fintype.card (Module.Dual FABL.𝔽₂ V) - 1 = _ + rw [Module.card_eq_pow_finrank (K := FABL.𝔽₂) + (V := Module.Dual FABL.𝔽₂ V), + ZMod.card, Subspace.dual_finrank_eq] + +private theorem dualEvaluation_ne_zero + (V : Type*) [Finite V] [AddCommGroup V] [Module FABL.𝔽₂ V] + (y : V) (hy : y ≠ 0) : + Module.Dual.eval FABL.𝔽₂ V y ≠ 0 := by + intro hzero + apply hy + apply (Module.evalEquiv FABL.𝔽₂ V).injective + simpa using hzero + +private theorem card_nonzeroDual_vanishing + (V : Type*) [Finite V] [AddCommGroup V] [Module FABL.𝔽₂ V] + (y : V) (hy : y ≠ 0) : + ((nonzeroDualFinset V).filter fun ell ↦ ell y = 0).card = + 2 ^ (Module.finrank FABL.𝔽₂ V - 1) - 1 := by + classical + letI : Fintype V := Fintype.ofFinite V + let ev : Module.Dual FABL.𝔽₂ V →ₗ[FABL.𝔽₂] FABL.𝔽₂ := + Module.Dual.eval FABL.𝔽₂ V y + have hev : ev ≠ 0 := dualEvaluation_ne_zero V y hy + have hkerRank : Module.finrank FABL.𝔽₂ (LinearMap.ker ev) = + Module.finrank FABL.𝔽₂ V - 1 := by + have hrank := Module.Dual.finrank_ker_add_one_of_ne_zero hev + rw [Subspace.dual_finrank_eq] at hrank + omega + have hfilter : + (nonzeroDualFinset V).filter (fun ell ↦ ell y = 0) = + ((Finset.univ : Finset (Module.Dual FABL.𝔽₂ V)).filter + (fun ell ↦ ell y = 0)).erase 0 := by + ext ell + simp [nonzeroDualFinset] + have hzero : (0 : Module.Dual FABL.𝔽₂ V) ∈ + (Finset.univ.filter fun ell ↦ ell y = 0) := by simp + rw [hfilter, Finset.card_erase_of_mem hzero] + rw [← Fintype.card_subtype (fun ell : Module.Dual FABL.𝔽₂ V ↦ + ell y = 0)] + let e : { ell : Module.Dual FABL.𝔽₂ V // ell y = 0 } ≃ + LinearMap.ker ev := { + toFun := fun ell ↦ ⟨ell.1, ell.2⟩ + invFun := fun ell ↦ ⟨ell.1, by + change ev ell.1 = 0 + exact ell.2⟩ + left_inv := fun ell ↦ Subtype.ext rfl + right_inv := fun ell ↦ Subtype.ext rfl } + rw [Fintype.card_congr e, + Module.card_eq_pow_finrank (K := FABL.𝔽₂) (V := LinearMap.ker ev), + ZMod.card, hkerRank] + +/-- Above half dimension, the indicator of a subspace is congruent modulo +`2^(n/2)` to the negative sum of the indicators of the kernels of all its +nonzero linear functionals. -/ +theorem functionalKernelCombination_modeq + (F : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hF : n / 2 < Module.finrank FABL.𝔽₂ F) : + ∀ x : FABL.F₂Cube n, + Int.ModEq ((2 : ℤ) ^ (n / 2)) + (linearSubspaceIndicatorInt F x) + (-∑ ell ∈ nonzeroDualFinset F, + linearSubspaceIndicatorInt (ambientFunctionalKernel F ell) x) := by + classical + intro x + by_cases hxF : x ∈ F + · by_cases hx0 : x = 0 + · subst x + have hsum : + (∑ ell ∈ nonzeroDualFinset F, + linearSubspaceIndicatorInt (ambientFunctionalKernel F ell) 0) = + ((nonzeroDualFinset F).card : ℤ) := by + simp [linearSubspaceIndicatorInt] + have hcard : ((nonzeroDualFinset F).card : ℤ) = + (2 : ℤ) ^ Module.finrank FABL.𝔽₂ F - 1 := by + have hle : 1 ≤ (2 : ℕ) ^ Module.finrank FABL.𝔽₂ F := + Nat.one_le_pow _ _ (by omega) + rw [card_nonzeroDualFinset] + norm_num [Nat.cast_sub hle] + rw [linearSubspaceIndicatorInt, if_pos (Submodule.zero_mem F), hsum, + hcard, Int.modEq_iff_dvd] + have heq : -((2 : ℤ) ^ Module.finrank FABL.𝔽₂ F - 1) - 1 = + -((2 : ℤ) ^ Module.finrank FABL.𝔽₂ F) := by ring + rw [heq] + exact (pow_dvd_pow (2 : ℤ) (Nat.le_of_lt hF)).neg_right + · let y : F := ⟨x, hxF⟩ + have hy : y ≠ 0 := by + intro hyzero + apply hx0 + exact congrArg Subtype.val hyzero + have hsum : + (∑ ell ∈ nonzeroDualFinset F, + linearSubspaceIndicatorInt (ambientFunctionalKernel F ell) x) = + (((nonzeroDualFinset F).filter fun ell ↦ ell y = 0).card : ℤ) := by + calc + (∑ ell ∈ nonzeroDualFinset F, + linearSubspaceIndicatorInt (ambientFunctionalKernel F ell) x) = + ∑ ell ∈ nonzeroDualFinset F, + if ell y = 0 then (1 : ℤ) else 0 := by + apply Finset.sum_congr rfl + intro ell _hell + rw [linearSubspaceIndicatorInt, + mem_ambientFunctionalKernel_iff F ell x hxF] + simp [y] + _ = (((nonzeroDualFinset F).filter fun ell ↦ ell y = 0).card : ℤ) := by + rw [Finset.sum_boole] + have hcard : + (((nonzeroDualFinset F).filter fun ell ↦ ell y = 0).card : ℤ) = + (2 : ℤ) ^ (Module.finrank FABL.𝔽₂ F - 1) - 1 := by + have hle : 1 ≤ (2 : ℕ) ^ (Module.finrank FABL.𝔽₂ F - 1) := + Nat.one_le_pow _ _ (by omega) + rw [card_nonzeroDual_vanishing F y hy] + norm_num [Nat.cast_sub hle] + rw [linearSubspaceIndicatorInt, if_pos hxF, hsum, hcard, + Int.modEq_iff_dvd] + have hrank : n / 2 ≤ Module.finrank FABL.𝔽₂ F - 1 := by omega + have heq : -((2 : ℤ) ^ (Module.finrank FABL.𝔽₂ F - 1) - 1) - 1 = + -((2 : ℤ) ^ (Module.finrank FABL.𝔽₂ F - 1)) := by ring + rw [heq] + exact (pow_dvd_pow (2 : ℤ) hrank).neg_right + · have hkernel : ∀ ell : Module.Dual FABL.𝔽₂ F, + x ∉ ambientFunctionalKernel F ell := by + intro ell hx + exact hxF (F.map_subtype_le (LinearMap.ker ell) hx) + simp [linearSubspaceIndicatorInt, hxF, hkernel] + +/-- An integer-valued function is representable modulo `2^(n/2)` by an +integer combination of half-dimensional subspace indicators. -/ +def HasHalfSubspaceRepresentation + (g : FABL.F₂Cube n → ℤ) : Prop := + ∃ c : Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ, + ∀ x : FABL.F₂Cube n, + Int.ModEq ((2 : ℤ) ^ (n / 2)) (g x) (halfSubspaceCombination c x) + +private theorem hasHalfSubspaceRepresentation_of_pointwise_modeq + {g h : FABL.F₂Cube n → ℤ} + (hgh : ∀ x, Int.ModEq ((2 : ℤ) ^ (n / 2)) (g x) (h x)) + (hh : HasHalfSubspaceRepresentation h) : + HasHalfSubspaceRepresentation g := by + obtain ⟨c, hc⟩ := hh + exact ⟨c, fun x ↦ (hgh x).trans (hc x)⟩ + +private theorem HasHalfSubspaceRepresentation.add + {g h : FABL.F₂Cube n → ℤ} + (hg : HasHalfSubspaceRepresentation g) + (hh : HasHalfSubspaceRepresentation h) : + HasHalfSubspaceRepresentation (fun x ↦ g x + h x) := by + classical + obtain ⟨c, hc⟩ := hg + obtain ⟨d, hd⟩ := hh + refine ⟨fun E ↦ c E + d E, fun x ↦ ?_⟩ + simpa [halfSubspaceCombination, add_mul, Finset.sum_add_distrib] using + (hc x).add (hd x) + +private theorem HasHalfSubspaceRepresentation.neg + {g : FABL.F₂Cube n → ℤ} + (hg : HasHalfSubspaceRepresentation g) : + HasHalfSubspaceRepresentation (fun x ↦ -g x) := by + classical + obtain ⟨c, hc⟩ := hg + refine ⟨fun E ↦ -c E, fun x ↦ ?_⟩ + simpa [halfSubspaceCombination] using (hc x).neg + +private theorem HasHalfSubspaceRepresentation.intMul + (a : ℤ) {g : FABL.F₂Cube n → ℤ} + (hg : HasHalfSubspaceRepresentation g) : + HasHalfSubspaceRepresentation (fun x ↦ a * g x) := by + classical + obtain ⟨c, hc⟩ := hg + refine ⟨fun E ↦ a * c E, fun x ↦ ?_⟩ + have hx := (hc x).mul_left a + rw [halfSubspaceCombination] at hx ⊢ + rw [Finset.mul_sum] at hx + simpa [mul_assoc] using hx + +private theorem HasHalfSubspaceRepresentation.sum + {I : Type*} + (s : Finset I) (g : I → FABL.F₂Cube n → ℤ) + (hg : ∀ i ∈ s, HasHalfSubspaceRepresentation (g i)) : + HasHalfSubspaceRepresentation (fun x ↦ ∑ i ∈ s, g i x) := by + classical + induction s using Finset.induction_on with + | empty => + refine ⟨fun _ ↦ 0, fun x ↦ ?_⟩ + simp [halfSubspaceCombination] + | @insert i s hi ih => + have hgi := hg i (Finset.mem_insert_self i s) + have hgs : ∀ j ∈ s, HasHalfSubspaceRepresentation (g j) := by + intro j hj + exact hg j (Finset.mem_insert_of_mem hj) + simpa [hi] using hgi.add (ih hgs) + +/-- The indicator of a half-dimensional subspace is itself a half-subspace +combination. -/ +theorem hasHalfSubspaceRepresentation_indicator_of_finrank_eq + (F : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hF : Module.finrank FABL.𝔽₂ F = n / 2) : + HasHalfSubspaceRepresentation (linearSubspaceIndicatorInt F) := by + classical + let c : Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ := + fun E ↦ if E = F then 1 else 0 + refine ⟨c, fun x ↦ ?_⟩ + have hmem : F ∈ binaryLinearSubspaces (n / 2) n := + (mem_binaryLinearSubspaces F).mpr hF + have hcombination : halfSubspaceCombination c x = + linearSubspaceIndicatorInt F x := by + simp [halfSubspaceCombination, c, hmem] + rw [hcombination] + +private theorem hasHalfSubspaceRepresentation_indicator_of_half_le_finrank_aux + (d : ℕ) : + ∀ F : Submodule FABL.𝔽₂ (FABL.F₂Cube n), + Module.finrank FABL.𝔽₂ F = d → n / 2 ≤ d → + HasHalfSubspaceRepresentation (linearSubspaceIndicatorInt F) := by + induction d using Nat.strong_induction_on with + | h d ih => + intro F hFd hhalf + by_cases hd : d = n / 2 + · apply hasHalfSubspaceRepresentation_indicator_of_finrank_eq F + omega + · have hhalfLt : n / 2 < Module.finrank FABL.𝔽₂ F := by omega + have hkernel : ∀ ell ∈ nonzeroDualFinset F, + HasHalfSubspaceRepresentation + (linearSubspaceIndicatorInt (ambientFunctionalKernel F ell)) := by + intro ell hell + have hrank := finrank_ambientFunctionalKernel F ell + ((mem_nonzeroDualFinset F ell).mp hell) + have hkernelRank : + Module.finrank FABL.𝔽₂ (ambientFunctionalKernel F ell) = d - 1 := by + rw [hFd] at hrank + omega + apply ih (d - 1) (by omega) (ambientFunctionalKernel F ell) + hkernelRank + omega + have hsum := HasHalfSubspaceRepresentation.sum + (nonzeroDualFinset F) + (fun ell ↦ linearSubspaceIndicatorInt (ambientFunctionalKernel F ell)) + hkernel + apply hasHalfSubspaceRepresentation_of_pointwise_modeq + (functionalKernelCombination_modeq F hhalfLt) + exact hsum.neg + +/-- The high-dimensional branch of Carlet Lemma 3. -/ +theorem hasHalfSubspaceRepresentation_indicator_of_half_le_finrank + (F : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hF : n / 2 ≤ Module.finrank FABL.𝔽₂ F) : + HasHalfSubspaceRepresentation (linearSubspaceIndicatorInt F) := + hasHalfSubspaceRepresentation_indicator_of_half_le_finrank_aux + (Module.finrank FABL.𝔽₂ F) F rfl hF + +private theorem exists_superSubmodule_finrank_add_two + (F : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hF : Module.finrank FABL.𝔽₂ F + 2 ≤ n) : + ∃ G : Submodule FABL.𝔽₂ (FABL.F₂Cube n), + F ≤ G ∧ + Module.finrank FABL.𝔽₂ G = + Module.finrank FABL.𝔽₂ F + 2 := by + have hambient : Module.finrank FABL.𝔽₂ (FABL.F₂Cube n) = n := by + rw [Module.finrank_fintype_fun_eq_card] + simp + have hFlt : Module.finrank FABL.𝔽₂ F < + Module.finrank FABL.𝔽₂ (FABL.F₂Cube n) := by omega + obtain ⟨a, ha⟩ := Submodule.exists_of_finrank_lt F hFlt + have haF : a ∉ F := by simpa using ha 1 one_ne_zero + let A := F ⊔ Submodule.span FABL.𝔽₂ {a} + have hArank : Module.finrank FABL.𝔽₂ A = + Module.finrank FABL.𝔽₂ F + 1 := by + exact Submodule.finrank_sup_span_singleton haF + have hAlt : Module.finrank FABL.𝔽₂ A < + Module.finrank FABL.𝔽₂ (FABL.F₂Cube n) := by omega + obtain ⟨b, hb⟩ := Submodule.exists_of_finrank_lt A hAlt + have hbA : b ∉ A := by simpa using hb 1 one_ne_zero + let G := A ⊔ Submodule.span FABL.𝔽₂ {b} + refine ⟨G, le_trans le_sup_left le_sup_left, ?_⟩ + rw [show Module.finrank FABL.𝔽₂ G = + Module.finrank FABL.𝔽₂ A + 1 by + exact Submodule.finrank_sup_span_singleton hbA, + hArank] + +/-- The preimage in the ambient cube of a functional kernel on the quotient +`G / F`. -/ +local instance geometricRelativeQuotientFinite + (F G : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) : + Finite (G ⧸ F.comap G.subtype) := + Finite.of_surjective (Submodule.mkQ (F.comap G.subtype)) + (Submodule.mkQ_surjective (F.comap G.subtype)) + +noncomputable def rankTwoIntermediateSubspace + (F G : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (ell : Module.Dual FABL.𝔽₂ (G ⧸ F.comap G.subtype)) : + Submodule FABL.𝔽₂ (FABL.F₂Cube n) := + ambientFunctionalKernel G (ell.comp (Submodule.mkQ (F.comap G.subtype))) + +theorem mem_rankTwoIntermediateSubspace_iff + (F G : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (ell : Module.Dual FABL.𝔽₂ (G ⧸ F.comap G.subtype)) + (x : FABL.F₂Cube n) (hxG : x ∈ G) : + x ∈ rankTwoIntermediateSubspace F G ell ↔ + ell (Submodule.mkQ (F.comap G.subtype) ⟨x, hxG⟩) = 0 := by + rw [rankTwoIntermediateSubspace, + mem_ambientFunctionalKernel_iff G _ x hxG] + rfl + +theorem finrank_rankTwoIntermediateSubspace + (F G : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (ell : Module.Dual FABL.𝔽₂ (G ⧸ F.comap G.subtype)) + (hell : ell ≠ 0) : + Module.finrank FABL.𝔽₂ (rankTwoIntermediateSubspace F G ell) + 1 = + Module.finrank FABL.𝔽₂ G := by + apply finrank_ambientFunctionalKernel + intro hcomp + apply hell + apply LinearMap.ext + intro q + obtain ⟨g, rfl⟩ := Submodule.mkQ_surjective (F.comap G.subtype) q + have hg := LinearMap.congr_fun hcomp g + simpa [rankTwoIntermediateSubspace] using hg + +private theorem finrank_relativeQuotient_eq_two + (F G : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hFG : F ≤ G) + (hG : Module.finrank FABL.𝔽₂ G = + Module.finrank FABL.𝔽₂ F + 2) : + Module.finrank FABL.𝔽₂ (G ⧸ F.comap G.subtype) = 2 := by + let W : Submodule FABL.𝔽₂ G := F.comap G.subtype + have hmap : W.map G.subtype = F := by + rw [show W = F.comap G.subtype by rfl, Submodule.map_comap_subtype, + inf_eq_right.mpr hFG] + have hW : Module.finrank FABL.𝔽₂ W = + Module.finrank FABL.𝔽₂ F := by + rw [← Submodule.finrank_map_subtype_eq G W, hmap] + have hquotient := W.finrank_quotient_add_finrank + dsimp [W] at hW hquotient + rw [hW, hG] at hquotient + omega + +/-- The rank-two subspace diamond: if `G/F` has dimension two, its three +nonzero dual kernels are the three intermediate subspaces, and their indicator +sum is `1_G + 2·1_F`. -/ +theorem rankTwoSubspaceDiamond + (F G : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hFG : F ≤ G) + (hG : Module.finrank FABL.𝔽₂ G = + Module.finrank FABL.𝔽₂ F + 2) : + (∀ ell ∈ nonzeroDualFinset (G ⧸ F.comap G.subtype), + Module.finrank FABL.𝔽₂ (rankTwoIntermediateSubspace F G ell) = + Module.finrank FABL.𝔽₂ F + 1) ∧ + ∀ x : FABL.F₂Cube n, + (∑ ell ∈ nonzeroDualFinset (G ⧸ F.comap G.subtype), + linearSubspaceIndicatorInt (rankTwoIntermediateSubspace F G ell) x) = + linearSubspaceIndicatorInt G x + + 2 * linearSubspaceIndicatorInt F x := by + classical + have hquotient := finrank_relativeQuotient_eq_two F G hFG hG + constructor + · intro ell hell + have hrank := finrank_rankTwoIntermediateSubspace F G ell + ((mem_nonzeroDualFinset _ ell).mp hell) + rw [hG] at hrank + omega + · intro x + by_cases hxG : x ∈ G + · let q : G ⧸ F.comap G.subtype := + Submodule.mkQ (F.comap G.subtype) ⟨x, hxG⟩ + have hqzero : q = 0 ↔ x ∈ F := by + simp [q, Submodule.Quotient.mk_eq_zero] + by_cases hxF : x ∈ F + · have hq : q = 0 := hqzero.mpr hxF + have hsum : + (∑ ell ∈ nonzeroDualFinset (G ⧸ F.comap G.subtype), + linearSubspaceIndicatorInt (rankTwoIntermediateSubspace F G ell) x) = + ((nonzeroDualFinset (G ⧸ F.comap G.subtype)).card : ℤ) := by + calc + (∑ ell ∈ nonzeroDualFinset (G ⧸ F.comap G.subtype), + linearSubspaceIndicatorInt + (rankTwoIntermediateSubspace F G ell) x) = + ∑ ell ∈ nonzeroDualFinset (G ⧸ F.comap G.subtype), + (1 : ℤ) := by + apply Finset.sum_congr rfl + intro ell _hell + have hmk : + Submodule.mkQ (F.comap G.subtype) ⟨x, hxG⟩ = 0 := hq + rw [linearSubspaceIndicatorInt, + mem_rankTwoIntermediateSubspace_iff F G ell x hxG] + simp [hmk] + _ = _ := by simp + rw [hsum, card_nonzeroDualFinset, hquotient] + norm_num [linearSubspaceIndicatorInt, hxG, hxF] + · have hq : q ≠ 0 := fun h ↦ hxF (hqzero.mp h) + have hsum : + (∑ ell ∈ nonzeroDualFinset (G ⧸ F.comap G.subtype), + linearSubspaceIndicatorInt (rankTwoIntermediateSubspace F G ell) x) = + (((nonzeroDualFinset (G ⧸ F.comap G.subtype)).filter + fun ell ↦ ell q = 0).card : ℤ) := by + calc + (∑ ell ∈ nonzeroDualFinset (G ⧸ F.comap G.subtype), + linearSubspaceIndicatorInt + (rankTwoIntermediateSubspace F G ell) x) = + ∑ ell ∈ nonzeroDualFinset (G ⧸ F.comap G.subtype), + if ell q = 0 then (1 : ℤ) else 0 := by + apply Finset.sum_congr rfl + intro ell _hell + rw [linearSubspaceIndicatorInt, + mem_rankTwoIntermediateSubspace_iff F G ell x hxG] + simp [q] + _ = _ := by rw [Finset.sum_boole] + rw [hsum, card_nonzeroDual_vanishing _ q hq, hquotient] + norm_num [linearSubspaceIndicatorInt, hxG, hxF] + · have hxF : x ∉ F := fun hx ↦ hxG (hFG hx) + have hkernel : + ∀ ell : Module.Dual FABL.𝔽₂ (G ⧸ F.comap G.subtype), + x ∉ rankTwoIntermediateSubspace F G ell := by + intro ell hx + exact hxG (G.map_subtype_le _ hx) + simp [linearSubspaceIndicatorInt, hxG, hxF, hkernel] + +private theorem hasHalfSubspaceRepresentation_scaledIndicator_aux + (hn : Even n) (k : ℕ) : + ∀ F : Submodule FABL.𝔽₂ (FABL.F₂Cube n), + n / 2 - Module.finrank FABL.𝔽₂ F = k → + Module.finrank FABL.𝔽₂ F ≤ n / 2 → + HasHalfSubspaceRepresentation + (fun x ↦ (2 : ℤ) ^ + (n / 2 - Module.finrank FABL.𝔽₂ F) * + linearSubspaceIndicatorInt F x) := by + induction k using Nat.strong_induction_on with + | h k ih => + intro F hgap hFle + by_cases hk : k = 0 + · have hFrank : Module.finrank FABL.𝔽₂ F = n / 2 := by omega + simpa [hFrank] using + hasHalfSubspaceRepresentation_indicator_of_finrank_eq F hFrank + · have hFlt : Module.finrank FABL.𝔽₂ F < n / 2 := by omega + have hroom : Module.finrank FABL.𝔽₂ F + 2 ≤ n := by + rcases hn with ⟨r, hr⟩ + have hhalf : n / 2 = r := by omega + omega + obtain ⟨G, hFG, hGrank⟩ := + exists_superSubmodule_finrank_add_two F hroom + have hdiamond := rankTwoSubspaceDiamond F G hFG hGrank + let p : ℤ := + (2 : ℤ) ^ (n / 2 - Module.finrank FABL.𝔽₂ F - 1) + have hinter : ∀ ell ∈ nonzeroDualFinset (G ⧸ F.comap G.subtype), + HasHalfSubspaceRepresentation + (fun x ↦ p * linearSubspaceIndicatorInt + (rankTwoIntermediateSubspace F G ell) x) := by + intro ell hell + have hrank := hdiamond.1 ell hell + have hle : Module.finrank FABL.𝔽₂ + (rankTwoIntermediateSubspace F G ell) ≤ n / 2 := by omega + have hnewGap : n / 2 - Module.finrank FABL.𝔽₂ + (rankTwoIntermediateSubspace F G ell) = k - 1 := by omega + have hrec := ih (k - 1) (by omega) + (rankTwoIntermediateSubspace F G ell) hnewGap hle + have hexponent : + n / 2 - Module.finrank FABL.𝔽₂ + (rankTwoIntermediateSubspace F G ell) = + n / 2 - Module.finrank FABL.𝔽₂ F - 1 := by omega + simpa [p, hexponent] using hrec + have hinterSum := HasHalfSubspaceRepresentation.sum + (nonzeroDualFinset (G ⧸ F.comap G.subtype)) + (fun ell x ↦ p * linearSubspaceIndicatorInt + (rankTwoIntermediateSubspace F G ell) x) + hinter + have hGrepresentation : HasHalfSubspaceRepresentation + (fun x ↦ p * linearSubspaceIndicatorInt G x) := by + by_cases hGle : Module.finrank FABL.𝔽₂ G ≤ n / 2 + · have hGgap : n / 2 - Module.finrank FABL.𝔽₂ G < k := by + omega + have hrec := ih (n / 2 - Module.finrank FABL.𝔽₂ G) + hGgap G rfl hGle + have hp : p = 2 * (2 : ℤ) ^ + (n / 2 - Module.finrank FABL.𝔽₂ G) := by + have hexponent : + n / 2 - Module.finrank FABL.𝔽₂ F - 1 = + (n / 2 - Module.finrank FABL.𝔽₂ G) + 1 := by omega + dsimp [p] + rw [hexponent, pow_succ] + ring + simpa [hp, mul_assoc] using hrec.intMul 2 + · have hGhigh : n / 2 ≤ Module.finrank FABL.𝔽₂ G := by omega + have hp : p = 1 := by + have hexponent : + n / 2 - Module.finrank FABL.𝔽₂ F - 1 = 0 := by omega + simp [p, hexponent] + simpa [hp] using + hasHalfSubspaceRepresentation_indicator_of_half_le_finrank G hGhigh + have hright := hinterSum.add hGrepresentation.neg + apply hasHalfSubspaceRepresentation_of_pointwise_modeq (h := fun x ↦ + (∑ ell ∈ nonzeroDualFinset (G ⧸ F.comap G.subtype), + p * linearSubspaceIndicatorInt + (rankTwoIntermediateSubspace F G ell) x) + + -(p * linearSubspaceIndicatorInt G x)) + · intro x + have hpower : (2 : ℤ) ^ + (n / 2 - Module.finrank FABL.𝔽₂ F) = 2 * p := by + have hexponent : n / 2 - Module.finrank FABL.𝔽₂ F = + (n / 2 - Module.finrank FABL.𝔽₂ F - 1) + 1 := by + omega + dsimp [p] + conv_lhs => rw [hexponent] + rw [pow_succ] + ring + rw [hpower, Int.modEq_iff_dvd] + refine ⟨0, ?_⟩ + rw [← Finset.mul_sum, hdiamond.2 x] + ring + · exact hright + +/-- The low-dimensional branch of Carlet Lemma 3, strengthened so that no +separate constant term is needed. -/ +theorem hasHalfSubspaceRepresentation_scaledIndicator_of_finrank_le_half + (F : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hn : Even n) + (hF : Module.finrank FABL.𝔽₂ F ≤ n / 2) : + HasHalfSubspaceRepresentation + (fun x ↦ (2 : ℤ) ^ + (n / 2 - Module.finrank FABL.𝔽₂ F) * + linearSubspaceIndicatorInt F x) := + hasHalfSubspaceRepresentation_scaledIndicator_aux hn + (n / 2 - Module.finrank FABL.𝔽₂ F) F rfl hF + +/-- Carlet Lemma 3 in its two source-facing branches. -/ +theorem carletLemma3 + (F : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hn : Even n) : + (Module.finrank FABL.𝔽₂ F < n / 2 → + ∃ m : ℤ, ∃ c : Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ, + ∀ x : FABL.F₂Cube n, + Int.ModEq ((2 : ℤ) ^ (n / 2)) + ((2 : ℤ) ^ (n / 2 - Module.finrank FABL.𝔽₂ F) * + linearSubspaceIndicatorInt F x) + (m + halfSubspaceCombination c x)) ∧ + (n / 2 < Module.finrank FABL.𝔽₂ F → + ∃ c : Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ, + ∀ x : FABL.F₂Cube n, + Int.ModEq ((2 : ℤ) ^ (n / 2)) + (linearSubspaceIndicatorInt F x) + (halfSubspaceCombination c x)) := by + constructor + · intro hF + obtain ⟨c, hc⟩ := + hasHalfSubspaceRepresentation_scaledIndicator_of_finrank_le_half F hn hF.le + exact ⟨0, c, fun x ↦ by simpa using hc x⟩ + · intro hF + exact hasHalfSubspaceRepresentation_indicator_of_half_le_finrank F hF.le + +/-- The integer square-free numerical monomial indexed by a coordinate set. -/ +def numericalMonomialInt + (I : Finset (Fin n)) (x : FABL.F₂Cube n) : ℤ := + ∏ i ∈ I, bitValueInt (x i) + +theorem numericalMonomialInt_cast + (I : Finset (Fin n)) (x : FABL.F₂Cube n) : + (numericalMonomialInt I x : ℝ) = FABL.numericalMonomial I x := by + classical + unfold numericalMonomialInt FABL.numericalMonomial + push_cast + apply Finset.prod_congr rfl + intro i _hi + by_cases hxi : x i = 1 <;> simp [bitValueInt, hxi] + +private theorem coordinateZeroIndicatorInt_eq_prod + (I : Finset (Fin n)) (x : FABL.F₂Cube n) : + linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace I) x = + ∏ i ∈ I, (1 - bitValueInt (x i)) := by + classical + by_cases hx : x ∈ FABL.F₂DecisionTree.coordinateZeroSubspace I + · rw [linearSubspaceIndicatorInt, if_pos hx] + symm + apply Finset.prod_eq_one + intro i hi + have hxi := + (FABL.F₂DecisionTree.mem_coordinateZeroSubspace_iff I x).mp hx i hi + simp [bitValueInt, hxi] + · rw [linearSubspaceIndicatorInt, if_neg hx] + have hnot := hx + rw [FABL.F₂DecisionTree.mem_coordinateZeroSubspace_iff] at hnot + push Not at hnot + obtain ⟨i, hi, hxi⟩ := hnot + have hxiOne : x i = 1 := Fin.eq_one_of_ne_zero _ hxi + symm + apply Finset.prod_eq_zero hi + simp [bitValueInt, hxiOne] + +/-- Inclusion-exclusion expresses a numerical monomial as an alternating sum +of indicators of coordinate zero subspaces. -/ +theorem numericalMonomialInt_eq_sum_coordinateZeroIndicators + (I : Finset (Fin n)) (x : FABL.F₂Cube n) : + numericalMonomialInt I x = + ∑ J ∈ I.powerset, + (-1 : ℤ) ^ J.card * + linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace J) x := by + classical + have hexpand := Finset.prod_sub + (fun _ : Fin n ↦ (1 : ℤ)) + (fun i ↦ 1 - bitValueInt (x i)) I + simpa [numericalMonomialInt, coordinateZeroIndicatorInt_eq_prod] using hexpand + +/-- The coordinate zero subspace indexed by `I` has dimension `n - |I|`. -/ +theorem finrank_coordinateZeroSubspace + (I : Finset (Fin n)) : + Module.finrank FABL.𝔽₂ + (FABL.F₂DecisionTree.coordinateZeroSubspace I) = n - I.card := by + have hcodimension := + FABL.F₂DecisionTree.f₂Codimension_coordinateZeroSubspace I + rw [FABL.f₂Codimension, FABL.finrank_perpendicularSubspace] at hcodimension + have hfinrank : Module.finrank FABL.𝔽₂ + (FABL.F₂DecisionTree.coordinateZeroSubspace I) ≤ n := by + simpa using + (FABL.F₂DecisionTree.coordinateZeroSubspace I).finrank_le + omega + +@[simp] theorem linearSubspaceIndicatorInt_coordinateZeroSubspace_univ + (x : FABL.F₂Cube n) : + linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace Finset.univ) x = + originIndicatorInt x := by + classical + by_cases hx : x = 0 + · subst x + simp [linearSubspaceIndicatorInt, originIndicatorInt] + · have hnot : + x ∉ FABL.F₂DecisionTree.coordinateZeroSubspace + (Finset.univ : Finset (Fin n)) := by + intro hmem + apply hx + funext i + exact (FABL.F₂DecisionTree.mem_coordinateZeroSubspace_iff _ x).mp + hmem i (Finset.mem_univ i) + simp [linearSubspaceIndicatorInt, originIndicatorInt, hx, hnot] + +/-- The integral numerical normal form evaluates to the zero-one embedding of +a Boolean function. -/ +theorem bitValueInt_eq_sum_booleanNumericalCoeffInt_mul_numericalMonomialInt + (f : BooleanFunction n) (x : FABL.F₂Cube n) : + bitValueInt (f x) = + ∑ I : Finset (Fin n), + FABL.booleanNumericalCoeffInt f I * numericalMonomialInt I x := by + classical + apply Int.cast_injective (α := ℝ) + have hnormal := congrFun + (FABL.numericalEval_numericalCoeff (FABL.booleanRealEmbedding f)) x + rw [FABL.numericalEval] at hnormal + calc + (bitValueInt (f x) : ℝ) = FABL.booleanRealEmbedding f x := by + by_cases hfx : f x = 1 <;> simp [bitValueInt, FABL.booleanRealEmbedding, hfx] + _ = ∑ I : Finset (Fin n), + FABL.numericalCoeff (FABL.booleanRealEmbedding f) I * + FABL.numericalMonomial I x := hnormal.symm + _ = (↑(∑ I : Finset (Fin n), + FABL.booleanNumericalCoeffInt f I * numericalMonomialInt I x) : ℝ) := by + push_cast + apply Finset.sum_congr rfl + intro I _hI + rw [FABL.numericalCoeff_booleanRealEmbedding_eq_intCast, + numericalMonomialInt_cast] + +private theorem hasHalfSubspaceRepresentation_intMul_coordinateZeroIndicator + (I : Finset (Fin n)) (a : ℤ) (hn : Even n) + (hdiv : Module.finrank FABL.𝔽₂ + (FABL.F₂DecisionTree.coordinateZeroSubspace I) < n / 2 → + (2 : ℤ) ^ (n / 2 - Module.finrank FABL.𝔽₂ + (FABL.F₂DecisionTree.coordinateZeroSubspace I)) ∣ a) : + HasHalfSubspaceRepresentation + (fun x ↦ a * linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace I) x) := by + let Z := FABL.F₂DecisionTree.coordinateZeroSubspace I + by_cases hZ : Module.finrank FABL.𝔽₂ Z < n / 2 + · obtain ⟨q, hq⟩ := hdiv hZ + have hscaled := + hasHalfSubspaceRepresentation_scaledIndicator_of_finrank_le_half Z hn hZ.le + have hmultiple := hscaled.intMul q + simpa [Z, hq, mul_assoc, mul_comm, mul_left_comm] using hmultiple + · have hZhalf : n / 2 ≤ Module.finrank FABL.𝔽₂ Z := by omega + exact (hasHalfSubspaceRepresentation_indicator_of_half_le_finrank Z hZhalf).intMul a + +private theorem hasHalfSubspaceRepresentation_intMul_numericalMonomialInt + (I : Finset (Fin n)) (a : ℤ) (hn : Even n) + (hdiv : n / 2 < I.card → + (2 : ℤ) ^ (I.card - n / 2) ∣ a) : + HasHalfSubspaceRepresentation + (fun x ↦ a * numericalMonomialInt I x) := by + classical + have hterms : ∀ J ∈ I.powerset, + HasHalfSubspaceRepresentation (fun x ↦ + a * ((-1 : ℤ) ^ J.card * linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace J) x)) := by + intro J hJ + have hJI : J ⊆ I := Finset.mem_powerset.mp hJ + have hbase := hasHalfSubspaceRepresentation_intMul_coordinateZeroIndicator + J (a * (-1 : ℤ) ^ J.card) hn (by + intro hZ + have hJhalf : n / 2 < J.card := by + rw [finrank_coordinateZeroSubspace] at hZ + rcases hn with ⟨r, hr⟩ + have hhalf : n / 2 = r := by omega + omega + have hIhalf : n / 2 < I.card := + lt_of_lt_of_le hJhalf (Finset.card_le_card hJI) + have hpowers : (2 : ℤ) ^ (J.card - n / 2) ∣ + (2 : ℤ) ^ (I.card - n / 2) := + pow_dvd_pow (2 : ℤ) + (Nat.sub_le_sub_right (Finset.card_le_card hJI) (n / 2)) + have hcoefficient := (hpowers.trans (hdiv hIhalf)).mul_right + ((-1 : ℤ) ^ J.card) + rw [finrank_coordinateZeroSubspace] + rcases hn with ⟨r, hr⟩ + have hhalf : n / 2 = r := by omega + have hJle : J.card ≤ n := by simpa using Finset.card_le_univ J + have hexponent : n / 2 - (n - J.card) = J.card - n / 2 := by omega + rw [hexponent] + exact hcoefficient) + simpa [mul_assoc] using hbase + have hsum := HasHalfSubspaceRepresentation.sum I.powerset + (fun J x ↦ a * ((-1 : ℤ) ^ J.card * + linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace J) x)) hterms + apply hasHalfSubspaceRepresentation_of_pointwise_modeq + (h := fun x ↦ ∑ J ∈ I.powerset, + a * ((-1 : ℤ) ^ J.card * linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace J) x)) + · intro x + rw [numericalMonomialInt_eq_sum_coordinateZeroIndicators, + Finset.mul_sum] + · exact hsum + +private theorem hasHalfSubspaceRepresentation_topMonomial_add_origin + (hn : Even n) (hnTwo : 2 ≤ n) : + HasHalfSubspaceRepresentation (fun x ↦ + (2 : ℤ) ^ (n / 2 - 1) * + numericalMonomialInt (Finset.univ : Finset (Fin n)) x + + (2 : ℤ) ^ (n / 2 - 1) * originIndicatorInt x) := by + classical + let t : ℤ := (2 : ℤ) ^ (n / 2 - 1) + let N : Finset (Fin n) := Finset.univ + let s : Finset (Finset (Fin n)) := N.powerset.erase N + have hterms : ∀ J ∈ s, + HasHalfSubspaceRepresentation (fun x ↦ + t * ((-1 : ℤ) ^ J.card * linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace J) x)) := by + intro J hJ + have hJne : J ≠ N := Finset.ne_of_mem_erase hJ + have hJsubset : J ⊆ N := + Finset.mem_powerset.mp (Finset.mem_of_mem_erase hJ) + have hJcardLt : J.card < n := by + have hcardLe : J.card ≤ n := by simpa [N] using Finset.card_le_univ J + apply lt_of_le_of_ne hcardLe + intro hcard + apply hJne + apply Finset.eq_univ_of_card + simpa [N] using hcard + have hbase := hasHalfSubspaceRepresentation_intMul_coordinateZeroIndicator + J (t * (-1 : ℤ) ^ J.card) hn (by + intro hZ + have hexponent : + n / 2 - Module.finrank FABL.𝔽₂ + (FABL.F₂DecisionTree.coordinateZeroSubspace J) = + J.card - n / 2 := by + rw [finrank_coordinateZeroSubspace] + rcases hn with ⟨r, hr⟩ + have hhalf : n / 2 = r := by omega + omega + have hle : J.card - n / 2 ≤ n / 2 - 1 := by + rcases hn with ⟨r, hr⟩ + have hhalf : n / 2 = r := by omega + omega + rw [hexponent] + exact (pow_dvd_pow (2 : ℤ) hle).mul_right ((-1 : ℤ) ^ J.card)) + simpa [mul_assoc] using hbase + have hsum := HasHalfSubspaceRepresentation.sum s + (fun J x ↦ t * ((-1 : ℤ) ^ J.card * + linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace J) x)) hterms + apply hasHalfSubspaceRepresentation_of_pointwise_modeq + (h := fun x ↦ ∑ J ∈ s, + t * ((-1 : ℤ) ^ J.card * linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace J) x)) + · intro x + have hNmem : N ∈ N.powerset := Finset.mem_powerset.mpr (Subset.rfl) + have hdecomp := Finset.sum_erase_add N.powerset + (fun J ↦ t * ((-1 : ℤ) ^ J.card * + linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace J) x)) hNmem + have hNcard : N.card = n := by simp [N] + have hsign : (-1 : ℤ) ^ N.card = 1 := by + rw [hNcard, hn.neg_one_pow] + have htopTerm : + t * ((-1 : ℤ) ^ N.card * + linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace N) x) = + t * originIndicatorInt x := by + rw [hsign, one_mul] + congr 1 + exact linearSubspaceIndicatorInt_coordinateZeroSubspace_univ x + have hfull : t * numericalMonomialInt N x = + (∑ J ∈ s, t * ((-1 : ℤ) ^ J.card * + linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace J) x)) + + t * originIndicatorInt x := by + rw [numericalMonomialInt_eq_sum_coordinateZeroIndicators, + Finset.mul_sum] + change (∑ J ∈ N.powerset, t * ((-1 : ℤ) ^ J.card * + linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace J) x)) = _ + calc + _ = (∑ J ∈ N.powerset.erase N, + t * ((-1 : ℤ) ^ J.card * linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace J) x)) + + t * ((-1 : ℤ) ^ N.card * linearSubspaceIndicatorInt + (FABL.F₂DecisionTree.coordinateZeroSubspace N) x) := + hdecomp.symm + _ = _ := by rw [htopTerm] + have hdouble : (2 : ℤ) ^ (n / 2) = 2 * t := by + dsimp [t] + conv_lhs => rw [show n / 2 = (n / 2 - 1) + 1 by omega] + rw [pow_succ] + ring + dsimp [t, N] at hfull ⊢ + rw [Int.modEq_iff_dvd] + refine ⟨-originIndicatorInt x, ?_⟩ + rw [hfull, hdouble] + ring + · exact hsum + +private theorem hasHalfSubspaceRepresentation_bitValueInt_add_origin_of_conditions + (f : BooleanFunction n) (hn : Even n) (hnTwo : 2 ≤ n) + (hf : SatisfiesBentNNFCoefficientConditions f) : + HasHalfSubspaceRepresentation (fun x ↦ + bitValueInt (f x) + + (2 : ℤ) ^ (n / 2 - 1) * originIndicatorInt x) := by + classical + let N : Finset (Fin n) := Finset.univ + let s : Finset (Finset (Fin n)) := Finset.univ.erase N + have hterms : ∀ I ∈ s, + HasHalfSubspaceRepresentation (fun x ↦ + FABL.booleanNumericalCoeffInt f I * numericalMonomialInt I x) := by + intro I hI + have hIne : I ≠ N := Finset.ne_of_mem_erase hI + have hIcardLt : I.card < n := by + have hcardLe : I.card ≤ n := by simpa using Finset.card_le_univ I + apply lt_of_le_of_ne hcardLe + intro hcard + apply hIne + apply Finset.eq_univ_of_card + simpa [N] using hcard + apply hasHalfSubspaceRepresentation_intMul_numericalMonomialInt I + (FABL.booleanNumericalCoeffInt f I) hn + intro hIhalf + exact hf.1 I hIhalf hIcardLt + have hrest := HasHalfSubspaceRepresentation.sum s + (fun I x ↦ FABL.booleanNumericalCoeffInt f I * numericalMonomialInt I x) + hterms + have htop := hasHalfSubspaceRepresentation_topMonomial_add_origin hn hnTwo + have hright := hrest.add htop + apply hasHalfSubspaceRepresentation_of_pointwise_modeq (h := fun x ↦ + (∑ I ∈ s, + FABL.booleanNumericalCoeffInt f I * numericalMonomialInt I x) + + ((2 : ℤ) ^ (n / 2 - 1) * numericalMonomialInt N x + + (2 : ℤ) ^ (n / 2 - 1) * originIndicatorInt x)) + · intro x + have hNmem : N ∈ (Finset.univ : Finset (Finset (Fin n))) := + Finset.mem_univ N + have hdecomp := Finset.sum_erase_add + (Finset.univ : Finset (Finset (Fin n))) + (fun I ↦ FABL.booleanNumericalCoeffInt f I * numericalMonomialInt I x) + hNmem + have htopDvd := hf.2.dvd.mul_right (numericalMonomialInt N x) + rw [Int.modEq_iff_dvd] + have heq : + (∑ I ∈ s, + FABL.booleanNumericalCoeffInt f I * numericalMonomialInt I x) + + ((2 : ℤ) ^ (n / 2 - 1) * numericalMonomialInt N x + + (2 : ℤ) ^ (n / 2 - 1) * originIndicatorInt x) - + (bitValueInt (f x) + + (2 : ℤ) ^ (n / 2 - 1) * originIndicatorInt x) = + ((2 : ℤ) ^ (n / 2 - 1) - + FABL.booleanNumericalCoeffInt f N) * numericalMonomialInt N x := by + rw [bitValueInt_eq_sum_booleanNumericalCoeffInt_mul_numericalMonomialInt] + change (∑ I ∈ Finset.univ.erase N, + FABL.booleanNumericalCoeffInt f I * numericalMonomialInt I x) + _ - + ((∑ I : Finset (Fin n), + FABL.booleanNumericalCoeffInt f I * numericalMonomialInt I x) + _) = _ + rw [← hdecomp] + ring + rw [heq] + exact htopDvd + · simpa [N] using hright + +/-- The necessary direction of Carlet Theorem 12. -/ +theorem hasGeometricBentCongruence_of_isBent + (f : BooleanFunction n) (hn : Even n) (hnTwo : 2 ≤ n) + (hf : IsBent f) : + HasGeometricBentCongruence f := by + have hconditions := (isBent_iff_nnfCoefficientConditions f hn hnTwo).mp hf + obtain ⟨c, hc⟩ := + hasHalfSubspaceRepresentation_bitValueInt_add_origin_of_conditions + f hn hnTwo hconditions + refine ⟨c, fun x ↦ ?_⟩ + have hsub := (hc x).sub + (Int.ModEq.refl ((2 : ℤ) ^ (n / 2 - 1) * originIndicatorInt x)) + simpa [geometricBentExpression] using hsub + +/-- Carlet Theorem 12: in positive even dimension, bentness is equivalent to +the geometric congruence by half-dimensional subspace indicators. -/ +theorem isBent_iff_hasGeometricBentCongruence + (f : BooleanFunction n) (hn : Even n) (hnTwo : 2 ≤ n) : + IsBent f ↔ HasGeometricBentCongruence f := + ⟨hasGeometricBentCongruence_of_isBent f hn hnTwo, + isBent_of_hasGeometricBentCongruence f hn hnTwo⟩ + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/HyperBent.lean b/CryptBoolean/Carlet/Chapter06/HyperBent.lean new file mode 100644 index 0000000..430c001 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/HyperBent.lean @@ -0,0 +1,413 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter02.TracePairing +public import CryptBoolean.Carlet.Chapter05.QuadraticTraceRepresentation +public import CryptBoolean.Carlet.Chapter06.Bentness + +import Mathlib.GroupTheory.OrderOfElement + +/-! +# Hyper-bent functions + +Carlet Section 6.7: finite-field Walsh transforms and the power-reindexing +definition of hyper-bent functions. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +noncomputable local instance hyperBentFieldFintype : + Fintype (BinaryGaloisField n) := + Fintype.ofFinite (BinaryGaloisField n) + +/-- The raw Walsh transform of a Boolean function represented on `GF(2^n)`, +using the absolute-trace pairing for its linear characters. -/ +noncomputable def fieldWalshTransform + (f : FieldBooleanFunction n) (a : BinaryGaloisField n) : ℤ := + ∑ x : BinaryGaloisField n, + bitSignInt (f x + absoluteTrace n (a * x)) + +/-- Bentness in finite-field coordinates. -/ +def IsFieldBent (f : FieldBooleanFunction n) : Prop := + ∀ a : BinaryGaloisField n, + (fieldWalshTransform f a).natAbs = 2 ^ (n / 2) + +/-- Reindex a finite-field Boolean function by a power map. -/ +noncomputable def fieldPowerReindex (f : FieldBooleanFunction n) (i : ℕ) : + FieldBooleanFunction n := + fun x ↦ f (x ^ i) + +/-- A power map with exponent coprime to the order of the multiplicative +group is a permutation of `GF(2^n)`. -/ +theorem fieldPowerMap_bijective {i : ℕ} (hn : 2 ≤ n) + (hi : Nat.Coprime i (2 ^ n - 1)) : + Function.Bijective + (fun x : BinaryGaloisField n ↦ x ^ i) := by + have hcard : Nat.card (BinaryGaloisField n)ˣ = 2 ^ n - 1 := by + rw [Nat.card_units, GaloisField.card 2 n (by omega)] + have hcop : (Nat.card (BinaryGaloisField n)ˣ).Coprime i := by + rw [hcard] + exact hi.symm + have hunit : Function.Bijective + (fun z : (BinaryGaloisField n)ˣ ↦ z ^ i) := + Nat.Coprime.pow_left_bijective hcop + have hmodulus : 1 < 2 ^ n - 1 := by + have hpower : 2 ^ 2 ≤ 2 ^ n := + Nat.pow_le_pow_right (by omega) hn + norm_num at hpower ⊢ + omega + have hiPos : 0 < i := by + by_contra hnot + have hizero : i = 0 := by omega + subst i + simp only [Nat.coprime_zero_left] at hi + omega + constructor + · intro x y hxy + by_cases hx : x = 0 + · subst x + have hy : y = 0 := + (pow_eq_zero_iff hiPos.ne').mp + (by simpa [zero_pow hiPos.ne'] using hxy.symm) + exact hy.symm + · by_cases hy : y = 0 + · subst y + have hxzero : x = 0 := + (pow_eq_zero_iff hiPos.ne').mp + (by simpa [zero_pow hiPos.ne'] using hxy) + exact (hx hxzero).elim + · have hu : (Units.mk0 x hx : (BinaryGaloisField n)ˣ) ^ i = + (Units.mk0 y hy : (BinaryGaloisField n)ˣ) ^ i := by + apply Units.val_injective + exact hxy + exact congrArg Units.val (hunit.1 hu) + · intro y + by_cases hy : y = 0 + · exact ⟨0, by simp [hy, zero_pow hiPos.ne']⟩ + · obtain ⟨u, hu⟩ := hunit.2 (Units.mk0 y hy) + refine ⟨(u : BinaryGaloisField n), ?_⟩ + exact congrArg Units.val hu + +/-- The power permutation attached to a coprime exponent. -/ +noncomputable def fieldPowerEquiv {i : ℕ} (hn : 2 ≤ n) + (hi : Nat.Coprime i (2 ^ n - 1)) : + BinaryGaloisField n ≃ BinaryGaloisField n := + Equiv.ofBijective (fun x ↦ x ^ i) (fieldPowerMap_bijective hn hi) + +@[simp] theorem fieldPowerEquiv_apply {i : ℕ} (hn : 2 ≤ n) + (hi : Nat.Coprime i (2 ^ n - 1)) (x : BinaryGaloisField n) : + fieldPowerEquiv hn hi x = x ^ i := rfl + +/-- Power reindexing is precomposition by the corresponding field +permutation. -/ +theorem fieldPowerReindex_eq_comp_fieldPowerEquiv + (f : FieldBooleanFunction n) {i : ℕ} (hn : 2 ≤ n) + (hi : Nat.Coprime i (2 ^ n - 1)) : + fieldPowerReindex f i = f ∘ fieldPowerEquiv hn hi := by + rfl + +/-- Carlet's hyper-bent predicate: in even dimension, every power reindexing +whose exponent is coprime to `2^n-1` is bent. -/ +def IsHyperBent (f : FieldBooleanFunction n) : Prop := + Even n ∧ ∀ i : ℕ, Nat.Coprime i (2 ^ n - 1) → + IsFieldBent (fieldPowerReindex f i) + +/-- Every cube frequency has a unique finite-field trace coefficient, so its +raw Walsh coefficient is a field Walsh coefficient. -/ +theorem exists_fieldWalshTransform_eq_walshTransform + (theta : FABL.F₂Cube n ≃ₗ[FABL.𝔽₂] BinaryGaloisField n) + (f : FieldBooleanFunction n) (u : FABL.F₂Cube n) : + ∃ a : BinaryGaloisField n, + fieldWalshTransform f a = walshTransform (f ∘ theta) u := by + obtain ⟨a, ha, _haUnique⟩ := existsUnique_tracePairingCoefficient theta u + refine ⟨a, ?_⟩ + unfold fieldWalshTransform walshTransform + symm + apply Fintype.sum_equiv theta.toEquiv + intro x + unfold walshTerm + change bitSignInt (f (theta x) + FABL.f₂DotProduct u x) = _ + rw [ha x] + rfl + +/-- Conversely, every finite-field trace coefficient is represented by a +cube frequency under any linear choice of field coordinates. -/ +theorem exists_walshTransform_eq_fieldWalshTransform + (theta : FABL.F₂Cube n ≃ₗ[FABL.𝔽₂] BinaryGaloisField n) + (f : FieldBooleanFunction n) (a : BinaryGaloisField n) : + ∃ u : FABL.F₂Cube n, + walshTransform (f ∘ theta) u = fieldWalshTransform f a := by + let ell : FABL.F₂Cube n →ₗ[FABL.𝔽₂] FABL.𝔽₂ := + { toFun := fun x ↦ absoluteTrace n (a * theta x) + map_add' := by + intro x y + simp only [map_add, mul_add] + map_smul' := by + intro c x + rw [theta.map_smul] + have hmul : a * (c • theta x) = c • (a * theta x) := by + simp only [Algebra.smul_def] + ring + rw [hmul, map_smul] + rfl } + let u : FABL.F₂Cube n := + (dotProductEquiv FABL.𝔽₂ (Fin n)).symm ell + have hu (x : FABL.F₂Cube n) : + FABL.f₂DotProduct u x = absoluteTrace n (a * theta x) := by + change (dotProductEquiv FABL.𝔽₂ (Fin n) u) x = ell x + rw [LinearEquiv.apply_symm_apply] + refine ⟨u, ?_⟩ + unfold fieldWalshTransform walshTransform + apply Fintype.sum_equiv theta.toEquiv + intro x + unfold walshTerm + change bitSignInt (f (theta x) + FABL.f₂DotProduct u x) = _ + rw [hu x] + rfl + +/-- Finite-field bentness agrees with canonical cube bentness under every +linear coordinate identification. -/ +theorem isFieldBent_iff_isBent_comp_linearEquiv + (theta : FABL.F₂Cube n ≃ₗ[FABL.𝔽₂] BinaryGaloisField n) + (f : FieldBooleanFunction n) : + IsFieldBent f ↔ IsBent (f ∘ theta) := by + rw [isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half] + constructor + · intro hf u + obtain ⟨a, ha⟩ := + exists_fieldWalshTransform_eq_walshTransform theta f u + rw [← ha] + exact hf a + · intro hf a + obtain ⟨u, hu⟩ := + exists_walshTransform_eq_fieldWalshTransform theta f a + rw [← hu] + exact hf u + +/-- The power exponent `1` shows that every hyper-bent function is bent. -/ +theorem IsHyperBent.isFieldBent {f : FieldBooleanFunction n} + (hf : IsHyperBent f) : IsFieldBent f := by + have h := hf.2 1 (by simp) + have heq : fieldPowerReindex f 1 = f := by + funext x + simp [fieldPowerReindex] + rw [heq] at h + exact h + +/-- Coordinate form of the hyper-bent definition. -/ +theorem isHyperBent_iff_forall_isBent_powerReindex_comp_linearEquiv + (theta : FABL.F₂Cube n ≃ₗ[FABL.𝔽₂] BinaryGaloisField n) + (f : FieldBooleanFunction n) : + IsHyperBent f ↔ + Even n ∧ ∀ i : ℕ, Nat.Coprime i (2 ^ n - 1) → + IsBent (fieldPowerReindex f i ∘ theta) := by + unfold IsHyperBent + constructor + · rintro ⟨hn, hf⟩ + refine ⟨hn, fun i hi ↦ ?_⟩ + exact (isFieldBent_iff_isBent_comp_linearEquiv theta _).1 (hf i hi) + · rintro ⟨hn, hf⟩ + refine ⟨hn, fun i hi ↦ ?_⟩ + exact (isFieldBent_iff_isBent_comp_linearEquiv theta _).2 (hf i hi) + +/-- The two directions `1` and `c` span the quadratic extension when `c` +does not lie in the embedded subfield. -/ +theorem quadraticSubfieldBasisMap_bijective {m : ℕ} (hm : 0 < m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (c : BinaryGaloisField (2 * m)) (hc : c ∉ Set.range iota) : + Function.Bijective + (fun p : BinaryGaloisField m × BinaryGaloisField m ↦ + iota p.1 + c * iota p.2) := by + let coord : BinaryGaloisField m × BinaryGaloisField m → + BinaryGaloisField (2 * m) := + fun p ↦ iota p.1 + c * iota p.2 + have hcoordInjective : Function.Injective coord := by + rintro ⟨z, r⟩ ⟨z', r'⟩ hcoord + change iota z + c * iota r = iota z' + c * iota r' at hcoord + have hdiff : c * iota (r - r') = iota (z' - z) := by + rw [map_sub, map_sub] + linear_combination hcoord + have hr : r = r' := by + by_contra hrNe + have hrDiff : r - r' ≠ 0 := sub_ne_zero.mpr hrNe + apply hc + refine ⟨(z' - z) / (r - r'), ?_⟩ + symm + calc + c = iota (z' - z) / iota (r - r') := + (eq_div_iff ((map_ne_zero iota).mpr hrDiff)).2 hdiff + _ = iota ((z' - z) / (r - r')) := by + exact (map_div₀ iota (z' - z) (r - r')).symm + subst r' + have hz : z = z' := by + apply iota.toRingHom.injective + exact add_right_cancel hcoord + subst z' + rfl + have hcoordCard : Nat.card + (BinaryGaloisField m × BinaryGaloisField m) = + Nat.card (BinaryGaloisField (2 * m)) := by + rw [Nat.card_prod, + GaloisField.card 2 m hm.ne', + GaloisField.card 2 (2 * m) (mul_ne_zero (by omega) hm.ne')] + rw [← pow_add] + congr 1 + omega + exact (Nat.bijective_iff_injective_and_card coord).2 + ⟨hcoordInjective, hcoordCard⟩ + +/-- Coordinates in a quadratic binary extension relative to the basis +formed by `1` and an element outside the embedded subfield. -/ +noncomputable def quadraticSubfieldBasisEquiv {m : ℕ} (hm : 0 < m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (c : BinaryGaloisField (2 * m)) (hc : c ∉ Set.range iota) : + BinaryGaloisField m × BinaryGaloisField m ≃ + BinaryGaloisField (2 * m) := + Equiv.ofBijective + (fun p ↦ iota p.1 + c * iota p.2) + (quadraticSubfieldBasisMap_bijective hm iota c hc) + +@[simp] theorem quadraticSubfieldBasisEquiv_apply {m : ℕ} (hm : 0 < m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (c : BinaryGaloisField (2 * m)) (hc : c ∉ Set.range iota) + (p : BinaryGaloisField m × BinaryGaloisField m) : + quadraticSubfieldBasisEquiv hm iota c hc p = + iota p.1 + c * iota p.2 := rfl + +/-- A coprime power permutation of the quadratic extension restricts to a +power permutation of its embedded middle field. -/ +theorem quadraticSubfield_powerMap_bijective {m i : ℕ} (hm : 0 < m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (hi : Nat.Coprime i (2 ^ (2 * m) - 1)) : + Function.Bijective (fun r : BinaryGaloisField m ↦ r ^ i) := by + have hpowerInjective : Function.Injective + (fun x : BinaryGaloisField (2 * m) ↦ x ^ i) := + (fieldPowerMap_bijective (by omega) hi).1 + have hrestrictedInjective : Function.Injective + (fun r : BinaryGaloisField m ↦ r ^ i) := by + intro r s hrs + have hmap : (iota r) ^ i = (iota s) ^ i := by + simpa only [map_pow] using congrArg iota hrs + exact iota.toRingHom.injective (hpowerInjective hmap) + exact ⟨hrestrictedInjective, + (Finite.injective_iff_surjective).mp hrestrictedInjective⟩ + +/-- Membership in the quadratic subfield is invariant under every coprime +power permutation of the ambient field. -/ +theorem pow_mem_quadraticSubfield_iff {m i : ℕ} (hm : 0 < m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (hi : Nat.Coprime i (2 ^ (2 * m) - 1)) + (x : BinaryGaloisField (2 * m)) : + x ^ i ∈ Set.range iota ↔ x ∈ Set.range iota := by + have hpowerInjective : Function.Injective + (fun y : BinaryGaloisField (2 * m) ↦ y ^ i) := + (fieldPowerMap_bijective (by omega) hi).1 + have hrestricted := quadraticSubfield_powerMap_bijective hm iota hi + constructor + · rintro ⟨k, hk⟩ + obtain ⟨r, hr⟩ := hrestricted.2 k + change r ^ i = k at hr + refine ⟨r, hpowerInjective ?_⟩ + change (iota r) ^ i = x ^ i + rw [← map_pow, hr, hk] + · rintro ⟨r, rfl⟩ + exact ⟨r ^ i, map_pow iota r i⟩ + +/-- Carlet Lemma 4: a coprime power of a translated quadratic-subfield +line meets every non-subfield scalar multiple of the subfield exactly once. -/ +theorem existsUnique_subfield_power_intersection {m i : ℕ} (hm : 0 < m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (a omega : BinaryGaloisField (2 * m)) + (ha : a ∉ Set.range iota) + (_homega : omega ∉ Set.range iota) + (hi : Nat.Coprime i (2 ^ (2 * m) - 1)) : + ∃! z : BinaryGaloisField m, + ∃ k : BinaryGaloisField m, + a * (iota z + omega) ^ i = iota k := by + let power : BinaryGaloisField (2 * m) ≃ BinaryGaloisField (2 * m) := + fieldPowerEquiv (by omega) hi + let c : BinaryGaloisField (2 * m) := power.symm a⁻¹ + have hpowerInjective : Function.Injective + (fun x : BinaryGaloisField (2 * m) ↦ x ^ i) := by + intro x y hxy + apply power.injective + exact hxy + have hcPower : c ^ i = a⁻¹ := by + change power c = a⁻¹ + exact power.apply_symm_apply a⁻¹ + have ha0 : a ≠ 0 := by + intro haZero + apply ha + refine ⟨0, ?_⟩ + simp [haZero] + have hcOutside : c ∉ Set.range iota := by + rintro ⟨r, hr⟩ + have hinv : a⁻¹ = iota (r ^ i) := by + calc + a⁻¹ = c ^ i := hcPower.symm + _ = (iota r) ^ i := by rw [hr] + _ = iota (r ^ i) := by rw [map_pow] + apply ha + refine ⟨(r ^ i)⁻¹, ?_⟩ + simpa only [inv_inv, map_inv₀] using (congrArg Inv.inv hinv).symm + have hrestrictedPowerSurjective : Function.Surjective + (fun r : BinaryGaloisField m ↦ r ^ i) := + (quadraticSubfield_powerMap_bijective hm iota hi).2 + have hcondition (z : BinaryGaloisField m) : + (∃ k : BinaryGaloisField m, + a * (iota z + omega) ^ i = iota k) ↔ + ∃ r : BinaryGaloisField m, + iota z + omega = c * iota r := by + constructor + · rintro ⟨k, hk⟩ + obtain ⟨r, hr⟩ := hrestrictedPowerSurjective k + change r ^ i = k at hr + refine ⟨r, hpowerInjective ?_⟩ + calc + (iota z + omega) ^ i = a⁻¹ * (a * (iota z + omega) ^ i) := by + rw [← mul_assoc, inv_mul_cancel₀ ha0, one_mul] + _ = a⁻¹ * iota k := by rw [hk] + _ = c ^ i * iota (r ^ i) := by rw [hcPower, hr] + _ = (c * iota r) ^ i := by rw [mul_pow, map_pow] + · rintro ⟨r, hr⟩ + refine ⟨r ^ i, ?_⟩ + rw [hr, mul_pow, map_pow, hcPower, ← mul_assoc, + mul_inv_cancel₀ ha0, one_mul] + let coord := quadraticSubfieldBasisEquiv hm iota c hcOutside + obtain ⟨p, hp⟩ := coord.surjective omega + refine ⟨-p.1, ?_, ?_⟩ + · change ∃ k : BinaryGaloisField m, + a * (iota (-p.1) + omega) ^ i = iota k + rw [hcondition] + refine ⟨p.2, ?_⟩ + change iota p.1 + c * iota p.2 = omega at hp + rw [← hp, map_neg] + ring + · intro z hz + rw [hcondition] at hz + obtain ⟨r, hr⟩ := hz + have hzr : coord (-z, r) = omega := by + change iota (-z) + c * iota r = omega + rw [map_neg, ← hr] + ring + have hpairs := coord.injective (hzr.trans hp.symm) + simpa using congrArg (fun q ↦ -q.1) hpairs + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/HyperBentPartialSpread.lean b/CryptBoolean/Carlet/Chapter06/HyperBentPartialSpread.lean new file mode 100644 index 0000000..e2cc794 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/HyperBentPartialSpread.lean @@ -0,0 +1,589 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.HyperBent + +/-! +# Hyper-bent partial-spread functions + +Carlet Proposition 25: the quadratic-extension partial-spread construction +and its power-trace proof of hyper-bentness. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +noncomputable local instance hyperBentPartialSpreadFieldFintype {r : ℕ} : + Fintype (BinaryGaloisField r) := + Fintype.ofFinite (BinaryGaloisField r) + +/-- In a quadratic binary extension, the kernel of the relative trace is +exactly the embedded middle field. -/ +theorem relativeTrace_eq_zero_iff_mem_quadraticSubfield {m : ℕ} (hm : 0 < m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (x : BinaryGaloisField (2 * m)) : + letI := iota.toAlgebra + Algebra.trace (BinaryGaloisField m) (BinaryGaloisField (2 * m)) x = 0 ↔ + x ∈ Set.range iota := by + letI := iota.toAlgebra + let tr := Algebra.trace (BinaryGaloisField m) (BinaryGaloisField (2 * m)) + let subfield := Algebra.linearMap (BinaryGaloisField m) + (BinaryGaloisField (2 * m)) + have hfinrank : Module.finrank (BinaryGaloisField m) + (BinaryGaloisField (2 * m)) = 2 := + quadraticTraceMiddle_finrank hm.ne' iota + have htwo : (2 : BinaryGaloisField m) = 0 := by + change ((2 : ℕ) : BinaryGaloisField m) = 0 + exact CharP.cast_eq_zero (BinaryGaloisField m) 2 + have hsubfieldKer : subfield.range ≤ tr.ker := by + rintro y ⟨z, rfl⟩ + rw [LinearMap.mem_ker] + change Algebra.trace (BinaryGaloisField m) (BinaryGaloisField (2 * m)) + (algebraMap (BinaryGaloisField m) (BinaryGaloisField (2 * m)) z) = 0 + rw [Algebra.trace_algebraMap, hfinrank] + simp [htwo] + have hsubfieldFinrank : Module.finrank (BinaryGaloisField m) subfield.range = 1 := by + rw [LinearMap.finrank_range_of_inj] + · exact Module.finrank_self (BinaryGaloisField m) + · intro y z hyz + exact iota.toRingHom.injective hyz + have hkerFinrank : Module.finrank (BinaryGaloisField m) tr.ker = 1 := by + have h := tr.finrank_range_add_finrank_ker + rw [LinearMap.range_eq_top.mpr (Algebra.trace_surjective + (BinaryGaloisField m) (BinaryGaloisField (2 * m))), hfinrank] at h + rw [finrank_top, Module.finrank_self] at h + omega + have heq : subfield.range = tr.ker := + Submodule.eq_of_le_of_finrank_eq hsubfieldKer + (hsubfieldFinrank.trans hkerFinrank.symm) + constructor + · intro hx + have hxker : x ∈ tr.ker := (LinearMap.mem_ker).2 hx + rw [← heq] at hxker + obtain ⟨z, hz⟩ := hxker + exact ⟨z, hz⟩ + · rintro ⟨z, rfl⟩ + change tr (algebraMap (BinaryGaloisField m) + (BinaryGaloisField (2 * m)) z) = 0 + rw [Algebra.trace_algebraMap, hfinrank] + simp [htwo] + +/-- The absolute trace of a product with an embedded middle-field element +factors through the relative trace. -/ +theorem absoluteTrace_mul_quadraticSubfield {m : ℕ} + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (x : BinaryGaloisField (2 * m)) (y : BinaryGaloisField m) : + letI := iota.toAlgebra + absoluteTrace (2 * m) (x * iota y) = + absoluteTrace m + (Algebra.trace (BinaryGaloisField m) (BinaryGaloisField (2 * m)) x * y) := by + letI := iota.toAlgebra + letI : IsScalarTower FABL.𝔽₂ (BinaryGaloisField m) + (BinaryGaloisField (2 * m)) := + IsScalarTower.of_algebraMap_eq' (Subsingleton.elim _ _) + change Algebra.trace FABL.𝔽₂ (BinaryGaloisField (2 * m)) + (x * algebraMap (BinaryGaloisField m) (BinaryGaloisField (2 * m)) y) = + Algebra.trace FABL.𝔽₂ (BinaryGaloisField m) + (Algebra.trace (BinaryGaloisField m) (BinaryGaloisField (2 * m)) x * y) + rw [← Algebra.trace_trace (R := FABL.𝔽₂) (S := BinaryGaloisField m) + (T := BinaryGaloisField (2 * m))] + congr 1 + rw [mul_comm x, ← Algebra.smul_def, map_smul] + simp [mul_comm] + +/-- Every nontrivial absolute-trace additive character has zero sum over a binary field. -/ +theorem sum_bitSignInt_absoluteTrace_mul_eq_zero {m : ℕ} + (t : BinaryGaloisField m) (ht : t ≠ 0) : + (∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace m (t * y))) = 0 := by + classical + obtain ⟨u, hu⟩ := exists_absoluteTrace_eq_one m + let y0 : BinaryGaloisField m := t⁻¹ * u + have hy0 : absoluteTrace m (t * y0) = 1 := by + change absoluteTrace m (t * (t⁻¹ * u)) = 1 + rw [← mul_assoc, mul_inv_cancel₀ ht, one_mul, hu] + let S : ℤ := ∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace m (t * y)) + have hshift : S = ∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace m (t * (y + y0))) := by + exact (Equiv.sum_comp (Equiv.addRight y0) + (fun y : BinaryGaloisField m ↦ + bitSignInt (absoluteTrace m (t * y)))).symm + have hneg : (∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace m (t * (y + y0)))) = -S := by + rw [show (∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace m (t * (y + y0)))) = + ∑ y : BinaryGaloisField m, + -bitSignInt (absoluteTrace m (t * y)) by + apply Finset.sum_congr rfl + intro y _hy + rw [mul_add, map_add, hy0, bitSignInt_add] + norm_num [bitSignInt]] + simp [S] + rw [hneg] at hshift + omega + +/-- A quadratic-extension trace character sums to the middle-field cardinality +when its coefficient lies in the middle field. -/ +theorem sum_quadraticSubfieldTraceCharacter_of_mem {m : ℕ} (hm : 0 < m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (x : BinaryGaloisField (2 * m)) (hx : x ∈ Set.range iota) : + (∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace (2 * m) (x * iota y))) = (2 ^ m : ℤ) := by + letI := iota.toAlgebra + have htrace : Algebra.trace (BinaryGaloisField m) + (BinaryGaloisField (2 * m)) x = 0 := + (relativeTrace_eq_zero_iff_mem_quadraticSubfield hm iota x).2 hx + simp_rw [absoluteTrace_mul_quadraticSubfield iota] + rw [htrace] + simp only [zero_mul, map_zero] + rw [show bitSignInt 0 = 1 by norm_num [bitSignInt], Finset.sum_const, + Finset.card_univ, ← Nat.card_eq_fintype_card, + GaloisField.card 2 m hm.ne'] + simp + +/-- A quadratic-extension trace character sums to zero when its coefficient +lies outside the middle field. -/ +theorem sum_quadraticSubfieldTraceCharacter_of_not_mem {m : ℕ} (hm : 0 < m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (x : BinaryGaloisField (2 * m)) (hx : x ∉ Set.range iota) : + (∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace (2 * m) (x * iota y))) = 0 := by + letI := iota.toAlgebra + have htrace : Algebra.trace (BinaryGaloisField m) + (BinaryGaloisField (2 * m)) x ≠ 0 := by + intro hzero + exact hx ((relativeTrace_eq_zero_iff_mem_quadraticSubfield hm iota x).1 hzero) + simp_rw [absoluteTrace_mul_quadraticSubfield iota] + exact sum_bitSignInt_absoluteTrace_mul_eq_zero _ htrace + +/-- Dillon's partial-spread function in quadratic-extension coordinates, with +field division defining the zero-denominator case. -/ +noncomputable def psapFunction {m : ℕ} (hm : 0 < m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (omega : BinaryGaloisField (2 * m)) (homega : omega ∉ Set.range iota) + (g : FieldBooleanFunction m) : FieldBooleanFunction (2 * m) := + fun x ↦ + let p := (quadraticSubfieldBasisEquiv hm iota omega homega).symm x + g (p.1 / p.2) + +/-- The partial-spread function evaluates to the quotient rule in its defining +quadratic-extension coordinates. -/ +@[simp] theorem psapFunction_coordinate {m : ℕ} (hm : 0 < m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (omega : BinaryGaloisField (2 * m)) (homega : omega ∉ Set.range iota) + (g : FieldBooleanFunction m) (y' y : BinaryGaloisField m) : + psapFunction hm iota omega homega g (iota y' + omega * iota y) = + g (y' / y) := by + unfold psapFunction + let coord := quadraticSubfieldBasisEquiv hm iota omega homega + change g ((coord.symm (coord (y', y))).1 / + (coord.symm (coord (y', y))).2) = g (y' / y) + rw [coord.symm_apply_apply] + +/-- The sign sum of a field Boolean function vanishes when its pullback to the +Boolean cube is balanced. -/ +theorem sum_bitSignInt_field_eq_zero_of_balanced {m : ℕ} + (theta : FABL.F₂Cube m ≃ₗ[FABL.𝔽₂] BinaryGaloisField m) + (g : FieldBooleanFunction m) (hg : IsBalanced (g ∘ theta)) : + (∑ z : BinaryGaloisField m, bitSignInt (g z)) = 0 := by + calc + (∑ z : BinaryGaloisField m, bitSignInt (g z)) = + ∑ x : FABL.F₂Cube m, bitSignInt (g (theta x)) := + (Equiv.sum_comp theta.toEquiv (fun z ↦ bitSignInt (g z))).symm + _ = walshTransform (g ∘ theta) 0 := by + symm + unfold walshTransform + apply Finset.sum_congr rfl + intro x _hx + rw [walshTerm_zero] + rfl + _ = 0 := (isBalanced_iff_walshTransform_zero_eq_zero _).1 hg + +/-- The source-normalized power-trace transform used in the hyper-bent criterion. -/ +noncomputable def fieldPowerTraceTransform {n : ℕ} + (f : FieldBooleanFunction n) (i : ℕ) (a : BinaryGaloisField n) : ℤ := + ∑ x : BinaryGaloisField n, + bitSignInt (f x + absoluteTrace n (a * x ^ i)) + +/-- The power-trace transform of a partial-spread function decomposes into +middle-field character sums. -/ +theorem fieldPowerTraceTransform_psap_eq {m i : ℕ} (hm : 0 < m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (omega : BinaryGaloisField (2 * m)) (homega : omega ∉ Set.range iota) + (g : FieldBooleanFunction m) (hg0 : g 0 = 0) + (hi : Nat.Coprime i (2 ^ (2 * m) - 1)) + (a : BinaryGaloisField (2 * m)) : + fieldPowerTraceTransform + (psapFunction hm iota omega homega g) i a = + (∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace (2 * m) (a * iota y))) + + ∑ z : BinaryGaloisField m, bitSignInt (g z) * + ((∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace (2 * m) + ((a * (iota z + omega) ^ i) * iota y))) - 1) := by + classical + let coord := quadraticSubfieldBasisEquiv hm iota omega homega + let term (y' y : BinaryGaloisField m) : ℤ := + bitSignInt (g (y' / y) + absoluteTrace (2 * m) + (a * (iota y' + omega * iota y) ^ i)) + have hcoordinate : + fieldPowerTraceTransform + (psapFunction hm iota omega homega g) i a = + ∑ y : BinaryGaloisField m, ∑ y' : BinaryGaloisField m, term y' y := by + rw [sum_comm] + symm + calc + (∑ y' : BinaryGaloisField m, ∑ y : BinaryGaloisField m, term y' y) = + ∑ p : BinaryGaloisField m × BinaryGaloisField m, + bitSignInt + (psapFunction hm iota omega homega g (coord p) + + absoluteTrace (2 * m) (a * (coord p) ^ i)) := by + rw [Fintype.sum_prod_type] + apply Finset.sum_congr rfl + intro y' _hy' + apply Finset.sum_congr rfl + intro y _hy + change term y' y = bitSignInt + (psapFunction hm iota omega homega g + (iota y' + omega * iota y) + + absoluteTrace (2 * m) + (a * (iota y' + omega * iota y) ^ i)) + rw [psapFunction_coordinate] + _ = fieldPowerTraceTransform + (psapFunction hm iota omega homega g) i a := + Equiv.sum_comp coord (fun x ↦ bitSignInt + (psapFunction hm iota omega homega g x + + absoluteTrace (2 * m) (a * x ^ i))) + let powerK : BinaryGaloisField m ≃ BinaryGaloisField m := + Equiv.ofBijective (fun y ↦ y ^ i) + (quadraticSubfield_powerMap_bijective hm iota hi) + have hzeroLine : (∑ y' : BinaryGaloisField m, term y' 0) = + ∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace (2 * m) (a * iota y)) := by + calc + (∑ y' : BinaryGaloisField m, term y' 0) = + ∑ y' : BinaryGaloisField m, + bitSignInt (absoluteTrace (2 * m) (a * iota (y' ^ i))) := by + apply Finset.sum_congr rfl + intro y' _hy' + simp only [term, div_zero, hg0, zero_add, map_zero, mul_zero, add_zero, + map_pow] + _ = ∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace (2 * m) (a * iota y)) := + Equiv.sum_comp powerK (fun y ↦ + bitSignInt (absoluteTrace (2 * m) (a * iota y))) + have hslope (y : BinaryGaloisField m) (hy : y ≠ 0) : + (∑ y' : BinaryGaloisField m, term y' y) = + ∑ z : BinaryGaloisField m, bitSignInt (g z) * + bitSignInt (absoluteTrace (2 * m) + ((a * (iota z + omega) ^ i) * iota (y ^ i))) := by + calc + (∑ y' : BinaryGaloisField m, term y' y) = + ∑ z : BinaryGaloisField m, term (z * y) y := + (Equiv.sum_comp (Equiv.mulRight₀ y hy) + (fun y' ↦ term y' y)).symm + _ = ∑ z : BinaryGaloisField m, bitSignInt (g z) * + bitSignInt (absoluteTrace (2 * m) + ((a * (iota z + omega) ^ i) * iota (y ^ i))) := by + apply Finset.sum_congr rfl + intro z _hz + unfold term + rw [mul_div_cancel_right₀ z hy, map_mul iota z y] + have hcoordinateProduct : + iota z * iota y + omega * iota y = + (iota z + omega) * iota y := by ring + rw [hcoordinateProduct, mul_pow, map_pow iota y i] + rw [show a * ((iota z + omega) ^ i * (iota y) ^ i) = + (a * (iota z + omega) ^ i) * (iota y) ^ i by ring] + rw [bitSignInt_add] + have hpowerErase (lambda : BinaryGaloisField (2 * m)) : + (∑ y ∈ Finset.univ.erase 0, + bitSignInt (absoluteTrace (2 * m) (lambda * iota (y ^ i)))) = + (∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace (2 * m) (lambda * iota y))) - 1 := by + have hfull : + (∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace (2 * m) (lambda * iota (y ^ i)))) = + ∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace (2 * m) (lambda * iota y)) := + Equiv.sum_comp powerK (fun y ↦ + bitSignInt (absoluteTrace (2 * m) (lambda * iota y))) + have hsplit := Finset.add_sum_erase Finset.univ + (fun y : BinaryGaloisField m ↦ + bitSignInt (absoluteTrace (2 * m) (lambda * iota (y ^ i)))) + (Finset.mem_univ 0) + have hzero : bitSignInt + (absoluteTrace (2 * m) (lambda * iota ((0 : BinaryGaloisField m) ^ i))) = 1 := by + have hiPos : 0 < i := by + have hmodulus : 1 < 2 ^ (2 * m) - 1 := by + have : 2 ≤ 2 * m := by omega + have hpower : 2 ^ 2 ≤ 2 ^ (2 * m) := + Nat.pow_le_pow_right (by omega) this + norm_num at hpower ⊢ + omega + by_contra hiZero + have : i = 0 := by omega + subst i + simp only [Nat.coprime_zero_left] at hi + omega + rw [zero_pow hiPos.ne', map_zero, mul_zero, map_zero] + norm_num [bitSignInt] + rw [hzero] at hsplit + rw [hfull] at hsplit + omega + rw [hcoordinate] + rw [← Finset.add_sum_erase Finset.univ + (fun y : BinaryGaloisField m ↦ ∑ y' : BinaryGaloisField m, term y' y) + (Finset.mem_univ 0), hzeroLine] + rw [add_right_inj] + rw [show (∑ y ∈ Finset.univ.erase 0, + ∑ y' : BinaryGaloisField m, term y' y) = + ∑ y ∈ Finset.univ.erase 0, ∑ z : BinaryGaloisField m, + bitSignInt (g z) * + bitSignInt (absoluteTrace (2 * m) + ((a * (iota z + omega) ^ i) * iota (y ^ i))) by + apply Finset.sum_congr rfl + intro y hy + rw [hslope y (Finset.mem_erase.mp hy).1]] + rw [Finset.sum_comm] + apply Finset.sum_congr rfl + intro z _hz + rw [← Finset.mul_sum, hpowerErase] + +/-- Every coprime power-trace transform of a partial-spread function has bent magnitude. -/ +theorem fieldPowerTraceTransform_psap_natAbs {m i : ℕ} (hm : 2 ≤ m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (omega : BinaryGaloisField (2 * m)) (homega : omega ∉ Set.range iota) + (theta : FABL.F₂Cube m ≃ₗ[FABL.𝔽₂] BinaryGaloisField m) + (g : FieldBooleanFunction m) (hg : IsBalanced (g ∘ theta)) (hg0 : g 0 = 0) + (hi : Nat.Coprime i (2 ^ (2 * m) - 1)) + (a : BinaryGaloisField (2 * m)) : + (fieldPowerTraceTransform + (psapFunction (by omega) iota omega homega g) i a).natAbs = 2 ^ m := by + classical + let charSum (lambda : BinaryGaloisField (2 * m)) : ℤ := + ∑ y : BinaryGaloisField m, + bitSignInt (absoluteTrace (2 * m) (lambda * iota y)) + have hsign : (∑ z : BinaryGaloisField m, bitSignInt (g z)) = 0 := + sum_bitSignInt_field_eq_zero_of_balanced theta g hg + have hformula := fieldPowerTraceTransform_psap_eq (by omega : 0 < m) + iota omega homega g hg0 hi a + have hsimplified : + fieldPowerTraceTransform + (psapFunction (by omega) iota omega homega g) i a = + charSum a + ∑ z : BinaryGaloisField m, + bitSignInt (g z) * charSum (a * (iota z + omega) ^ i) := by + rw [hformula] + change charSum a + _ = charSum a + _ + rw [add_right_inj] + calc + (∑ z : BinaryGaloisField m, bitSignInt (g z) * + (charSum (a * (iota z + omega) ^ i) - 1)) = + ∑ z : BinaryGaloisField m, + (bitSignInt (g z) * charSum (a * (iota z + omega) ^ i) - + bitSignInt (g z)) := by + apply Finset.sum_congr rfl + intro z _hz + ring + _ = (∑ z : BinaryGaloisField m, + bitSignInt (g z) * charSum (a * (iota z + omega) ^ i)) - + ∑ z : BinaryGaloisField m, bitSignInt (g z) := + by rw [Finset.sum_sub_distrib] + _ = ∑ z : BinaryGaloisField m, + bitSignInt (g z) * charSum (a * (iota z + omega) ^ i) := by + rw [hsign, sub_zero] + rw [hsimplified] + by_cases ha : a ∈ Set.range iota + · have hline : charSum a = (2 ^ m : ℤ) := by + simpa only [charSum] using + sum_quadraticSubfieldTraceCharacter_of_mem (by omega) iota a ha + obtain ⟨alpha, halpha⟩ := ha + by_cases ha0 : a = 0 + · subst a + have hcharZero : charSum 0 = (2 ^ m : ℤ) := by + apply sum_quadraticSubfieldTraceCharacter_of_mem (by omega) iota + exact ⟨0, by simp⟩ + have hmiddle : (∑ z : BinaryGaloisField m, + bitSignInt (g z) * charSum (0 * (iota z + omega) ^ i)) = 0 := by + simp only [zero_mul, hcharZero] + rw [← Finset.sum_mul, hsign, zero_mul] + rw [ha0, hcharZero, hmiddle, add_zero] + simp + · have halpha0 : alpha ≠ 0 := by + intro hzero + subst alpha + simp at halpha + exact ha0 halpha.symm + have hnotmem (z : BinaryGaloisField m) : + a * (iota z + omega) ^ i ∉ Set.range iota := by + rintro ⟨k, hk⟩ + have hpow : (iota z + omega) ^ i ∈ Set.range iota := by + refine ⟨alpha⁻¹ * k, ?_⟩ + calc + iota (alpha⁻¹ * k) = (iota alpha)⁻¹ * iota k := by + rw [map_mul, map_inv₀] + _ = a⁻¹ * (a * (iota z + omega) ^ i) := by + rw [halpha, hk] + _ = (iota z + omega) ^ i := by + rw [← mul_assoc, inv_mul_cancel₀ ha0, one_mul] + obtain ⟨r, hr⟩ := + (pow_mem_quadraticSubfield_iff (by omega) iota hi + (iota z + omega)).1 hpow + apply homega + refine ⟨r - z, ?_⟩ + rw [map_sub, hr] + ring + have hmiddle : (∑ z : BinaryGaloisField m, + bitSignInt (g z) * charSum (a * (iota z + omega) ^ i)) = 0 := by + apply Finset.sum_eq_zero + intro z _hz + rw [show charSum (a * (iota z + omega) ^ i) = 0 by + simpa only [charSum] using + sum_quadraticSubfieldTraceCharacter_of_not_mem (by omega) iota _ (hnotmem z)] + simp + rw [hline, hmiddle, add_zero] + simp + · have hline : charSum a = 0 := by + simpa only [charSum] using + sum_quadraticSubfieldTraceCharacter_of_not_mem (by omega) iota a ha + obtain ⟨z0, hz0, hunique⟩ := + existsUnique_subfield_power_intersection (by omega : 0 < m) + iota a omega ha homega hi + have hmem0 : a * (iota z0 + omega) ^ i ∈ Set.range iota := by + obtain ⟨k, hk⟩ := hz0 + exact ⟨k, hk.symm⟩ + have hchar0 : charSum (a * (iota z0 + omega) ^ i) = (2 ^ m : ℤ) := by + simpa only [charSum] using + sum_quadraticSubfieldTraceCharacter_of_mem (by omega) iota _ hmem0 + have hnotmem (z : BinaryGaloisField m) (hz : z ≠ z0) : + a * (iota z + omega) ^ i ∉ Set.range iota := by + intro hmem + apply hz + apply hunique z + obtain ⟨k, hk⟩ := hmem + exact ⟨k, hk.symm⟩ + have hmiddle : (∑ z : BinaryGaloisField m, + bitSignInt (g z) * charSum (a * (iota z + omega) ^ i)) = + bitSignInt (g z0) * (2 ^ m : ℤ) := by + rw [Finset.sum_eq_single z0] + · rw [hchar0] + · intro z _hz hzNe + rw [show charSum (a * (iota z + omega) ^ i) = 0 by + simpa only [charSum] using + sum_quadraticSubfieldTraceCharacter_of_not_mem (by omega) iota _ + (hnotmem z hzNe)] + simp + · exact fun hz0NotMem ↦ (hz0NotMem (Finset.mem_univ z0)).elim + rw [hline, hmiddle, zero_add, Int.natAbs_mul] + have hsignAbs : (bitSignInt (g z0)).natAbs = 1 := by + rw [bitSignInt_eq_if_one] + split <;> norm_num + rw [hsignAbs, one_mul] + simp + +/-- Constant bent magnitude for all coprime power-trace transforms implies hyper-bentness. -/ +theorem isHyperBent_of_forall_fieldPowerTraceTransform {n : ℕ} + (hn : 2 ≤ n) (hnEven : Even n) (f : FieldBooleanFunction n) + (htransform : ∀ i : ℕ, Nat.Coprime i (2 ^ n - 1) → + ∀ a : BinaryGaloisField n, + (fieldPowerTraceTransform f i a).natAbs = 2 ^ (n / 2)) : + IsHyperBent f := by + classical + refine ⟨hnEven, ?_⟩ + intro i hi a + let modulus := 2 ^ n - 1 + have hmodulus : 1 < modulus := by + have hpower : 2 ^ 2 ≤ 2 ^ n := + Nat.pow_le_pow_right (by omega) hn + dsimp only [modulus] + norm_num at hpower ⊢ + omega + let u : (ZMod modulus)ˣ := ZMod.unitOfCoprime i hi + let j : ℕ := ((u⁻¹ : (ZMod modulus)ˣ) : ZMod modulus).val + have hj : Nat.Coprime j modulus := + ZMod.val_coe_unit_coprime (u⁻¹) + have hmodulusNe : modulus ≠ 0 := by omega + letI : NeZero modulus := ⟨hmodulusNe⟩ + have hij : Nat.ModEq modulus (i * j) 1 := by + rw [← ZMod.natCast_eq_natCast_iff] + rw [Nat.cast_mul, Nat.cast_one] + rw [show (j : ZMod modulus) = ((u⁻¹ : (ZMod modulus)ˣ) : ZMod modulus) by + exact ZMod.natCast_zmod_val _] + exact Units.mul_inv u + have hiPos : 0 < i := by + by_contra hzero + have : i = 0 := by omega + subst i + simp only [Nat.coprime_zero_left] at hi + omega + have hjPos : 0 < j := by + by_contra hzero + have hjzero : j = 0 := by omega + have hmOne : modulus = 1 := + modulus.coprime_zero_left.mp (hjzero ▸ hj) + omega + have hinverse (x : BinaryGaloisField n) : (x ^ i) ^ j = x := by + by_cases hx : x = 0 + · subst x + simp [zero_pow hiPos.ne', zero_pow hjPos.ne'] + · rw [← pow_mul] + have hxModulus : x ^ modulus = 1 := by + have hxCard := FiniteField.pow_card_sub_one_eq_one x hx + rw [← Nat.card_eq_fintype_card, + GaloisField.card 2 n (by omega)] at hxCard + exact hxCard + rw [pow_eq_pow_of_modEq hij hxModulus, pow_one] + have hWalsh : fieldWalshTransform (fieldPowerReindex f i) a = + fieldPowerTraceTransform f j a := by + unfold fieldWalshTransform fieldPowerReindex fieldPowerTraceTransform + symm + calc + (∑ x : BinaryGaloisField n, + bitSignInt (f x + absoluteTrace n (a * x ^ j))) = + ∑ x : BinaryGaloisField n, + bitSignInt (f (x ^ i) + absoluteTrace n (a * (x ^ i) ^ j)) := + (Equiv.sum_comp (fieldPowerEquiv hn hi) + (fun x ↦ bitSignInt (f x + absoluteTrace n (a * x ^ j)))).symm + _ = ∑ x : BinaryGaloisField n, + bitSignInt (f (x ^ i) + absoluteTrace n (a * x)) := by + apply Finset.sum_congr rfl + intro x _hx + rw [hinverse] + rw [hWalsh] + exact htransform j (by simpa only [modulus] using hj) a + +/-- Carlet Proposition 25: every partial-spread function of the stated quotient +form is hyper-bent. -/ +theorem isHyperBent_psapFunction {m : ℕ} (hm : 2 ≤ m) + (iota : BinaryGaloisField m →ₐ[FABL.𝔽₂] + BinaryGaloisField (2 * m)) + (omega : BinaryGaloisField (2 * m)) (homega : omega ∉ Set.range iota) + (theta : FABL.F₂Cube m ≃ₗ[FABL.𝔽₂] BinaryGaloisField m) + (g : FieldBooleanFunction m) (hg : IsBalanced (g ∘ theta)) (hg0 : g 0 = 0) : + IsHyperBent (psapFunction (by omega) iota omega homega g) := by + apply isHyperBent_of_forall_fieldPowerTraceTransform + (n := 2 * m) (by omega) ⟨m, by omega⟩ + intro i hi a + have h := fieldPowerTraceTransform_psap_natAbs hm + iota omega homega theta g hg hg0 hi a + rw [show (2 * m) / 2 = m by omega] + exact h + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/HyperplaneRestriction.lean b/CryptBoolean/Carlet/Chapter06/HyperplaneRestriction.lean new file mode 100644 index 0000000..b552202 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/HyperplaneRestriction.lean @@ -0,0 +1,372 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.NestedBent +public import CryptBoolean.Carlet.Chapter06.PlateauedSupport + +/-! +# Hyperplane restrictions of bent functions + +Carlet Theorem 11: the complementary plateaued spectra of the two restrictions +to a linear hyperplane and its other coset characterize bentness. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The one-dimensional binary cube point with prescribed coordinate. -/ +def singletonF₂Cube (b : FABL.𝔽₂) : FABL.F₂Cube 1 := + fun _ ↦ b + +@[simp] theorem singletonF₂Cube_apply (b : FABL.𝔽₂) (i : Fin 1) : + singletonF₂Cube b i = b := + rfl + +private def singletonF₂CubeLinearEquiv : + FABL.𝔽₂ ≃ₗ[FABL.𝔽₂] FABL.F₂Cube 1 where + toFun := singletonF₂Cube + invFun x := x 0 + left_inv _ := rfl + right_inv x := by + funext i + fin_cases i + rfl + map_add' _ _ := rfl + map_smul' _ _ := by + funext i + fin_cases i + rfl + +private theorem sum_singletonF₂Cube + {R : Type*} [AddCommMonoid R] (g : FABL.F₂Cube 1 → R) : + (∑ y, g y) = g (singletonF₂Cube 0) + g (singletonF₂Cube 1) := by + calc + (∑ y, g y) = ∑ b : FABL.𝔽₂, g (singletonF₂Cube b) := by + exact (Fintype.sum_equiv singletonF₂CubeLinearEquiv.toEquiv + (fun b ↦ g (singletonF₂Cube b)) g (fun _ ↦ rfl)).symm + _ = g (singletonF₂Cube 0) + g (singletonF₂Cube 1) := by + have huniv : (Finset.univ : Finset FABL.𝔽₂) = {0, 1} := rfl + rw [huniv] + simp + +/-- Splitting the last coordinate expresses an ambient Walsh coefficient as +the signed sum of the Walsh coefficients of the two hyperplane restrictions. -/ +theorem walshTransform_append_singletonF₂Cube + (f : BooleanFunction (n + 1)) (a : FABL.F₂Cube n) (b : FABL.𝔽₂) : + walshTransform f (Fin.append a (singletonF₂Cube b)) = + walshTransform (firstBlockSlice f (singletonF₂Cube 0)) a + + bitSignInt b * + walshTransform (firstBlockSlice f (singletonF₂Cube 1)) a := by + classical + rw [walshTransform] + calc + ∑ z : FABL.F₂Cube (n + 1), + walshTerm f (Fin.append a (singletonF₂Cube b)) z = + ∑ p : FABL.F₂Cube n × FABL.F₂Cube 1, + walshTerm f (Fin.append a (singletonF₂Cube b)) + (Fin.append p.1 p.2) := by + exact (Fintype.sum_equiv (Fin.appendEquiv n 1) + (fun p ↦ walshTerm f (Fin.append a (singletonF₂Cube b)) + (Fin.append p.1 p.2)) + (fun z ↦ walshTerm f (Fin.append a (singletonF₂Cube b)) z) + (fun _ ↦ rfl)).symm + _ = ∑ y : FABL.F₂Cube 1, ∑ x : FABL.F₂Cube n, + bitSignInt (FABL.f₂DotProduct (singletonF₂Cube b) y) * + walshTerm (firstBlockSlice f y) a x := by + rw [Fintype.sum_prod_type, Finset.sum_comm] + apply Finset.sum_congr rfl + intro y _hy + apply Finset.sum_congr rfl + intro x _hx + rw [walshTerm, walshTerm, FABL.f₂DotProduct_append] + rw [show + f (Fin.append x y) + + (FABL.f₂DotProduct a x + + FABL.f₂DotProduct (singletonF₂Cube b) y) = + FABL.f₂DotProduct (singletonF₂Cube b) y + + (firstBlockSlice f y x + FABL.f₂DotProduct a x) by + simp only [firstBlockSlice] + abel, + bitSignInt_add] + _ = ∑ y : FABL.F₂Cube 1, + bitSignInt (FABL.f₂DotProduct (singletonF₂Cube b) y) * + walshTransform (firstBlockSlice f y) a := by + apply Finset.sum_congr rfl + intro y _hy + rw [walshTransform, Finset.mul_sum] + _ = walshTransform (firstBlockSlice f (singletonF₂Cube 0)) a + + bitSignInt b * + walshTransform (firstBlockSlice f (singletonF₂Cube 1)) a := by + rw [sum_singletonF₂Cube] + simp [singletonF₂Cube, FABL.f₂DotProduct, dotProduct, + bitSignInt_eq_if_one] + +/-- The two coordinate restrictions determined by a linear change of +variables represent a linear hyperplane and its complementary affine coset. -/ +def linearHyperplaneRestriction + (f : BooleanFunction (n + 1)) + (L : FABL.F₂Cube (n + 1) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube (n + 1)) + (b : FABL.𝔽₂) : BooleanFunction n := + firstBlockSlice (f ∘ L) (singletonF₂Cube b) + +/-- The two hyperplane restrictions have complementary spectra of amplitude +`2^((n+1)/2)` when at every frequency exactly one coefficient is nonzero and +that coefficient has this magnitude. -/ +def HasComplementaryHyperplaneRestrictionSpectra + (f : BooleanFunction (n + 1)) + (L : FABL.F₂Cube (n + 1) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube (n + 1)) : Prop := + ∀ a : FABL.F₂Cube n, + (walshTransform (linearHyperplaneRestriction f L 0) a = 0 ∧ + (walshTransform (linearHyperplaneRestriction f L 1) a).natAbs = + 2 ^ ((n + 1) / 2)) ∨ + ((walshTransform (linearHyperplaneRestriction f L 0) a).natAbs = + 2 ^ ((n + 1) / 2) ∧ + walshTransform (linearHyperplaneRestriction f L 1) a = 0) + +/-- Carlet Theorem 11 for a fixed linear hyperplane: in even ambient +dimension at least four, bentness is equivalent to complementary restriction +spectra with values `0` and `±2^((n+1)/2)`. -/ +theorem isBent_iff_hasComplementaryHyperplaneRestrictionSpectra + (f : BooleanFunction (n + 1)) + (L : FABL.F₂Cube (n + 1) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube (n + 1)) + (_hnEven : Even (n + 1)) (_hnFour : 4 ≤ n + 1) : + IsBent f ↔ HasComplementaryHyperplaneRestrictionSpectra f L := by + let g : BooleanFunction (n + 1) := f ∘ L + have hbentReindex : IsBent g ↔ IsBent f := by + simpa [g] using isBent_comp_affineEquiv_iff f L.toAffineEquiv + constructor + · intro hf a + have hg : IsBent g := hbentReindex.mpr hf + have hzero := walshTransform_append_singletonF₂Cube g a 0 + have hone := walshTransform_append_singletonF₂Cube g a 1 + simp [bitSignInt_eq_if_one] at hzero hone + have hzeroMagnitude := + natAbs_walshTransform_eq_two_pow_half_of_isBent g hg + (Fin.append a (singletonF₂Cube 0)) + have honeMagnitude := + natAbs_walshTransform_eq_two_pow_half_of_isBent g hg + (Fin.append a (singletonF₂Cube 1)) + have hpowCast : + ((2 ^ ((n + 1) / 2) : ℕ) : ℤ) = + (2 : ℤ) ^ ((n + 1) / 2) := by + norm_num + rcases Int.natAbs_eq_iff.mp hzeroMagnitude with hzeroPos | hzeroNeg + · rcases Int.natAbs_eq_iff.mp honeMagnitude with honePos | honeNeg + · right + rw [hpowCast] at hzeroPos honePos + clear hzeroMagnitude honeMagnitude + constructor + · rw [show walshTransform (linearHyperplaneRestriction f L 0) a = + (2 ^ ((n + 1) / 2) : ℤ) by + change walshTransform (firstBlockSlice g (singletonF₂Cube 0)) a = _ + omega] + simp + · change walshTransform (firstBlockSlice g (singletonF₂Cube 1)) a = 0 + omega + · left + rw [hpowCast] at hzeroPos honeNeg + clear hzeroMagnitude honeMagnitude + constructor + · change walshTransform (firstBlockSlice g (singletonF₂Cube 0)) a = 0 + omega + · rw [show walshTransform (linearHyperplaneRestriction f L 1) a = + (2 ^ ((n + 1) / 2) : ℤ) by + change walshTransform (firstBlockSlice g (singletonF₂Cube 1)) a = _ + omega] + simp + · rcases Int.natAbs_eq_iff.mp honeMagnitude with honePos | honeNeg + · left + rw [hpowCast] at hzeroNeg honePos + clear hzeroMagnitude honeMagnitude + constructor + · change walshTransform (firstBlockSlice g (singletonF₂Cube 0)) a = 0 + omega + · rw [show walshTransform (linearHyperplaneRestriction f L 1) a = + -((2 ^ ((n + 1) / 2) : ℤ)) by + change walshTransform (firstBlockSlice g (singletonF₂Cube 1)) a = _ + omega] + simp + · right + rw [hpowCast] at hzeroNeg honeNeg + clear hzeroMagnitude honeMagnitude + constructor + · rw [show walshTransform (linearHyperplaneRestriction f L 0) a = + -((2 ^ ((n + 1) / 2) : ℤ)) by + change walshTransform (firstBlockSlice g (singletonF₂Cube 0)) a = _ + omega] + simp + · change walshTransform (firstBlockSlice g (singletonF₂Cube 1)) a = 0 + omega + · intro hrestrictions + apply hbentReindex.mp + apply (isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half g).2 + intro u + let p := (Fin.appendEquiv n 1).symm u + let a : FABL.F₂Cube n := p.1 + let b : FABL.𝔽₂ := p.2 0 + have htail : p.2 = singletonF₂Cube b := by + funext i + fin_cases i + rfl + have hu : Fin.append a (singletonF₂Cube b) = u := by + rw [← htail] + exact (Fin.appendEquiv n 1).apply_symm_apply u + rw [← hu, walshTransform_append_singletonF₂Cube] + rcases hrestrictions a with hright | hleft + · change + walshTransform (firstBlockSlice g (singletonF₂Cube 0)) a = 0 ∧ + (walshTransform (firstBlockSlice g (singletonF₂Cube 1)) a).natAbs = + 2 ^ ((n + 1) / 2) at hright + rw [hright.1, zero_add, Int.natAbs_mul, hright.2] + rw [bitSignInt_eq_if_one] + split <;> simp + · change + (walshTransform (firstBlockSlice g (singletonF₂Cube 0)) a).natAbs = + 2 ^ ((n + 1) / 2) ∧ + walshTransform (firstBlockSlice g (singletonF₂Cube 1)) a = 0 at hleft + rw [hleft.2, mul_zero, add_zero, hleft.1] + +/-- The Boolean function obtained by placing `h₀` and `h₁` on the two +cosets of the standard coordinate hyperplane. -/ +def hyperplaneExtension + (h₀ h₁ : BooleanFunction n) : BooleanFunction (n + 1) := + fun z ↦ + let p := (Fin.appendEquiv n 1).symm z + if p.2 0 = 0 then h₀ p.1 else h₁ p.1 + +@[simp] theorem hyperplaneExtension_append_singletonF₂Cube + (h₀ h₁ : BooleanFunction n) (x : FABL.F₂Cube n) (b : FABL.𝔽₂) : + hyperplaneExtension h₀ h₁ (Fin.append x (singletonF₂Cube b)) = + if b = 0 then h₀ x else h₁ x := by + simp [hyperplaneExtension, singletonF₂Cube] + +@[simp] theorem linearHyperplaneRestriction_hyperplaneExtension_refl + (h₀ h₁ : BooleanFunction n) (b : FABL.𝔽₂) : + linearHyperplaneRestriction (hyperplaneExtension h₀ h₁) + (LinearEquiv.refl FABL.𝔽₂ _) b = + if b = 0 then h₀ else h₁ := by + funext x + by_cases hb : b = 0 <;> + simp [linearHyperplaneRestriction, firstBlockSlice, hb] + +/-- Complementary Walsh spectra of amplitude `2^((n+1)/2)` give a bent +extension across the standard hyperplane. -/ +theorem isBent_hyperplaneExtension_of_complementaryWalshSpectra + (h₀ h₁ : BooleanFunction n) + (hnEven : Even (n + 1)) (hnFour : 4 ≤ n + 1) + (hspectra : ∀ a : FABL.F₂Cube n, + (walshTransform h₀ a = 0 ∧ + (walshTransform h₁ a).natAbs = 2 ^ ((n + 1) / 2)) ∨ + ((walshTransform h₀ a).natAbs = 2 ^ ((n + 1) / 2) ∧ + walshTransform h₁ a = 0)) : + IsBent (hyperplaneExtension h₀ h₁) := by + apply (isBent_iff_hasComplementaryHyperplaneRestrictionSpectra + (hyperplaneExtension h₀ h₁) (LinearEquiv.refl FABL.𝔽₂ _) + hnEven hnFour).2 + intro a + simpa using hspectra a + +/-- In Theorem 11, a bent function has the complementary restriction property +for every linear hyperplane coordinate system. -/ +theorem isBent_iff_forall_hasComplementaryHyperplaneRestrictionSpectra + (f : BooleanFunction (n + 1)) + (hnEven : Even (n + 1)) (hnFour : 4 ≤ n + 1) : + IsBent f ↔ + ∀ L : FABL.F₂Cube (n + 1) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube (n + 1), + HasComplementaryHyperplaneRestrictionSpectra f L := by + constructor + · intro hf L + exact (isBent_iff_hasComplementaryHyperplaneRestrictionSpectra + f L hnEven hnFour).mp hf + · intro h + exact (isBent_iff_hasComplementaryHyperplaneRestrictionSpectra + f (LinearEquiv.refl FABL.𝔽₂ _) hnEven hnFour).mpr + (h (LinearEquiv.refl FABL.𝔽₂ _)) + +/-- In Theorem 11, it is enough that one linear hyperplane coordinate system +has complementary restriction spectra. -/ +theorem isBent_iff_exists_hasComplementaryHyperplaneRestrictionSpectra + (f : BooleanFunction (n + 1)) + (hnEven : Even (n + 1)) (hnFour : 4 ≤ n + 1) : + IsBent f ↔ + ∃ L : FABL.F₂Cube (n + 1) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube (n + 1), + HasComplementaryHyperplaneRestrictionSpectra f L := by + constructor + · intro hf + refine ⟨LinearEquiv.refl FABL.𝔽₂ _, ?_⟩ + exact (isBent_iff_hasComplementaryHyperplaneRestrictionSpectra + f (LinearEquiv.refl FABL.𝔽₂ _) hnEven hnFour).mp hf + · rintro ⟨L, hL⟩ + exact (isBent_iff_hasComplementaryHyperplaneRestrictionSpectra + f L hnEven hnFour).mpr hL + +/-- Each affine-hyperplane restriction of a bent function in even ambient +dimension at least four is plateaued with the optimal odd-dimensional +amplitude. -/ +theorem hasPlateauedWalshAmplitude_linearHyperplaneRestriction_of_isBent + (f : BooleanFunction (n + 1)) + (L : FABL.F₂Cube (n + 1) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube (n + 1)) + (hf : IsBent f) (hnEven : Even (n + 1)) (hnFour : 4 ≤ n + 1) + (b : FABL.𝔽₂) : + HasPlateauedWalshAmplitude (linearHyperplaneRestriction f L b) + (2 ^ ((n + 1) / 2)) := by + refine ⟨by positivity, fun a ↦ ?_⟩ + have hspectra := + (isBent_iff_hasComplementaryHyperplaneRestrictionSpectra + f L hnEven hnFour).mp hf a + fin_cases b + · exact hspectra.elim (fun h ↦ Or.inl h.1) (fun h ↦ Or.inr h.1) + · exact hspectra.elim (fun h ↦ Or.inr h.2) (fun h ↦ Or.inl h.2) + +/-- Every affine-hyperplane restriction of a bent function is plateaued. -/ +theorem isPlateaued_linearHyperplaneRestriction_of_isBent + (f : BooleanFunction (n + 1)) + (L : FABL.F₂Cube (n + 1) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube (n + 1)) + (hf : IsBent f) (hnEven : Even (n + 1)) (hnFour : 4 ≤ n + 1) + (b : FABL.𝔽₂) : + IsPlateaued (linearHyperplaneRestriction f L b) := + ⟨2 ^ ((n + 1) / 2), + hasPlateauedWalshAmplitude_linearHyperplaneRestriction_of_isBent + f L hf hnEven hnFour b⟩ + +/-- The affine-hyperplane restrictions of an even-dimensional bent function +have optimal odd-dimensional nonlinearity. -/ +theorem nonlinearity_linearHyperplaneRestriction_of_isBent + (f : BooleanFunction (n + 1)) + (L : FABL.F₂Cube (n + 1) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube (n + 1)) + (hf : IsBent f) (hnEven : Even (n + 1)) (hnFour : 4 ≤ n + 1) + (b : FABL.𝔽₂) : + nonlinearity (linearHyperplaneRestriction f L b) = + 2 ^ (n - 1) - 2 ^ ((n - 1) / 2) := by + let h := linearHyperplaneRestriction f L b + have hamplitude := + hasPlateauedWalshAmplitude_linearHyperplaneRestriction_of_isBent + f L hf hnEven hnFour b + have hrelation := two_mul_nonlinearity_add_maxWalshMagnitude h + rw [maxWalshMagnitude_eq_of_hasPlateauedWalshAmplitude h + (2 ^ ((n + 1) / 2)) hamplitude] at hrelation + rcases hnEven with ⟨k, hk⟩ + have hhalf : (n + 1) / 2 = (n - 1) / 2 + 1 := by + omega + have hdim : n = (n - 1) + 1 := by omega + have hpowHalf : + 2 ^ ((n + 1) / 2) = 2 * 2 ^ ((n - 1) / 2) := by + rw [hhalf, pow_succ] + omega + have hpowDimension : 2 ^ n = 2 * 2 ^ (n - 1) := by + conv_lhs => rw [hdim, pow_succ] + omega + rw [hpowHalf, hpowDimension] at hrelation + change nonlinearity h = 2 ^ (n - 1) - 2 ^ ((n - 1) / 2) + omega + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/IndirectSum.lean b/CryptBoolean/Carlet/Chapter06/IndirectSum.lean new file mode 100644 index 0000000..821044b --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/IndirectSum.lean @@ -0,0 +1,212 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.NestedBent +public import CryptBoolean.Carlet.Chapter06.DualAffine + +/-! +# The indirect sum of bent functions + +Carlet Section 6.4.2: the four-function indirect-sum construction and its dual. +-/ + +open scoped BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n m : ℕ} + +/-- The indirect sum of two pairs of Boolean functions on disjoint blocks. -/ +def indirectSum + (f₁ f₂ : BooleanFunction n) (g₁ g₂ : BooleanFunction m) : + BooleanFunction (n + m) := + fun z ↦ + let p := (Fin.appendEquiv n m).symm z + f₁ p.1 + g₁ p.2 + (f₁ p.1 + f₂ p.1) * (g₁ p.2 + g₂ p.2) + +@[simp] theorem indirectSum_append + (f₁ f₂ : BooleanFunction n) (g₁ g₂ : BooleanFunction m) + (x : FABL.F₂Cube n) (y : FABL.F₂Cube m) : + indirectSum f₁ f₂ g₁ g₂ (Fin.append x y) = + f₁ x + g₁ y + (f₁ x + f₂ x) * (g₁ y + g₂ y) := by + simp [indirectSum] + +private theorem xor_cancel_left (a b c : FABL.𝔽₂) : + a + c + (a + b) = b + c := by + fin_cases a <;> fin_cases b <;> fin_cases c <;> decide + +private theorem bentDual_add_constant + (f : BooleanFunction n) (hf : IsBent f) (c : FABL.𝔽₂) + (a : FABL.F₂Cube n) : + bentDual (f + FABL.affineFunction c 0) a = bentDual f a + c := by + have hg : IsBent (f + FABL.affineFunction c 0) := + (isBent_add_affineFunction_iff f c 0).2 hf + have hdualG := + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + (f + FABL.affineFunction c 0) hg a + have hshift := walshTransform_add_affineFunction f c 0 a + have hdualF := + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf a + apply bitSignInt_injective + apply mul_left_cancel₀ (by positivity : (2 ^ (n / 2) : ℤ) ≠ 0) + calc + (2 ^ (n / 2) : ℤ) * + bitSignInt (bentDual (f + FABL.affineFunction c 0) a) = + walshTransform (f + FABL.affineFunction c 0) a := hdualG.symm + _ = bitSignInt c * walshTransform f (a + 0) := hshift + _ = bitSignInt c * + ((2 ^ (n / 2) : ℤ) * bitSignInt (bentDual f a)) := by + rw [add_zero, hdualF] + _ = (2 ^ (n / 2) : ℤ) * + (bitSignInt (bentDual f a) * bitSignInt c) := by ring + _ = (2 ^ (n / 2) : ℤ) * bitSignInt (bentDual f a + c) := by + rw [bitSignInt_add] + +private theorem firstBlockSlice_indirectSum + (f₁ f₂ : BooleanFunction n) (g₁ g₂ : BooleanFunction m) + (y : FABL.F₂Cube m) : + firstBlockSlice (indirectSum f₁ f₂ g₁ g₂) y = + if g₁ y + g₂ y = 0 then f₁ + FABL.affineFunction (g₁ y) 0 + else f₂ + FABL.affineFunction (g₁ y) 0 := by + funext x + by_cases h : g₁ y + g₂ y = 0 + · rw [if_pos h] + simp [firstBlockSlice, h, FABL.affineFunction, FABL.f₂DotProduct] + · have hone : g₁ y + g₂ y = 1 := Fin.eq_one_of_ne_zero _ h + rw [if_neg h] + simp only [firstBlockSlice, indirectSum_append, Pi.add_apply, + FABL.affineFunction, FABL.f₂DotProduct, zero_dotProduct] + rw [hone, mul_one, add_zero] + exact xor_cancel_left (f₁ x) (f₂ x) (g₁ y) + +private theorem dualSliceFunction_indirectSum + (f₁ f₂ : BooleanFunction n) (g₁ g₂ : BooleanFunction m) + (hf₁ : IsBent f₁) (hf₂ : IsBent f₂) + (s : FABL.F₂Cube n) : + dualSliceFunction (indirectSum f₁ f₂ g₁ g₂) s = + fun y ↦ bentDual f₁ s + g₁ y + + (bentDual f₁ s + bentDual f₂ s) * (g₁ y + g₂ y) := by + funext y + rw [dualSliceFunction, firstBlockSlice_indirectSum] + by_cases h : g₁ y + g₂ y = 0 + · rw [if_pos h, bentDual_add_constant f₁ hf₁] + simp [h] + · have hone : g₁ y + g₂ y = 1 := Fin.eq_one_of_ne_zero _ h + rw [if_neg h, bentDual_add_constant f₂ hf₂] + rw [hone] + simpa [add_comm, add_left_comm, add_assoc] using + (xor_cancel_left (bentDual f₁ s) (bentDual f₂ s) (g₁ y)).symm + +private theorem isBent_dualSliceFunction_indirectSum + (f₁ f₂ : BooleanFunction n) (g₁ g₂ : BooleanFunction m) + (hf₁ : IsBent f₁) (hf₂ : IsBent f₂) + (hg₁ : IsBent g₁) (hg₂ : IsBent g₂) + (s : FABL.F₂Cube n) : + IsBent (dualSliceFunction (indirectSum f₁ f₂ g₁ g₂) s) := by + rw [dualSliceFunction_indirectSum f₁ f₂ g₁ g₂ hf₁ hf₂ s] + by_cases h : bentDual f₁ s + bentDual f₂ s = 0 + · have heq : + (fun y ↦ bentDual f₁ s + g₁ y + + (bentDual f₁ s + bentDual f₂ s) * (g₁ y + g₂ y)) = + g₁ + FABL.affineFunction (bentDual f₁ s) 0 := by + funext y + simp [h, FABL.affineFunction, FABL.f₂DotProduct] + ring + rw [heq] + exact (isBent_add_affineFunction_iff g₁ (bentDual f₁ s) 0).2 hg₁ + · have hone : bentDual f₁ s + bentDual f₂ s = 1 := + Fin.eq_one_of_ne_zero _ h + have heq : + (fun y ↦ bentDual f₁ s + g₁ y + + (bentDual f₁ s + bentDual f₂ s) * (g₁ y + g₂ y)) = + g₂ + FABL.affineFunction (bentDual f₁ s) 0 := by + funext y + simp only [Pi.add_apply, FABL.affineFunction, FABL.f₂DotProduct, + zero_dotProduct, add_zero] + rw [hone, one_mul] + simpa [add_comm, add_left_comm, add_assoc] using + xor_cancel_left (g₁ y) (g₂ y) (bentDual f₁ s) + rw [heq] + exact (isBent_add_affineFunction_iff g₂ (bentDual f₁ s) 0).2 hg₂ + +/-- The indirect sum of four bent functions is bent. -/ +theorem isBent_indirectSum + (f₁ f₂ : BooleanFunction n) (g₁ g₂ : BooleanFunction m) + (hn : Even n) (hm : Even m) (_hnPositive : 0 < n) (_hmPositive : 0 < m) + (hf₁ : IsBent f₁) (hf₂ : IsBent f₂) + (hg₁ : IsBent g₁) (hg₂ : IsBent g₂) : + IsBent (indirectSum f₁ f₂ g₁ g₂) := by + have hslices : + ∀ y, IsBent (firstBlockSlice (indirectSum f₁ f₂ g₁ g₂) y) := by + intro y + rw [firstBlockSlice_indirectSum] + split + · exact (isBent_add_affineFunction_iff f₁ (g₁ y) 0).2 hf₁ + · exact (isBent_add_affineFunction_iff f₂ (g₁ y) 0).2 hf₂ + apply (isBent_iff_forall_isBent_dualSliceFunction + (indirectSum f₁ f₂ g₁ g₂) hn hm hslices).2 + exact isBent_dualSliceFunction_indirectSum + f₁ f₂ g₁ g₂ hf₁ hf₂ hg₁ hg₂ + +/-- The dual of an indirect sum is the indirect sum of the four duals. -/ +theorem bentDual_indirectSum_append + (f₁ f₂ : BooleanFunction n) (g₁ g₂ : BooleanFunction m) + (hn : Even n) (hm : Even m) (_hnPositive : 0 < n) (_hmPositive : 0 < m) + (hf₁ : IsBent f₁) (hf₂ : IsBent f₂) + (hg₁ : IsBent g₁) (hg₂ : IsBent g₂) + (s : FABL.F₂Cube n) (t : FABL.F₂Cube m) : + bentDual (indirectSum f₁ f₂ g₁ g₂) (Fin.append s t) = + indirectSum (bentDual f₁) (bentDual f₂) (bentDual g₁) (bentDual g₂) + (Fin.append s t) := by + let h := indirectSum f₁ f₂ g₁ g₂ + have hslices : ∀ y, IsBent (firstBlockSlice h y) := by + intro y + dsimp [h] + rw [firstBlockSlice_indirectSum] + split + · exact (isBent_add_affineFunction_iff f₁ (g₁ y) 0).2 hf₁ + · exact (isBent_add_affineFunction_iff f₂ (g₁ y) 0).2 hf₂ + have hdualSlices : ∀ u, IsBent (dualSliceFunction h u) := by + intro u + exact isBent_dualSliceFunction_indirectSum + f₁ f₂ g₁ g₂ hf₁ hf₂ hg₁ hg₂ u + rw [bentDual_append_eq_bentDual_dualSliceFunction + h hn hm hslices hdualSlices s t] + rw [indirectSum_append] + dsimp [h] + rw [dualSliceFunction_indirectSum f₁ f₂ g₁ g₂ hf₁ hf₂ s] + by_cases hd : bentDual f₁ s + bentDual f₂ s = 0 + · have hfunction : + (fun y ↦ bentDual f₁ s + g₁ y + + (bentDual f₁ s + bentDual f₂ s) * (g₁ y + g₂ y)) = + g₁ + FABL.affineFunction (bentDual f₁ s) 0 := by + funext y + simp [hd, FABL.affineFunction, FABL.f₂DotProduct] + ring + rw [hfunction, bentDual_add_constant g₁ hg₁] + simp [hd] + abel + · have hdOne : bentDual f₁ s + bentDual f₂ s = 1 := + Fin.eq_one_of_ne_zero _ hd + have hfunction : + (fun y ↦ bentDual f₁ s + g₁ y + + (bentDual f₁ s + bentDual f₂ s) * (g₁ y + g₂ y)) = + g₂ + FABL.affineFunction (bentDual f₁ s) 0 := by + funext y + simp only [Pi.add_apply, FABL.affineFunction, FABL.f₂DotProduct, + zero_dotProduct, add_zero] + rw [hdOne, one_mul] + simpa [add_comm, add_left_comm, add_assoc] using + xor_cancel_left (g₁ y) (g₂ y) (bentDual f₁ s) + rw [hfunction, bentDual_add_constant g₂ hg₂] + rw [hdOne] + simpa [add_comm, add_left_comm, add_assoc] using + (xor_cancel_left (bentDual g₁ t) (bentDual g₂ t) (bentDual f₁ s)).symm + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/Kerdock.lean b/CryptBoolean/Carlet/Chapter06/Kerdock.lean new file mode 100644 index 0000000..6646d1b --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/Kerdock.lean @@ -0,0 +1,215 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter04.ReedMullerCosetDistance +public import CryptBoolean.Carlet.Chapter06.Bentness + +/-! +# Carlet Chapter 6 Kerdock-code parameters + +The code parameters obtained from a finite family of quadratic representatives +whose pairwise sums are bent. The finite-field construction of such a family +is a separate existence problem. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The source conditions on a finite family of Kerdock coset representatives: +zero is represented, every nonzero representative is quadratic, distinct +representatives have bent sum, and the family has `2^(n-1)` members. -/ +def IsKerdockRepresentativeFamily + (F : Finset (BooleanFunction n)) : Prop := + (0 : BooleanFunction n) ∈ F ∧ + (∀ f ∈ F, f ≠ 0 → FABL.functionAlgebraicDegree f = 2) ∧ + (∀ ⦃f⦄, f ∈ F → ∀ ⦃g⦄, g ∈ F → f ≠ g → IsBent (f + g)) ∧ + F.card = 2 ^ (n - 1) + +/-- The union of first-order Reed--Muller cosets determined by a finite +Kerdock representative family. -/ +noncomputable def kerdockCodeOfRepresentatives + (F : Finset (BooleanFunction n)) : Finset (BooleanFunction n) := + firstOrderCosetUnion F + +/-- Every representative in a Kerdock family has algebraic degree at most +two, including the zero representative. -/ +theorem functionAlgebraicDegree_le_two_of_mem_kerdockRepresentatives + {F : Finset (BooleanFunction n)} + (hF : IsKerdockRepresentativeFamily F) + {f : BooleanFunction n} (hf : f ∈ F) : + FABL.functionAlgebraicDegree f ≤ 2 := by + by_cases hfZero : f = 0 + · subst f + simp + · exact (hF.2.1 f hf hfZero).le + +/-- The Kerdock coset union contains the first-order Reed--Muller code. -/ +theorem reedMuller_one_subset_kerdockCodeOfRepresentatives + {F : Finset (BooleanFunction n)} + (hF : IsKerdockRepresentativeFamily F) : + ∀ ⦃c : BooleanFunction n⦄, c ∈ reedMuller 1 n → + c ∈ kerdockCodeOfRepresentatives F := by + intro c hc + rw [kerdockCodeOfRepresentatives, mem_firstOrderCosetUnion_iff] + refine ⟨0, hF.1, ?_⟩ + simpa using hc + +/-- The Kerdock coset union is contained in the second-order Reed--Muller +code. -/ +theorem kerdockCodeOfRepresentatives_subset_reedMuller_two + {F : Finset (BooleanFunction n)} + (hF : IsKerdockRepresentativeFamily F) : + ∀ ⦃c : BooleanFunction n⦄, + c ∈ kerdockCodeOfRepresentatives F → c ∈ reedMuller 2 n := by + intro c hc + rw [kerdockCodeOfRepresentatives, mem_firstOrderCosetUnion_iff] at hc + obtain ⟨f, hf, hcf⟩ := hc + have hcfTwo : c + f ∈ reedMuller 2 n := + reedMuller_mono (n := n) (by omega) hcf + have hfTwo : f ∈ reedMuller 2 n := + functionAlgebraicDegree_le_two_of_mem_kerdockRepresentatives hF hf + have hsum := (reedMuller 2 n).add_mem hcfTwo hfTwo + have hcancel : (c + f) + f = c := by + funext x + exact CharTwo.add_cancel_right _ _ + rwa [hcancel] at hsum + +/-- Distinct representatives in a Kerdock family have the exact bent +nonlinearity value. -/ +theorem nonlinearity_add_eq_kerdockDistance_of_mem + {F : Finset (BooleanFunction n)} + (hF : IsKerdockRepresentativeFamily F) (hn : 2 ≤ n) + {f g : BooleanFunction n} (hf : f ∈ F) (hg : g ∈ F) + (hfg : f ≠ g) : + nonlinearity (f + g) = + 2 ^ (n - 1) - 2 ^ (n / 2 - 1) := by + exact nonlinearity_eq_two_pow_sub_two_pow_half_of_isBent + (f + g) (hF.2.2.1 hf hg hfg) hn + +/-- In dimension at least two, bent pairwise sums force distinct Kerdock +representatives to determine distinct first-order Reed--Muller cosets. -/ +theorem hasDistinctFirstOrderCosets_of_isKerdockRepresentativeFamily + {F : Finset (BooleanFunction n)} + (hF : IsKerdockRepresentativeFamily F) + (hnEven : Even n) (hn : 2 ≤ n) : + HasDistinctFirstOrderCosets F := by + intro f hf g hg hfg hmem + obtain ⟨b, a, haffine⟩ := + FABL.exists_affineFunction_of_functionAlgebraicDegree_le_one + (f + g) hmem + have hzero : nonlinearity (f + g) = 0 := by + rw [haffine, nonlinearity_affineFunction] + have hexact := + nonlinearity_add_eq_kerdockDistance_of_mem hF hn hf hg hfg + have hexponents : n / 2 - 1 < n - 1 := by + rcases hnEven with ⟨k, rfl⟩ + omega + have hpowers : 2 ^ (n / 2 - 1) < 2 ^ (n - 1) := + Nat.pow_lt_pow_right (by omega) hexponents + rw [hzero] at hexact + omega + +/-- A Kerdock representative family in dimension at least two contains two +distinct representatives. -/ +theorem kerdockRepresentativeFamily_offDiag_nonempty + {F : Finset (BooleanFunction n)} + (hF : IsKerdockRepresentativeFamily F) (hn : 2 ≤ n) : + F.offDiag.Nonempty := by + have htwo : 2 ≤ F.card := by + rw [hF.2.2.2] + have hexponent : 1 ≤ n - 1 := by omega + simpa using + (Nat.pow_le_pow_right (n := 2) (by omega : 0 < 2) hexponent) + obtain ⟨f, hf, g, hg, hfg⟩ := Finset.one_lt_card.mp (by omega : 1 < F.card) + exact ⟨(f, g), Finset.mem_offDiag.mpr ⟨hf, hg, hfg⟩⟩ + +/-- A Kerdock coset union has `2^(2n)` codewords in dimension at least two. -/ +theorem card_kerdockCodeOfRepresentatives + {F : Finset (BooleanFunction n)} + (hF : IsKerdockRepresentativeFamily F) + (hnEven : Even n) (hn : 2 ≤ n) : + (kerdockCodeOfRepresentatives F).card = 2 ^ (2 * n) := by + rw [kerdockCodeOfRepresentatives, + card_firstOrderCosetUnion + (hasDistinctFirstOrderCosets_of_isKerdockRepresentativeFamily + hF hnEven hn), + hF.2.2.2, reedMuller_card] + have hsum : + (∑ j ∈ Finset.range (1 + 1), Nat.choose n j) = n + 1 := by + norm_num [Finset.sum_range_succ, Nat.choose_zero_right, + Nat.choose_one_right, Nat.add_comm] + rw [hsum, ← pow_add] + congr 1 + omega + +/-- The minimum pair nonlinearity of a Kerdock representative family is the +bent nonlinearity value. -/ +theorem minimumPairNonlinearity_eq_kerdockDistance + {F : Finset (BooleanFunction n)} + (hF : IsKerdockRepresentativeFamily F) (hn : 2 ≤ n) : + minimumPairNonlinearity F = + 2 ^ (n - 1) - 2 ^ (n / 2 - 1) := by + have hnonempty := kerdockRepresentativeFamily_offDiag_nonempty hF hn + obtain ⟨p, hp⟩ := hnonempty + have hnonempty' : F.offDiag.Nonempty := ⟨p, hp⟩ + have hpMem := Finset.mem_offDiag.mp hp + apply le_antisymm + · calc + minimumPairNonlinearity F ≤ nonlinearity (p.1 + p.2) := + minimumPairNonlinearity_le hnonempty' hpMem.1 hpMem.2.1 hpMem.2.2 + _ = 2 ^ (n - 1) - 2 ^ (n / 2 - 1) := + nonlinearity_add_eq_kerdockDistance_of_mem + hF hn hpMem.1 hpMem.2.1 hpMem.2.2 + · apply le_minimumPairNonlinearity hnonempty' + intro f hf g hg hfg + rw [nonlinearity_add_eq_kerdockDistance_of_mem hF hn hf hg hfg] + +/-- The minimum distance of a Kerdock coset union is +`2^(n-1) - 2^(n/2-1)`. -/ +theorem minimumHammingDistance_kerdockCodeOfRepresentatives + {F : Finset (BooleanFunction n)} + (hF : IsKerdockRepresentativeFamily F) + (hnEven : Even n) (hn : 2 ≤ n) : + minimumHammingDistance (kerdockCodeOfRepresentatives F) = + 2 ^ (n - 1) - 2 ^ (n / 2 - 1) := by + rw [kerdockCodeOfRepresentatives, + minimumHammingDistance_firstOrderCosetUnion + (kerdockRepresentativeFamily_offDiag_nonempty hF hn) + (hasDistinctFirstOrderCosets_of_isKerdockRepresentativeFamily + hF hnEven hn), + minimumPairNonlinearity_eq_kerdockDistance hF hn] + +/-- The Kerdock parameters determined by a finite quadratic representative +family in positive even dimension. -/ +theorem kerdockCodeOfRepresentatives_parameters + {F : Finset (BooleanFunction n)} + (hF : IsKerdockRepresentativeFamily F) + (hnEven : Even n) (hn : 2 ≤ n) : + F.offDiag.Nonempty ∧ + HasDistinctFirstOrderCosets F ∧ + (∀ ⦃c : BooleanFunction n⦄, c ∈ reedMuller 1 n → + c ∈ kerdockCodeOfRepresentatives F) ∧ + (∀ ⦃c : BooleanFunction n⦄, + c ∈ kerdockCodeOfRepresentatives F → c ∈ reedMuller 2 n) ∧ + (kerdockCodeOfRepresentatives F).card = 2 ^ (2 * n) ∧ + minimumHammingDistance (kerdockCodeOfRepresentatives F) = + 2 ^ (n - 1) - 2 ^ (n / 2 - 1) := by + exact ⟨kerdockRepresentativeFamily_offDiag_nonempty hF hn, + hasDistinctFirstOrderCosets_of_isKerdockRepresentativeFamily + hF hnEven hn, + reedMuller_one_subset_kerdockCodeOfRepresentatives hF, + kerdockCodeOfRepresentatives_subset_reedMuller_two hF, + card_kerdockCodeOfRepresentatives hF hnEven hn, + minimumHammingDistance_kerdockCodeOfRepresentatives hF hnEven hn⟩ + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/KerdockCoordinateIdentity.lean b/CryptBoolean/Carlet/Chapter06/KerdockCoordinateIdentity.lean new file mode 100644 index 0000000..1af7bd8 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/KerdockCoordinateIdentity.lean @@ -0,0 +1,267 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.CompleteQuadratic +public import CryptBoolean.Carlet.Chapter06.KerdockFieldConstruction + +/-! +# Self-dual normal-basis coordinates for the Kerdock trace quadratic + +The conditional coordinate identity relating the complete quadratic function +to Carlet's finite-field trace formula. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +private theorem completeQuadraticPolar_eq_totalProduct_add_dot {n : ℕ} + (a b : FABL.F₂Cube n) : + quadraticPolarKernel + (FABL.completeQuadraticBit : BooleanFunction n) a b = + (∑ i, a i) * (∑ i, b i) + ∑ i, a i * b i := by + rw [quadraticPolarKernel_completeQuadraticBit_eq_dotProduct, + FABL.f₂DotProduct, dotProduct] + simp only [completeQuadraticPolarFrequency] + rw [Finset.mul_sum] + rw [← Finset.sum_add_distrib] + apply Finset.sum_congr rfl + intro i _hi + rw [← Finset.sum_add_sum_compl ({i} : Finset (Fin n))] + simp + ring_nf + simp only [CharTwo.two_eq_zero, mul_zero, add_zero] + +private theorem completeQuadraticBit_single {n : ℕ} (i : Fin n) : + FABL.completeQuadraticBit (Pi.single i 1) = 0 := by + rw [FABL.completeQuadraticBit] + apply Finset.sum_eq_zero + intro j _hj + by_cases hji : j = i + · subst j + simp [Pi.single_apply] + · simp [Pi.single_apply, hji] + +private theorem completeQuadraticBit_zero {n : ℕ} : + FABL.completeQuadraticBit (0 : FABL.F₂Cube n) = 0 := by + rw [FABL.completeQuadraticBit] + simp + +private theorem append_single_eq_single_castAdd {m : ℕ} (i : Fin m) : + Fin.append (Pi.single i 1) (0 : FABL.F₂Cube 1) = + Pi.single (Fin.castAdd 1 i) 1 := by + funext j + refine Fin.addCases ?_ ?_ j + · intro k + simp [Pi.single_apply] + · intro k + have hne : Fin.natAdd m k ≠ Fin.castAdd 1 i := by + intro h + have hval := congrArg Fin.val h + simp only [Fin.val_natAdd, Fin.val_castAdd] at hval + omega + simp [hne] + +private theorem append_one_eq_single_natAdd {m : ℕ} : + Fin.append (0 : FABL.F₂Cube m) (1 : FABL.F₂Cube 1) = + Pi.single (Fin.natAdd m 0) 1 := by + funext j + refine Fin.addCases ?_ ?_ j + · intro k + have hne : Fin.castAdd 1 k ≠ Fin.natAdd m 0 := by + intro h + have hval := congrArg Fin.val h + simp only [Fin.val_castAdd, Fin.val_natAdd] at hval + omega + simp [hne] + · intro k + have hk : k = 0 := Subsingleton.elim _ _ + subst k + simp + +private theorem kerdockTraceQuadratic_basis_eq_zero_of_selfDualNormalCoordinates + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (hnormal : ∀ x : FABL.F₂Cube (2 * t + 1), + theta (fun i ↦ x (finRotate (2 * t + 1) i)) = + (theta x) ^ 2) + (hselfDual : ∀ x y : FABL.F₂Cube (2 * t + 1), + absoluteTrace (2 * t + 1) (theta x * theta y) = + ∑ i, x i * y i) + (i : Fin (2 * t + 1)) : + kerdockTraceQuadratic t (theta (Pi.single i 1)) = 0 := by + let rotate : FABL.F₂Cube (2 * t + 1) → + FABL.F₂Cube (2 * t + 1) := + fun x j ↦ x (finRotate (2 * t + 1) j) + haveI : NeZero (2 * t + 1) := ⟨by omega⟩ + have hiterate (x : FABL.F₂Cube (2 * t + 1)) (k : ℕ) : + theta (rotate^[k] x) = (theta x) ^ (2 ^ k) := by + induction k with + | zero => simp + | succ k ih => + rw [Function.iterate_succ_apply', hnormal, ih] + rw [Nat.pow_succ, pow_mul] + have hrotateApply (x : FABL.F₂Cube (2 * t + 1)) (k : ℕ) + (j : Fin (2 * t + 1)) : + (rotate^[k] x) j = x ((finRotate (2 * t + 1))^[k] j) := by + induction k generalizing j with + | zero => simp + | succ k ih => + rw [Function.iterate_succ_apply'] + change (rotate^[k] x) (finRotate (2 * t + 1) j) = _ + rw [ih, Function.iterate_succ_apply] + have hshiftNe (i : Fin (2 * t + 1)) (k : ℕ) + (hkpos : 0 < k) (hklt : k < 2 * t + 1) : + (finRotate (2 * t + 1))^[k] i ≠ i := by + let q : Fin (2 * t + 1) := ⟨k, hklt⟩ + have hcycle : i + q = (finRotate (2 * t + 1))^[k] i := by + simpa only [finCycle_apply, q] using + congrFun (finCycle_eq_finRotate_iterate (k := q)) i + intro heq + have hiq : i + q = i + 0 := by + rw [hcycle, heq, add_zero] + have hqzero : q = 0 := add_left_cancel hiq + exact (Nat.ne_of_gt hkpos) (congrArg Fin.val hqzero) + unfold kerdockTraceQuadratic oddQuadraticTracePart + rw [map_sum] + apply Finset.sum_eq_zero + intro j _hj + simp only [one_mul, binaryFrobeniusLinear_apply] + rw [← hiterate (Pi.single i 1) ((j : ℕ) + 1), hselfDual] + apply Finset.sum_eq_zero + intro k _hk + by_cases hki : k = i + · subst k + rw [hrotateApply] + simp only [Pi.single_apply, if_pos, mul_one] + rw [if_neg] + exact hshiftNe i ((j : ℕ) + 1) (by omega) (by omega) + · simp [hki] + +/-- Under self-dual normal-basis coordinates, Relation (56) is the +finite-field Kerdock trace formula. The hypotheses state the Frobenius +rotation, absolute-trace coordinate sum, and self-dual trace pairing. -/ +theorem completeQuadraticBit_eq_kerdockFieldRepresentative_one_of_selfDualNormalCoordinates + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (hnormal : ∀ x : FABL.F₂Cube (2 * t + 1), + theta (fun i ↦ x (finRotate (2 * t + 1) i)) = + (theta x) ^ 2) + (htrace : ∀ x : FABL.F₂Cube (2 * t + 1), + absoluteTrace (2 * t + 1) (theta x) = ∑ i, x i) + (hselfDual : ∀ x y : FABL.F₂Cube (2 * t + 1), + absoluteTrace (2 * t + 1) (theta x * theta y) = + ∑ i, x i * y i) : + (FABL.completeQuadraticBit : BooleanFunction ((2 * t + 1) + 1)) = + kerdockFieldRepresentative t theta 1 := by + let split := cubeSplitLinearEquiv (2 * t + 1) 1 + let field := kerdockFieldRepresentative t theta 1 + let difference : BooleanFunction ((2 * t + 1) + 1) := + FABL.completeQuadraticBit + field + have hpolar : ∀ a b, quadraticPolarKernel difference a b = 0 := by + intro a b + let x := (split a).1 + let z := (split a).2 + let y := (split b).1 + let r := (split b).2 + have ha : a = Fin.append x z := by + apply split.injective + simp [split, x, z, cubeSplitLinearEquiv] + have hb : b = Fin.append y r := by + apply split.injective + simp [split, y, r, cubeSplitLinearEquiv] + have hdifference : + quadraticPolarKernel difference a b = + quadraticPolarKernel + (FABL.completeQuadraticBit : + BooleanFunction ((2 * t + 1) + 1)) a b + + quadraticPolarKernel field a b := by + simp only [difference, quadraticPolarKernel_eq, Pi.add_apply] + ring + have hsumA : + (∑ i, Fin.append x z i) = (∑ i, x i) + z 0 := by + rw [Fin.sum_univ_add] + simp + have hsumB : + (∑ i, Fin.append y r i) = (∑ i, y i) + r 0 := by + rw [Fin.sum_univ_add] + simp + have hdot : + (∑ i, Fin.append x z i * Fin.append y r i) = + (∑ i, x i * y i) + z 0 * r 0 := by + rw [Fin.sum_univ_add] + simp + have hfieldA : + kerdockFieldCoordinateEquiv t theta (Fin.append x z) = + (theta x, z 0) := by + simp [kerdockFieldCoordinateEquiv, cubeSplitLinearEquiv] + have hfieldB : + kerdockFieldCoordinateEquiv t theta (Fin.append y r) = + (theta y, r 0) := by + simp [kerdockFieldCoordinateEquiv, cubeSplitLinearEquiv] + rw [hdifference, ha, hb, completeQuadraticPolar_eq_totalProduct_add_dot] + rw [hsumA, hsumB, hdot] + rw [quadraticPolarKernel_kerdockFieldRepresentative] + rw [hfieldA, hfieldB] + simp only [one_mul, one_pow] + rw [htrace, htrace, hselfDual] + ring_nf + simp only [CharTwo.two_eq_zero, mul_zero, add_zero] + obtain ⟨c, frequency, haffine⟩ := + exists_affineFunction_of_quadraticPolarKernel_eq_zero difference hpolar + have hc : c = 0 := by + have hzero := congrFun haffine 0 + symm + simpa [difference, field, kerdockFieldRepresentative, + kerdockFieldQuadratic, kerdockTraceQuadratic, oddQuadraticTracePart, + FABL.affineFunction, FABL.f₂DotProduct, + completeQuadraticBit_zero] using hzero + have hfieldSingle (i : Fin ((2 * t + 1) + 1)) : + field (Pi.single i 1) = 0 := by + refine Fin.addCases ?_ ?_ i + · intro j + rw [← append_single_eq_single_castAdd j] + have hbasis := + kerdockTraceQuadratic_basis_eq_zero_of_selfDualNormalCoordinates + t theta hnormal hselfDual j + simp [field, kerdockFieldRepresentative, kerdockFieldCoordinateEquiv, + cubeSplitLinearEquiv, kerdockFieldQuadratic, hbasis] + · intro j + have hj : j = 0 := Subsingleton.elim _ _ + subst j + rw [← append_one_eq_single_natAdd] + dsimp only [field, kerdockFieldRepresentative] + rw [show kerdockFieldCoordinateEquiv t theta + (Fin.append (0 : FABL.F₂Cube (2 * t + 1)) + (1 : FABL.F₂Cube 1)) = (0, 1) by + simp [kerdockFieldCoordinateEquiv, cubeSplitLinearEquiv] + rfl] + simp [kerdockFieldQuadratic, kerdockTraceQuadratic, + oddQuadraticTracePart] + have hfrequency : frequency = 0 := by + funext i + have hi := congrFun haffine (Pi.single i 1) + have hcomplete := completeQuadraticBit_single i + rw [hc] at hi + simp only [difference, Pi.add_apply, hcomplete, hfieldSingle, zero_add, + FABL.affineFunction, FABL.f₂DotProduct, zero_add] at hi + rw [dotProduct_single] at hi + simpa using hi.symm + funext a + have haffineA := congrFun haffine a + rw [hc, hfrequency] at haffineA + simp only [difference, Pi.add_apply, FABL.affineFunction, + FABL.f₂DotProduct, zero_add, zero_dotProduct] at haffineA + exact (add_eq_zero_iff_eq_neg.mp haffineA).trans + (ZModModule.neg_eq_self _) + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/KerdockFieldConstruction.lean b/CryptBoolean/Carlet/Chapter06/KerdockFieldConstruction.lean new file mode 100644 index 0000000..df471b8 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/KerdockFieldConstruction.lean @@ -0,0 +1,716 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter04.AlgebraicImmunityBounds +public import CryptBoolean.Carlet.Chapter05.QuadraticTraceRepresentation +public import CryptBoolean.Carlet.Chapter06.Kerdock +public import CryptBoolean.Carlet.Chapter06.QuadraticBent + +/-! +# Finite-field construction of Kerdock representatives + +The odd-dimensional trace quadratic, its one-coordinate extension, and the +resulting finite family of quadratic representatives with pairwise bent sums. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +/-- The homogeneous trace quadratic used in the Kerdock construction. -/ +noncomputable def kerdockTraceQuadratic (t : ℕ) : + FieldBooleanFunction (2 * t + 1) := + oddQuadraticTracePart t (fun _ ↦ 1) + +/-- The field-coordinate Kerdock representative indexed by `u`. -/ +noncomputable def kerdockFieldQuadratic (t : ℕ) + (u x : BinaryGaloisField (2 * t + 1)) (z : FABL.𝔽₂) : FABL.𝔽₂ := + kerdockTraceQuadratic t (u * x) + z * absoluteTrace (2 * t + 1) (u * x) + +private theorem kerdockFrobeniusCoefficientSum (t : ℕ) + (x : BinaryGaloisField (2 * t + 1)) : + (∑ i : Fin t, + (x ^ (2 ^ ((i : ℕ) + 1)) + + x ^ (2 ^ ((2 * t + 1) - ((i : ℕ) + 1))))) = + algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) + (absoluteTrace (2 * t + 1) x) + x := by + rw [algebraMap_absoluteTrace_eq_sum_frobenius (by omega)] + rw [Finset.sum_add_distrib] + let f : ℕ → BinaryGaloisField (2 * t + 1) := fun i ↦ x ^ (2 ^ i) + have hfirst : + (∑ i : Fin t, x ^ (2 ^ ((i : ℕ) + 1))) = + ∑ i ∈ Finset.range t, f (i + 1) := + Fin.sum_univ_eq_sum_range (fun i ↦ f (i + 1)) t + have hsecond : + (∑ i : Fin t, x ^ (2 ^ ((2 * t + 1) - ((i : ℕ) + 1)))) = + ∑ i ∈ Finset.range t, f ((2 * t + 1) - (i + 1)) := + Fin.sum_univ_eq_sum_range + (fun i ↦ f ((2 * t + 1) - (i + 1))) t + rw [hfirst, hsecond] + change (∑ i ∈ Finset.range t, f (i + 1)) + + (∑ i ∈ Finset.range t, f ((2 * t + 1) - (i + 1))) = + (∑ i ∈ Finset.range (2 * t + 1), f i) + x + have hreflect : + (∑ i ∈ Finset.range t, f ((2 * t + 1) - (i + 1))) = + ∑ i ∈ Finset.range t, f (t + 1 + i) := by + calc + (∑ i ∈ Finset.range t, f ((2 * t + 1) - (i + 1))) = + ∑ i ∈ Finset.range t, f (t + 1 + (t - 1 - i)) := by + apply Finset.sum_congr rfl + intro i hi + congr 1 + have hit : i < t := Finset.mem_range.mp hi + omega + _ = ∑ i ∈ Finset.range t, f (t + 1 + i) := + Finset.sum_range_reflect (fun i ↦ f (t + 1 + i)) t + rw [hreflect] + have hrange : + (∑ i ∈ Finset.range (2 * t + 1), f i) = + (∑ i ∈ Finset.range (2 * t), f (i + 1)) + f 0 := by + simpa only [Nat.succ_eq_add_one] using + (Finset.sum_range_succ' f (2 * t)) + rw [hrange] + have hsplit : + (∑ i ∈ Finset.range (2 * t), f (i + 1)) = + (∑ i ∈ Finset.range t, f (i + 1)) + + ∑ i ∈ Finset.range t, f (t + 1 + i) := by + simpa only [two_mul, add_assoc, add_comm, add_left_comm] using + (Finset.sum_range_add (f := fun i ↦ f (i + 1)) t t) + rw [hsplit] + have hfzero : f 0 = x := by simp [f] + rw [hfzero] + change (∑ i ∈ Finset.range t, f (i + 1)) + + (∑ i ∈ Finset.range t, f (t + 1 + i)) = + ((∑ i ∈ Finset.range t, f (i + 1)) + + (∑ i ∈ Finset.range t, f (t + 1 + i)) + x) + x + rw [add_assoc, ZModModule.add_self, add_zero] + +/-- The polar form of the odd-dimensional trace quadratic is the sum of the +trace-product form and the trace pairing. -/ +theorem kerdockTraceQuadratic_polar (t : ℕ) + (x y : BinaryGaloisField (2 * t + 1)) : + kerdockTraceQuadratic t (x + y) + + kerdockTraceQuadratic t x + kerdockTraceQuadratic t y = + absoluteTrace (2 * t + 1) x * absoluteTrace (2 * t + 1) y + + absoluteTrace (2 * t + 1) (x * y) := by + have hpolar := oddQuadraticTracePart_polar_eq_sum t + (fun _ ↦ 1) x y + have hzero : oddQuadraticTracePart t (fun _ ↦ 1) 0 = 0 := by + simp [oddQuadraticTracePart] + rw [hzero, add_zero] at hpolar + change oddQuadraticTracePart t (fun _ ↦ 1) (x + y) + + oddQuadraticTracePart t (fun _ ↦ 1) x + + oddQuadraticTracePart t (fun _ ↦ 1) y = _ + rw [hpolar] + simp only [one_mul] + have hadjoint (i : Fin t) : + absoluteTrace (2 * t + 1) + (x * y ^ (2 ^ ((i : ℕ) + 1))) = + absoluteTrace (2 * t + 1) + (x ^ (2 ^ ((2 * t + 1) - ((i : ℕ) + 1))) * y) := by + exact absoluteTrace_mul_frobeniusPow + (2 * t + 1) ((i : ℕ) + 1) (by omega) (by omega) x y + calc + (∑ i : Fin t, absoluteTrace (2 * t + 1) + (x ^ (2 ^ ((i : ℕ) + 1)) * y + + x * y ^ (2 ^ ((i : ℕ) + 1)))) = + ∑ i : Fin t, absoluteTrace (2 * t + 1) + ((x ^ (2 ^ ((i : ℕ) + 1)) + + x ^ (2 ^ ((2 * t + 1) - ((i : ℕ) + 1)))) * y) := by + apply Finset.sum_congr rfl + intro i _hi + rw [map_add, hadjoint i, ← map_add, add_mul] + _ = absoluteTrace (2 * t + 1) + ((∑ i : Fin t, + (x ^ (2 ^ ((i : ℕ) + 1)) + + x ^ (2 ^ ((2 * t + 1) - ((i : ℕ) + 1))))) * y) := by + rw [Finset.sum_mul, map_sum] + _ = absoluteTrace (2 * t + 1) + ((algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) + (absoluteTrace (2 * t + 1) x) + x) * y) := by + rw [kerdockFrobeniusCoefficientSum] + _ = absoluteTrace (2 * t + 1) x * absoluteTrace (2 * t + 1) y + + absoluteTrace (2 * t + 1) (x * y) := by + rw [add_mul, map_add, ← Algebra.smul_def, map_smul] + rfl + +/-- On an odd binary extension, the absolute trace restricts to the identity +on the prime field. -/ +@[simp] theorem absoluteTrace_algebraMap_odd (t : ℕ) (c : FABL.𝔽₂) : + absoluteTrace (2 * t + 1) + (algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) c) = c := by + rw [absoluteTrace, Algebra.trace_algebraMap, + GaloisField.finrank 2 (by omega)] + rw [nsmul_eq_mul] + push_cast + simp only [CharTwo.two_eq_zero, zero_mul, zero_add, one_mul] + +/-- The odd-dimensional trace quadratic pulled back to binary coordinates. -/ +noncomputable def kerdockTraceCube (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (u : BinaryGaloisField (2 * t + 1)) : + BooleanFunction (2 * t + 1) := + fun x ↦ kerdockTraceQuadratic t (u * theta x) + +/-- The linear trace character paired with the Kerdock field parameter. -/ +noncomputable def kerdockTraceLinearCube (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (u : BinaryGaloisField (2 * t + 1)) : + BooleanFunction (2 * t + 1) := + fun x ↦ absoluteTrace (2 * t + 1) (u * theta x) + +/-- The binary-coordinate trace quadratic has algebraic degree at most two. -/ +theorem functionAlgebraicDegree_kerdockTraceCube_le_two + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (u : BinaryGaloisField (2 * t + 1)) : + FABL.functionAlgebraicDegree (kerdockTraceCube t theta u) ≤ 2 := by + by_cases ht : t = 0 + · subst t + have hzero : kerdockTraceCube 0 theta u = 0 := by + funext x + simp [kerdockTraceCube, kerdockTraceQuadratic, + oddQuadraticTracePart] + simp [hzero] + · let term (i : Fin t) : BooleanFunction (2 * t + 1) := + fun x ↦ absoluteTrace (2 * t + 1) + (u ^ (2 ^ ((i : ℕ) + 1) + 1) * + (theta x) ^ (2 ^ ((i : ℕ) + 1) + 1)) + have hdecomposition : + kerdockTraceCube t theta u = ∑ i, term i := by + funext x + simp only [kerdockTraceCube, kerdockTraceQuadratic, + oddQuadraticTracePart, binaryFrobeniusLinear_apply, one_mul, + map_sum, Finset.sum_apply, term] + apply Finset.sum_congr rfl + intro i _hi + congr 1 + rw [mul_pow, pow_add, pow_add, pow_one, pow_one] + ring + rw [hdecomposition] + apply FABL.functionAlgebraicDegree_finset_sum_le Finset.univ term 2 + intro i _hi + apply functionAlgebraicDegree_traceMonomial_two_pow_add_one_le_two + (by omega : 0 < 2 * t + 1) + exact two_pow_add_one_lt_odd_modulus t (Nat.pos_of_ne_zero ht) + ⟨(i : ℕ) + 1, by omega⟩ + +/-- The trace character paired with `u` is affine-linear. -/ +theorem functionAlgebraicDegree_kerdockTraceLinearCube_le_one + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (u : BinaryGaloisField (2 * t + 1)) : + FABL.functionAlgebraicDegree + (kerdockTraceLinearCube t theta u) ≤ 1 := by + have hlinear : FABL.IsF₂Linear (kerdockTraceLinearCube t theta u) := by + intro x y + simp [kerdockTraceLinearCube, mul_add] + obtain ⟨a, ha⟩ := (FABL.isF₂Linear_iff_exists_dotProduct _).mp hlinear + have heq : kerdockTraceLinearCube t theta u = + FABL.affineFunction 0 a := by + funext x + rw [ha x] + simp [FABL.affineFunction] + rw [heq] + exact FABL.functionAlgebraicDegree_affineFunction_le_one 0 a + +/-- Coordinates on the Kerdock ambient cube, split into the odd-dimensional +field coordinate and the final bit. -/ +noncomputable def kerdockFieldCoordinateEquiv (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) : + FABL.F₂Cube ((2 * t + 1) + 1) ≃ₗ[FABL.𝔽₂] + (BinaryGaloisField (2 * t + 1) × FABL.𝔽₂) := + (cubeSplitLinearEquiv (2 * t + 1) 1).trans + (theta.prodCongr (LinearEquiv.funUnique (Fin 1) FABL.𝔽₂ FABL.𝔽₂)) + +/-- The Boolean representative obtained by transporting the field-coordinate +quadratic to the canonical binary cube. -/ +noncomputable def kerdockFieldRepresentative (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (u : BinaryGaloisField (2 * t + 1)) : + BooleanFunction ((2 * t + 1) + 1) := + fun a ↦ + let p := kerdockFieldCoordinateEquiv t theta a + kerdockFieldQuadratic t u p.1 p.2 + +@[simp] theorem kerdockFieldRepresentative_coordinate + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (u x : BinaryGaloisField (2 * t + 1)) (z : FABL.𝔽₂) : + kerdockFieldRepresentative t theta u + ((kerdockFieldCoordinateEquiv t theta).symm (x, z)) = + kerdockFieldQuadratic t u x z := by + simp [kerdockFieldRepresentative] + +@[simp] theorem kerdockFieldRepresentative_zero + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) : + kerdockFieldRepresentative t theta 0 = 0 := by + funext a + simp [kerdockFieldRepresentative, kerdockFieldQuadratic, + kerdockTraceQuadratic, oddQuadraticTracePart] + +/-- Every finite-field Kerdock representative has algebraic degree at most +two. -/ +theorem functionAlgebraicDegree_kerdockFieldRepresentative_le_two + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (u : BinaryGaloisField (2 * t + 1)) : + FABL.functionAlgebraicDegree + (kerdockFieldRepresentative t theta u) ≤ 2 := by + let e := kerdockFieldCoordinateEquiv t theta + let fieldPart := + (LinearMap.fst FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) FABL.𝔽₂).comp + e.toLinearMap + let prefixMap := + theta.symm.toLinearMap.comp fieldPart + let bitPart := + (LinearMap.snd FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) FABL.𝔽₂).comp + e.toLinearMap + let final := + (LinearEquiv.funUnique (Fin 1) FABL.𝔽₂ FABL.𝔽₂).symm.toLinearMap.comp + bitPart + let quadraticPull : BooleanFunction ((2 * t + 1) + 1) := + kerdockTraceCube t theta u ∘ prefixMap.toAffineMap + let linearPull : BooleanFunction ((2 * t + 1) + 1) := + kerdockTraceLinearCube t theta u ∘ prefixMap.toAffineMap + let lastBit : BooleanFunction ((2 * t + 1) + 1) := + fun a ↦ final a 0 + have hdecomposition : + kerdockFieldRepresentative t theta u = + quadraticPull + lastBit * linearPull := by + funext a + simp [kerdockFieldRepresentative, kerdockFieldQuadratic, + quadraticPull, linearPull, lastBit, prefixMap, fieldPart, final, bitPart, + e, kerdockTraceCube, kerdockTraceLinearCube] + have hquadratic : + FABL.functionAlgebraicDegree quadraticPull ≤ 2 := + (functionAlgebraicDegree_comp_affineMap_le_general + (kerdockTraceCube t theta u) prefixMap.toAffineMap).trans + (functionAlgebraicDegree_kerdockTraceCube_le_two t theta u) + have hlinear : + FABL.functionAlgebraicDegree linearPull ≤ 1 := + (functionAlgebraicDegree_comp_affineMap_le_general + (kerdockTraceLinearCube t theta u) prefixMap.toAffineMap).trans + (functionAlgebraicDegree_kerdockTraceLinearCube_le_one t theta u) + have hlast : FABL.functionAlgebraicDegree lastBit ≤ 1 := by + exact functionAlgebraicDegree_affineMap_coordinate_le_one_general + final.toAffineMap 0 + rw [hdecomposition] + apply (FABL.functionAlgebraicDegree_add_le_max quadraticPull + (lastBit * linearPull)).trans + apply max_le hquadratic + exact (FABL.functionAlgebraicDegree_mul_le_add lastBit linearPull).trans + (Nat.add_le_add hlast hlinear |>.trans (by omega)) + +/-- The polar form of one field-coordinate Kerdock representative. -/ +theorem quadraticPolarKernel_kerdockFieldRepresentative + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (u : BinaryGaloisField (2 * t + 1)) + (a b : FABL.F₂Cube ((2 * t + 1) + 1)) : + let xz := kerdockFieldCoordinateEquiv t theta a + let yr := kerdockFieldCoordinateEquiv t theta b + quadraticPolarKernel (kerdockFieldRepresentative t theta u) a b = + absoluteTrace (2 * t + 1) (u * xz.1) * + absoluteTrace (2 * t + 1) (u * yr.1) + + absoluteTrace (2 * t + 1) (u ^ 2 * (xz.1 * yr.1)) + + xz.2 * absoluteTrace (2 * t + 1) (u * yr.1) + + yr.2 * absoluteTrace (2 * t + 1) (u * xz.1) := by + dsimp only + rw [quadraticPolarKernel_eq] + have hzero : kerdockTraceQuadratic t 0 = 0 := by + simp [kerdockTraceQuadratic, oddQuadraticTracePart] + simp only [kerdockFieldRepresentative, map_add, Prod.fst_add, Prod.snd_add, + kerdockFieldQuadratic, map_zero, Prod.fst_zero, Prod.snd_zero, mul_zero, + hzero, add_zero] + rw [show u * + ((kerdockFieldCoordinateEquiv t theta a).1 + + (kerdockFieldCoordinateEquiv t theta b).1) = + u * (kerdockFieldCoordinateEquiv t theta a).1 + + u * (kerdockFieldCoordinateEquiv t theta b).1 by ring] + simp only [map_add] + have hpolar := kerdockTraceQuadratic_polar t + (u * (kerdockFieldCoordinateEquiv t theta a).1) + (u * (kerdockFieldCoordinateEquiv t theta b).1) + have hproduct : + (u * (kerdockFieldCoordinateEquiv t theta a).1) * + (u * (kerdockFieldCoordinateEquiv t theta b).1) = + u ^ 2 * + ((kerdockFieldCoordinateEquiv t theta a).1 * + (kerdockFieldCoordinateEquiv t theta b).1) := by + ring + let cross : FABL.𝔽₂ := + (kerdockFieldCoordinateEquiv t theta a).2 * + absoluteTrace (2 * t + 1) + (u * (kerdockFieldCoordinateEquiv t theta b).1) + + (kerdockFieldCoordinateEquiv t theta b).2 * + absoluteTrace (2 * t + 1) + (u * (kerdockFieldCoordinateEquiv t theta a).1) + have hwithCross := congrArg (fun c : FABL.𝔽₂ ↦ c + cross) hpolar + rw [hproduct] at hwithCross + dsimp only [cross] at hwithCross + ring_nf at hwithCross ⊢ + simp only [CharTwo.two_eq_zero, mul_zero, add_zero] at hwithCross ⊢ + exact hwithCross + +/-- The polar form of the sum of two representatives, expressed through +their parameter sum. -/ +theorem quadraticPolarKernel_kerdockFieldRepresentative_add + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (u v : BinaryGaloisField (2 * t + 1)) + (a b : FABL.F₂Cube ((2 * t + 1) + 1)) : + let xz := kerdockFieldCoordinateEquiv t theta a + let yr := kerdockFieldCoordinateEquiv t theta b + let w := u + v + quadraticPolarKernel + (kerdockFieldRepresentative t theta u + + kerdockFieldRepresentative t theta v) a b = + absoluteTrace (2 * t + 1) (u * xz.1) * + absoluteTrace (2 * t + 1) (u * yr.1) + + absoluteTrace (2 * t + 1) (v * xz.1) * + absoluteTrace (2 * t + 1) (v * yr.1) + + absoluteTrace (2 * t + 1) (w ^ 2 * (xz.1 * yr.1)) + + xz.2 * absoluteTrace (2 * t + 1) (w * yr.1) + + yr.2 * absoluteTrace (2 * t + 1) (w * xz.1) := by + dsimp only + have hadd : quadraticPolarKernel + (kerdockFieldRepresentative t theta u + + kerdockFieldRepresentative t theta v) a b = + quadraticPolarKernel (kerdockFieldRepresentative t theta u) a b + + quadraticPolarKernel (kerdockFieldRepresentative t theta v) a b := by + simp only [quadraticPolarKernel_eq, Pi.add_apply] + ring + have hsquare : (u + v) ^ 2 = u ^ 2 + v ^ 2 := by + ring_nf + simp only [CharTwo.two_eq_zero, mul_zero, zero_add] + rw [hadd, + quadraticPolarKernel_kerdockFieldRepresentative t theta u a b, + quadraticPolarKernel_kerdockFieldRepresentative t theta v a b, + hsquare] + simp only [add_mul, map_add, mul_add] + ring + +/-- Distinct field parameters give a sum whose quadratic polar form has +trivial radical. -/ +theorem eq_zero_of_forall_quadraticPolarKernel_kerdockFieldRepresentative_add + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (u v : BinaryGaloisField (2 * t + 1)) (huv : u ≠ v) + (a : FABL.F₂Cube ((2 * t + 1) + 1)) + (ha : ∀ b, quadraticPolarKernel + (kerdockFieldRepresentative t theta u + + kerdockFieldRepresentative t theta v) a b = 0) : + a = 0 := by + let e := kerdockFieldCoordinateEquiv t theta + let w := u + v + let x := (e a).1 + let z := (e a).2 + have hw : w ≠ 0 := by + intro hwzero + apply huv + have h := congrArg (fun c ↦ c + v) hwzero + simpa only [w, add_assoc, ZModModule.add_self, add_zero, zero_add] using h + have htrace : absoluteTrace (2 * t + 1) (w * x) = 0 := by + have h := ha (e.symm (0, 1)) + rw [quadraticPolarKernel_kerdockFieldRepresentative_add + t theta u v a (e.symm (0, 1))] at h + simpa [e, w, x] using h + have htraceUV : + absoluteTrace (2 * t + 1) (u * x) = + absoluteTrace (2 * t + 1) (v * x) := by + have hsum : + absoluteTrace (2 * t + 1) (u * x) + + absoluteTrace (2 * t + 1) (v * x) = 0 := by + simpa [w, add_mul, map_add] using htrace + have h := congrArg (fun c ↦ c + + absoluteTrace (2 * t + 1) (v * x)) hsum + simpa only [add_assoc, ZModModule.add_self, add_zero, zero_add] using h + have hforall (y : BinaryGaloisField (2 * t + 1)) : + absoluteTrace (2 * t + 1) (u * x) * + absoluteTrace (2 * t + 1) (u * y) + + absoluteTrace (2 * t + 1) (v * x) * + absoluteTrace (2 * t + 1) (v * y) + + absoluteTrace (2 * t + 1) (w ^ 2 * (x * y)) + + z * absoluteTrace (2 * t + 1) (w * y) = 0 := by + have h := ha (e.symm (y, 0)) + rw [quadraticPolarKernel_kerdockFieldRepresentative_add + t theta u v a (e.symm (y, 0))] at h + simpa [e, w, x, z] using h + let s := absoluteTrace (2 * t + 1) (u * x) + let c : BinaryGaloisField (2 * t + 1) := + algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) s * w + + w ^ 2 * x + + algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) z * w + have hpair (y : BinaryGaloisField (2 * t + 1)) : + absoluteTrace (2 * t + 1) (c * y) = 0 := by + calc + absoluteTrace (2 * t + 1) (c * y) = + s * absoluteTrace (2 * t + 1) (w * y) + + absoluteTrace (2 * t + 1) (w ^ 2 * (x * y)) + + z * absoluteTrace (2 * t + 1) (w * y) := by + simp only [c, add_mul, map_add, mul_assoc] + rw [← Algebra.smul_def, map_smul, ← Algebra.smul_def, map_smul] + simp only [smul_eq_mul] + _ = 0 := by + simpa [s, w, add_mul, map_add, mul_add, htraceUV] using hforall y + letI : Algebra.IsAlgebraic FABL.𝔽₂ + (BinaryGaloisField (2 * t + 1)) := + Algebra.IsIntegral.isAlgebraic + letI : Algebra.IsSeparable FABL.𝔽₂ + (BinaryGaloisField (2 * t + 1)) := + Algebra.IsAlgebraic.isSeparable_of_perfectField + have hc : c = 0 := by + apply (traceForm_nondegenerate FABL.𝔽₂ + (BinaryGaloisField (2 * t + 1))).1 + intro y + rw [Algebra.traceForm_apply] + exact hpair y + have hfactor : + w * (algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) s + + w * x + + algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) z) = 0 := by + calc + w * (algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) s + + w * x + + algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) z) = c := by + dsimp only [c] + ring + _ = 0 := hc + have hinner : + algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) s + + w * x + + algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) z = 0 := + (mul_eq_zero.mp hfactor).resolve_left hw + have hwx : + w * x = algebraMap FABL.𝔽₂ + (BinaryGaloisField (2 * t + 1)) (s + z) := by + rw [map_add] + linear_combination + (norm := (ring_nf; simp [CharTwo.two_eq_zero])) + hinner + have hsz : s + z = 0 := by + have h := congrArg (absoluteTrace (2 * t + 1)) hwx + rw [htrace, absoluteTrace_algebraMap_odd] at h + exact h.symm + have hwxzero : w * x = 0 := by + rw [hwx, hsz, map_zero] + have hx : x = 0 := (mul_eq_zero.mp hwxzero).resolve_left hw + have hs : s = 0 := by + simp [s, hx] + have hzMap : + algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1)) z = 0 := by + simpa [hs, hx] using hinner + have hz : z = 0 := by + apply (algebraMap FABL.𝔽₂ (BinaryGaloisField (2 * t + 1))).injective + simpa using hzMap + apply e.injective + rw [map_zero] + apply Prod.ext + · simpa [x] using hx + · simpa [z] using hz + +/-- Distinct field parameters index representatives with bent pairwise sum. -/ +theorem isBent_kerdockFieldRepresentative_add + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (u v : BinaryGaloisField (2 * t + 1)) (huv : u ≠ v) : + IsBent (kerdockFieldRepresentative t theta u + + kerdockFieldRepresentative t theta v) := by + let f := kerdockFieldRepresentative t theta u + + kerdockFieldRepresentative t theta v + have hdegree : FABL.functionAlgebraicDegree f ≤ 2 := + (FABL.functionAlgebraicDegree_add_le_max + (kerdockFieldRepresentative t theta u) + (kerdockFieldRepresentative t theta v)).trans + (max_le + (functionAlgebraicDegree_kerdockFieldRepresentative_le_two + t theta u) + (functionAlgebraicDegree_kerdockFieldRepresentative_le_two + t theta v)) + apply (isBent_iff_quadraticRadical_eq_bot f hdegree).2 + ext a + constructor + · intro ha + have hall := (mem_quadraticRadical_iff f hdegree a).mp ha + have hazero := + eq_zero_of_forall_quadraticPolarKernel_kerdockFieldRepresentative_add + t theta u v huv a hall + simp [hazero] + · intro ha + have hazero : a = 0 := by simpa using ha + subst a + exact Submodule.zero_mem _ + +private theorem functionAlgebraicDegree_eq_two_of_isBent_of_le_two + {n : ℕ} (f : BooleanFunction n) (hf : IsBent f) + (hdegree : FABL.functionAlgebraicDegree f ≤ 2) (hn : 2 ≤ n) : + FABL.functionAlgebraicDegree f = 2 := by + apply Nat.le_antisymm hdegree + by_contra hnot + have hdegreeOne : FABL.functionAlgebraicDegree f ≤ 1 := by omega + obtain ⟨b, a, hfa⟩ := + FABL.exists_affineFunction_of_functionAlgebraicDegree_le_one + f hdegreeOne + have hnonlinearity := + nonlinearity_eq_two_pow_sub_two_pow_half_of_isBent f hf hn + rw [hfa, nonlinearity_affineFunction] at hnonlinearity + have hexponents : n / 2 - 1 < n - 1 := by + rcases even_of_isBent f hf with ⟨k, rfl⟩ + omega + have hpowers : 2 ^ (n / 2 - 1) < 2 ^ (n - 1) := + Nat.pow_lt_pow_right (by omega) hexponents + omega + +/-- A representative with nonzero field parameter is genuinely quadratic. -/ +theorem functionAlgebraicDegree_kerdockFieldRepresentative_eq_two + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) + (u : BinaryGaloisField (2 * t + 1)) (hu : u ≠ 0) : + FABL.functionAlgebraicDegree + (kerdockFieldRepresentative t theta u) = 2 := by + have hbent : IsBent (kerdockFieldRepresentative t theta u) := by + simpa using isBent_kerdockFieldRepresentative_add t theta u 0 hu + exact functionAlgebraicDegree_eq_two_of_isBent_of_le_two + (kerdockFieldRepresentative t theta u) hbent + (functionAlgebraicDegree_kerdockFieldRepresentative_le_two t theta u) + (by omega) + +/-- Distinct field parameters determine distinct Boolean representatives. -/ +theorem kerdockFieldRepresentative_injective + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) : + Function.Injective (kerdockFieldRepresentative t theta) := by + intro u v huv + by_contra hne + have hbent := isBent_kerdockFieldRepresentative_add t theta u v hne + have hdegree := functionAlgebraicDegree_eq_two_of_isBent_of_le_two + (kerdockFieldRepresentative t theta u + + kerdockFieldRepresentative t theta v) + hbent + ((FABL.functionAlgebraicDegree_add_le_max + (kerdockFieldRepresentative t theta u) + (kerdockFieldRepresentative t theta v)).trans + (max_le + (functionAlgebraicDegree_kerdockFieldRepresentative_le_two + t theta u) + (functionAlgebraicDegree_kerdockFieldRepresentative_le_two + t theta v))) + (by omega) + have hzero : kerdockFieldRepresentative t theta u + + kerdockFieldRepresentative t theta v = 0 := by + funext a + simp only [Pi.add_apply] + rw [huv, ZModModule.add_self] + rfl + rw [hzero, FABL.functionAlgebraicDegree_zero] at hdegree + omega + +/-- The finite set of all Kerdock representatives indexed by the odd binary +field. -/ +noncomputable def kerdockFieldRepresentativeFamily (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) : + Finset (BooleanFunction ((2 * t + 1) + 1)) := by + classical + letI : Fintype (BinaryGaloisField (2 * t + 1)) := Fintype.ofFinite _ + exact Finset.univ.image (kerdockFieldRepresentative t theta) + +/-- The finite-field representative set has one member for every field +parameter. -/ +theorem card_kerdockFieldRepresentativeFamily + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) : + (kerdockFieldRepresentativeFamily t theta).card = 2 ^ (2 * t + 1) := by + classical + letI : Fintype (BinaryGaloisField (2 * t + 1)) := Fintype.ofFinite _ + rw [kerdockFieldRepresentativeFamily, + Finset.card_image_of_injective] + · rw [Finset.card_univ, ← Nat.card_eq_fintype_card, + GaloisField.card 2 (2 * t + 1) (by omega)] + · exact kerdockFieldRepresentative_injective t theta + +/-- The explicit finite-field family satisfies the Kerdock representative +conditions. -/ +theorem isKerdockRepresentativeFamily_kerdockField + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) : + IsKerdockRepresentativeFamily + (kerdockFieldRepresentativeFamily t theta) := by + classical + letI : Fintype (BinaryGaloisField (2 * t + 1)) := Fintype.ofFinite _ + refine ⟨?_, ?_, ?_, ?_⟩ + · rw [kerdockFieldRepresentativeFamily] + exact Finset.mem_image.mpr + ⟨0, Finset.mem_univ 0, kerdockFieldRepresentative_zero t theta⟩ + · intro f hf hfzero + rw [kerdockFieldRepresentativeFamily] at hf + obtain ⟨u, _huMem, rfl⟩ := Finset.mem_image.mp hf + apply functionAlgebraicDegree_kerdockFieldRepresentative_eq_two + intro hu + subst u + exact hfzero (kerdockFieldRepresentative_zero t theta) + · intro f hf g hg hfg + rw [kerdockFieldRepresentativeFamily] at hf hg + obtain ⟨u, _huMem, rfl⟩ := Finset.mem_image.mp hf + obtain ⟨v, _hvMem, rfl⟩ := Finset.mem_image.mp hg + apply isBent_kerdockFieldRepresentative_add t theta u v + intro huv + subst v + exact hfg rfl + · rw [card_kerdockFieldRepresentativeFamily] + congr 1 + +/-- The explicit field representatives and their first-order coset union +have the Kerdock parameters. -/ +theorem kerdockFieldConstruction_parameters + (t : ℕ) + (theta : FABL.F₂Cube (2 * t + 1) ≃ₗ[FABL.𝔽₂] + BinaryGaloisField (2 * t + 1)) : + let F := kerdockFieldRepresentativeFamily t theta + IsKerdockRepresentativeFamily F ∧ + F.offDiag.Nonempty ∧ + HasDistinctFirstOrderCosets F ∧ + (∀ c : BooleanFunction ((2 * t + 1) + 1), + c ∈ reedMuller 1 ((2 * t + 1) + 1) → + c ∈ kerdockCodeOfRepresentatives F) ∧ + (∀ c : BooleanFunction ((2 * t + 1) + 1), + c ∈ kerdockCodeOfRepresentatives F → + c ∈ reedMuller 2 ((2 * t + 1) + 1)) ∧ + (kerdockCodeOfRepresentatives F).card = + 2 ^ (2 * ((2 * t + 1) + 1)) ∧ + minimumHammingDistance (kerdockCodeOfRepresentatives F) = + 2 ^ (((2 * t + 1) + 1) - 1) - + 2 ^ (((2 * t + 1) + 1) / 2 - 1) := by + dsimp only + have hF := isKerdockRepresentativeFamily_kerdockField t theta + refine ⟨hF, ?_⟩ + exact kerdockCodeOfRepresentatives_parameters hF + ⟨t + 1, by omega⟩ (by omega) + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/MaioranaMcFarland.lean b/CryptBoolean/Carlet/Chapter06/MaioranaMcFarland.lean new file mode 100644 index 0000000..eba6e28 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/MaioranaMcFarland.lean @@ -0,0 +1,128 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.Dual +public import CryptBoolean.Carlet.Chapter05.Affine +public import FABL.Chapter06.Constructions.MaioranaMcFarlandPermutation + +/-! +# Carlet Chapter 6 Maiorana--McFarland construction + +The original Maiorana--McFarland construction and its exact raw Walsh spectrum. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The original permutation construction belongs to the Maiorana--McFarland +class introduced in Chapter 5. -/ +theorem isMaioranaMcFarland_of_eq_permutation + (f : BooleanFunction (n + n)) (g : BooleanFunction n) + (π : Equiv.Perm (FABL.F₂Cube n)) + (hf : ∀ x y : FABL.F₂Cube n, + f (FABL.joinF₂CubeBlocks x y) = + FABL.f₂DotProduct x (π y) + g y) : + IsMaioranaMcFarland f := by + intro y + refine ⟨g y, π y, fun x ↦ ?_⟩ + change f (FABL.joinF₂CubeBlocks x y) = _ + rw [hf] + have hdot : FABL.f₂DotProduct x (π y) = + FABL.f₂DotProduct (π y) x := by + exact dotProduct_comm x (π y) + rw [FABL.affineFunction, hdot, add_comm] + +private theorem realSignView_eq_maioranaMcFarlandPermutation + (f : BooleanFunction (n + n)) (g : BooleanFunction n) + (π : Equiv.Perm (FABL.F₂Cube n)) + (hf : ∀ x y : FABL.F₂Cube n, + f (FABL.joinF₂CubeBlocks x y) = + FABL.f₂DotProduct x (π y) + g y) : + realSignView f = + FABL.maioranaMcFarlandPermutation π (fun y ↦ FABL.signEncode (g y)) := by + funext z + let x := (FABL.f₂CubeBlockEquiv n z).1 + let y := (FABL.f₂CubeBlockEquiv n z).2 + have hz : FABL.joinF₂CubeBlocks x y = z := + (FABL.f₂CubeBlockEquiv n).symm_apply_apply z + rw [← hz, FABL.maioranaMcFarlandPermutation_joinF₂CubeBlocks] + change FABL.signValue + (FABL.signEncode (f (FABL.joinF₂CubeBlocks x y))) = _ + rw [hf, + FABL.signValue_signEncode_eq_binarySign, + FABL.signValue_signEncode_eq_binarySign, + AddChar.map_add_eq_mul] + +/-- Carlet relation (48): the exact raw Walsh transform of the original +Maiorana--McFarland construction. -/ +theorem walshTransform_maioranaMcFarlandPermutation + (f : BooleanFunction (n + n)) (g : BooleanFunction n) + (π : Equiv.Perm (FABL.F₂Cube n)) + (hf : ∀ x y : FABL.F₂Cube n, + f (FABL.joinF₂CubeBlocks x y) = + FABL.f₂DotProduct x (π y) + g y) + (a b : FABL.F₂Cube n) : + walshTransform f (FABL.joinF₂CubeBlocks a b) = + bitSignInt (g (π.symm a) + FABL.f₂DotProduct b (π.symm a)) * + (2 ^ n : ℤ) := by + apply Int.cast_injective (α := ℝ) + rw [walshTransform_eq_two_pow_mul_vectorFourierCoeff, + realSignView_eq_maioranaMcFarlandPermutation f g π hf, + FABL.vectorFourierCoeff_maioranaMcFarlandPermutation_joinF₂CubeBlocks] + push_cast + rw [ + bitSignInt_cast, FABL.signValue_signEncode_eq_binarySign, + FABL.vectorWalshCharacter_apply] + rw [AddChar.map_add_eq_mul] + norm_num [pow_add] + field_simp + +/-- Every Boolean function satisfying Carlet relation (48) is bent. -/ +theorem isBent_of_maioranaMcFarlandPermutation + (f : BooleanFunction (n + n)) (g : BooleanFunction n) + (π : Equiv.Perm (FABL.F₂Cube n)) + (hf : ∀ x y : FABL.F₂Cube n, + f (FABL.joinF₂CubeBlocks x y) = + FABL.f₂DotProduct x (π y) + g y) : + IsBent f := by + change FABL.IsBent (realSignView f) + rw [realSignView_eq_maioranaMcFarlandPermutation f g π hf] + exact FABL.isBent_maioranaMcFarlandPermutation π + (fun y ↦ FABL.signEncode (g y)) + +/-- The dual of the original Maiorana--McFarland construction is obtained by +applying the inverse permutation to the first frequency block. -/ +theorem bentDual_maioranaMcFarlandPermutation + (f : BooleanFunction (n + n)) (g : BooleanFunction n) + (π : Equiv.Perm (FABL.F₂Cube n)) + (hf : ∀ x y : FABL.F₂Cube n, + f (FABL.joinF₂CubeBlocks x y) = + FABL.f₂DotProduct x (π y) + g y) + (a b : FABL.F₂Cube n) : + bentDual f (FABL.joinF₂CubeBlocks a b) = + FABL.f₂DotProduct b (π.symm a) + g (π.symm a) := by + have hbent := isBent_of_maioranaMcFarlandPermutation f g π hf + have hdual := walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + f hbent (FABL.joinF₂CubeBlocks a b) + have hspectrum := walshTransform_maioranaMcFarlandPermutation + f g π hf a b + have hhalf : (n + n) / 2 = n := by omega + rw [hhalf, hspectrum] at hdual + have hsign : + bitSignInt (bentDual f (FABL.joinF₂CubeBlocks a b)) = + bitSignInt + (FABL.f₂DotProduct b (π.symm a) + g (π.symm a)) := by + apply mul_right_cancel₀ (by positivity : (2 ^ n : ℤ) ≠ 0) + simpa [add_comm, mul_comm] using hdual.symm + exact bitSignInt_injective hsign + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/MaioranaMcFarlandCounting.lean b/CryptBoolean/Carlet/Chapter06/MaioranaMcFarlandCounting.lean new file mode 100644 index 0000000..d003eb9 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/MaioranaMcFarlandCounting.lean @@ -0,0 +1,173 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.DegreeBounds +public import CryptBoolean.Carlet.Chapter06.MaioranaMcFarland + +/-! +# Counting Maiorana--McFarland and bent functions + +The exact size of the original Maiorana--McFarland class and Carlet's naive +upper bound for the total number of bent functions. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {m n : ℕ} + +noncomputable local instance countingReedMullerFintype + (r n : ℕ) : Fintype (reedMuller r n) := + Fintype.ofFinite (reedMuller r n) + +/-- The permutation and Boolean offset parameters of the original +Maiorana--McFarland construction. -/ +abbrev MaioranaMcFarlandParameters (m : ℕ) := + Equiv.Perm (FABL.F₂Cube m) × BooleanFunction m + +/-- The Boolean-valued original Maiorana--McFarland function associated to a +permutation and an arbitrary Boolean offset. -/ +def booleanMaioranaMcFarlandPermutation + (π : Equiv.Perm (FABL.F₂Cube m)) (g : BooleanFunction m) : + BooleanFunction (m + m) := + fun z ↦ + let blocks := FABL.f₂CubeBlockEquiv m z + FABL.f₂DotProduct blocks.1 (π blocks.2) + g blocks.2 + +/-- Evaluation of the Boolean Maiorana--McFarland function on its two +coordinate blocks. -/ +@[simp] theorem booleanMaioranaMcFarlandPermutation_joinF₂CubeBlocks + (π : Equiv.Perm (FABL.F₂Cube m)) (g : BooleanFunction m) + (x y : FABL.F₂Cube m) : + booleanMaioranaMcFarlandPermutation π g + (FABL.joinF₂CubeBlocks x y) = + FABL.f₂DotProduct x (π y) + g y := by + simp [booleanMaioranaMcFarlandPermutation] + +/-- The Boolean function determined by a Maiorana--McFarland parameter +pair. -/ +def booleanMaioranaMcFarlandOfParameters + (p : MaioranaMcFarlandParameters m) : BooleanFunction (m + m) := + booleanMaioranaMcFarlandPermutation p.1 p.2 + +/-- The original Maiorana--McFarland parameterization is injective. -/ +theorem booleanMaioranaMcFarlandOfParameters_injective : + Function.Injective + (booleanMaioranaMcFarlandOfParameters (m := m)) := by + rintro ⟨π, g⟩ ⟨σ, h⟩ heq + have hoffset : g = h := by + funext y + have hy := congrFun heq + (FABL.joinF₂CubeBlocks (0 : FABL.F₂Cube m) y) + simpa [booleanMaioranaMcFarlandOfParameters, FABL.f₂DotProduct, + zero_dotProduct] using hy + have hperm : π = σ := by + apply Equiv.ext + intro y + funext i + have hi := congrFun heq + (FABL.joinF₂CubeBlocks + (Pi.single i (1 : FABL.𝔽₂)) y) + rw [booleanMaioranaMcFarlandOfParameters, + booleanMaioranaMcFarlandOfParameters, + booleanMaioranaMcFarlandPermutation_joinF₂CubeBlocks, + booleanMaioranaMcFarlandPermutation_joinF₂CubeBlocks, + hoffset] at hi + simpa [FABL.f₂DotProduct, single_dotProduct] using + (add_right_cancel hi) + exact Prod.ext hperm hoffset + +/-- The original parameter space has +`(2^m)! * 2^(2^m)` elements. -/ +theorem card_maioranaMcFarlandParameters (m : ℕ) : + Fintype.card (MaioranaMcFarlandParameters m) = + (2 ^ m).factorial * 2 ^ (2 ^ m) := by + rw [Fintype.card_prod, Fintype.card_perm, Fintype.card_fun] + norm_num [Fintype.card_pi, Fintype.card_fin, BooleanFunction] + +/-- The finite set of distinct functions in the original +Maiorana--McFarland class. -/ +noncomputable def originalMaioranaMcFarlandClass (m : ℕ) : + Finset (BooleanFunction (m + m)) := by + classical + exact Finset.univ.image booleanMaioranaMcFarlandOfParameters + +/-- The original Maiorana--McFarland class contains exactly +`(2^m)! * 2^(2^m)` distinct functions. -/ +theorem card_originalMaioranaMcFarlandClass (m : ℕ) : + (originalMaioranaMcFarlandClass m).card = + (2 ^ m).factorial * 2 ^ (2 ^ m) := by + classical + rw [originalMaioranaMcFarlandClass, + Finset.card_image_of_injective] + · rw [Finset.card_univ, card_maioranaMcFarlandParameters] + · exact booleanMaioranaMcFarlandOfParameters_injective + +/-- Every Boolean-valued original Maiorana--McFarland function is bent. -/ +theorem isBent_booleanMaioranaMcFarlandPermutation + (π : Equiv.Perm (FABL.F₂Cube m)) (g : BooleanFunction m) : + IsBent (booleanMaioranaMcFarlandPermutation π g) := by + apply isBent_of_maioranaMcFarlandPermutation + (booleanMaioranaMcFarlandPermutation π g) g π + intro x y + exact booleanMaioranaMcFarlandPermutation_joinF₂CubeBlocks π g x y + +/-- The finite family of all `n`-variable bent Boolean functions. -/ +noncomputable def bentFunctionFamily (n : ℕ) : + Finset (BooleanFunction n) := by + classical + exact Finset.univ.filter IsBent + +@[simp] theorem mem_bentFunctionFamily_iff + {f : BooleanFunction n} : + f ∈ bentFunctionFamily n ↔ IsBent f := by + classical + simp [bentFunctionFamily] + +/-- The original Maiorana--McFarland class is a family of bent functions. -/ +theorem originalMaioranaMcFarlandClass_subset_bentFunctionFamily (m : ℕ) : + originalMaioranaMcFarlandClass m ⊆ bentFunctionFamily (m + m) := by + classical + intro f hf + rw [originalMaioranaMcFarlandClass, Finset.mem_image] at hf + obtain ⟨p, _hp, rfl⟩ := hf + rw [mem_bentFunctionFamily_iff] + exact isBent_booleanMaioranaMcFarlandPermutation p.1 p.2 + +/-- Carlet's naive bound: in even dimension at least four, the number of +bent functions is at most the number of Boolean functions of degree at most +half the dimension. -/ +theorem card_bentFunctionFamily_le_naiveBound + (_hnEven : Even n) (hn : 4 ≤ n) : + (bentFunctionFamily n).card ≤ + 2 ^ (∑ i ∈ Finset.range (n / 2 + 1), Nat.choose n i) := by + classical + let lowDegreeFunctions : Finset (BooleanFunction n) := + (Finset.univ : Finset (reedMuller (n / 2) n)).image + (fun f ↦ f.1) + have hsubset : bentFunctionFamily n ⊆ lowDegreeFunctions := by + intro f hf + rw [mem_bentFunctionFamily_iff] at hf + simp only [lowDegreeFunctions, Finset.mem_image] + refine ⟨⟨f, ?_⟩, Finset.mem_univ _, rfl⟩ + exact functionAlgebraicDegree_le_half_of_isBent f hf hn + calc + (bentFunctionFamily n).card ≤ lowDegreeFunctions.card := + Finset.card_le_card hsubset + _ = Nat.card (reedMuller (n / 2) n) := by + simp only [lowDegreeFunctions] + rw [Finset.card_image_of_injective] + · rw [Finset.card_univ, ← Nat.card_eq_fintype_card] + · exact Subtype.val_injective + _ = 2 ^ (∑ i ∈ Finset.range (n / 2 + 1), Nat.choose n i) := + reedMuller_card + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/MaioranaMcFarlandGeneral.lean b/CryptBoolean/Carlet/Chapter06/MaioranaMcFarlandGeneral.lean new file mode 100644 index 0000000..45f7ad8 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/MaioranaMcFarlandGeneral.lean @@ -0,0 +1,309 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.Bentness +public import CryptBoolean.Carlet.Chapter06.MaioranaMcFarland + +/-! +# General Maiorana--McFarland functions + +Carlet relation (49) and its exact bentness criterion for unequal coordinate +blocks. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n r s : ℕ} + +/-- The signed character sum over a fiber in the general +Maiorana--McFarland construction. -/ +def maioranaMcFarlandFiberCharacterSum + (φ : FABL.F₂Cube s → FABL.F₂Cube r) + (g : BooleanFunction s) + (a : FABL.F₂Cube r) (b : FABL.F₂Cube s) : ℤ := + ∑ y with φ y = a, bitSignInt (g y + FABL.f₂DotProduct b y) + +/-- Carlet relation (49): the raw Walsh coefficient of a general +Maiorana--McFarland function is the corresponding fiber character sum +multiplied by the size of the first coordinate block. -/ +theorem walshTransform_maioranaMcFarlandGeneral + (f : BooleanFunction (r + s)) + (φ : FABL.F₂Cube s → FABL.F₂Cube r) + (g : BooleanFunction s) + (hf : ∀ x y, + f (Fin.append x y) = FABL.f₂DotProduct x (φ y) + g y) + (a : FABL.F₂Cube r) (b : FABL.F₂Cube s) : + walshTransform f (Fin.append a b) = + (2 ^ r : ℤ) * maioranaMcFarlandFiberCharacterSum φ g a b := by + classical + rw [walshTransform] + calc + ∑ z : FABL.F₂Cube (r + s), walshTerm f (Fin.append a b) z = + ∑ p : FABL.F₂Cube r × FABL.F₂Cube s, + walshTerm f (Fin.append a b) (Fin.append p.1 p.2) := by + exact (Fintype.sum_equiv (Fin.appendEquiv r s) + (fun p ↦ walshTerm f (Fin.append a b) (Fin.append p.1 p.2)) + (fun z ↦ walshTerm f (Fin.append a b) z) + (fun _ ↦ rfl)).symm + _ = ∑ x : FABL.F₂Cube r, ∑ y : FABL.F₂Cube s, + bitSignInt + (FABL.f₂DotProduct x (φ y) + g y + + (FABL.f₂DotProduct a x + FABL.f₂DotProduct b y)) := by + rw [Fintype.sum_prod_type] + apply Finset.sum_congr rfl + intro x _hx + apply Finset.sum_congr rfl + intro y _hy + simp only [walshTerm, hf, FABL.f₂DotProduct_append] + _ = ∑ y : FABL.F₂Cube s, ∑ x : FABL.F₂Cube r, + bitSignInt + (FABL.f₂DotProduct x (φ y) + g y + + (FABL.f₂DotProduct a x + FABL.f₂DotProduct b y)) := by + rw [Finset.sum_comm] + _ = ∑ y : FABL.F₂Cube s, + walshTransform + (FABL.affineFunction + (g y + FABL.f₂DotProduct b y) (φ y)) a := by + apply Finset.sum_congr rfl + intro y _hy + rw [walshTransform] + apply Finset.sum_congr rfl + intro x _hx + simp only [walshTerm, FABL.affineFunction] + congr 1 + rw [show FABL.f₂DotProduct x (φ y) = + FABL.f₂DotProduct (φ y) x by + exact dotProduct_comm x (φ y)] + abel + _ = ∑ y : FABL.F₂Cube s, + if a = φ y then + bitSignInt (g y + FABL.f₂DotProduct b y) * (2 ^ r : ℤ) + else 0 := by + apply Finset.sum_congr rfl + intro y _hy + rw [walshTransform_affineFunction] + _ = (2 ^ r : ℤ) * maioranaMcFarlandFiberCharacterSum φ g a b := by + rw [maioranaMcFarlandFiberCharacterSum, Finset.mul_sum] + rw [Finset.sum_filter] + apply Finset.sum_congr rfl + intro y _hy + by_cases hy : φ y = a + · simp [hy, mul_comm] + · simp [hy, Ne.symm hy] + +/-- Under the source's even-dimension hypothesis, a general +Maiorana--McFarland function is bent exactly when the first block fits within +half the dimension and every fiber character sum has the stated magnitude. -/ +theorem isBent_iff_maioranaMcFarlandFiberCharacterSum_natAbs + (f : BooleanFunction (r + s)) + (φ : FABL.F₂Cube s → FABL.F₂Cube r) + (g : BooleanFunction s) + (hf : ∀ x y, + f (Fin.append x y) = FABL.f₂DotProduct x (φ y) + g y) + (_heven : Even (r + s)) : + IsBent f ↔ + r ≤ (r + s) / 2 ∧ + ∀ a b, + (maioranaMcFarlandFiberCharacterSum φ g a b).natAbs = + 2 ^ ((r + s) / 2 - r) := by + constructor + · intro hbent + have hmag (a : FABL.F₂Cube r) (b : FABL.F₂Cube s) : + 2 ^ r * (maioranaMcFarlandFiberCharacterSum φ g a b).natAbs = + 2 ^ ((r + s) / 2) := by + have h := natAbs_walshTransform_eq_two_pow_half_of_isBent + f hbent (Fin.append a b) + rw [walshTransform_maioranaMcFarlandGeneral f φ g hf a b, + Int.natAbs_mul] at h + simpa using h + have hzero := hmag (0 : FABL.F₂Cube r) (0 : FABL.F₂Cube s) + have hsumNe : + (maioranaMcFarlandFiberCharacterSum φ g + (0 : FABL.F₂Cube r) (0 : FABL.F₂Cube s)).natAbs ≠ 0 := by + intro hsumZero + rw [hsumZero, mul_zero] at hzero + exact (pow_ne_zero _ (by norm_num : (2 : ℕ) ≠ 0)) hzero.symm + have hpowers : 2 ^ r ≤ 2 ^ ((r + s) / 2) := by + calc + 2 ^ r = 2 ^ r * 1 := by rw [mul_one] + _ ≤ 2 ^ r * + (maioranaMcFarlandFiberCharacterSum φ g + (0 : FABL.F₂Cube r) (0 : FABL.F₂Cube s)).natAbs := + Nat.mul_le_mul_left _ (Nat.one_le_iff_ne_zero.mpr hsumNe) + _ = 2 ^ ((r + s) / 2) := hzero + have hle : r ≤ (r + s) / 2 := + (Nat.pow_le_pow_iff_right (by omega : 1 < (2 : ℕ))).mp hpowers + refine ⟨hle, ?_⟩ + intro a b + apply Nat.mul_left_cancel (pow_pos (by omega : 0 < (2 : ℕ)) r) + calc + 2 ^ r * (maioranaMcFarlandFiberCharacterSum φ g a b).natAbs = + 2 ^ ((r + s) / 2) := hmag a b + _ = 2 ^ r * 2 ^ ((r + s) / 2 - r) := by + rw [← pow_add, Nat.add_sub_of_le hle] + · rintro ⟨hle, hmag⟩ + apply (isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half f).mpr + intro u + let p := (Fin.appendEquiv r s).symm u + have hu : Fin.append p.1 p.2 = u := + (Fin.appendEquiv r s).apply_symm_apply u + rw [← hu, + walshTransform_maioranaMcFarlandGeneral f φ g hf p.1 p.2, + Int.natAbs_mul] + have htwo : Int.natAbs (2 : ℤ) = 2 := by norm_num + rw [Int.natAbs_pow, htwo] + rw [hmag, ← pow_add, Nat.add_sub_of_le hle] + +/-- For equal coordinate blocks, bijectivity of the frequency map is both +necessary and sufficient for the Maiorana--McFarland function to be bent. -/ +theorem isBent_iff_bijective_maioranaMcFarland + (f : BooleanFunction (n + n)) + (φ : FABL.F₂Cube n → FABL.F₂Cube n) + (g : BooleanFunction n) + (hf : ∀ x y, + f (Fin.append x y) = FABL.f₂DotProduct x (φ y) + g y) : + IsBent f ↔ Function.Bijective φ := by + constructor + · intro hbent + have hcriterion := + (isBent_iff_maioranaMcFarlandFiberCharacterSum_natAbs + f φ g hf (by exact ⟨n, rfl⟩)).1 hbent + have hsurjective : Function.Surjective φ := by + intro a + have hmag := hcriterion.2 a (0 : FABL.F₂Cube n) + have hexponent : (n + n) / 2 - n = 0 := by omega + rw [hexponent, pow_zero] at hmag + by_contra hpreimage + have hnone : ∀ y, φ y ≠ a := by + intro y hy + exact hpreimage ⟨y, hy⟩ + have hzero : maioranaMcFarlandFiberCharacterSum φ g a 0 = 0 := by + rw [maioranaMcFarlandFiberCharacterSum] + simp [hnone] + rw [hzero] at hmag + norm_num at hmag + exact (Fintype.bijective_iff_surjective_and_card φ).2 + ⟨hsurjective, rfl⟩ + · intro hbijective + let π : Equiv.Perm (FABL.F₂Cube n) := Equiv.ofBijective φ hbijective + apply isBent_of_maioranaMcFarlandPermutation f g π + intro x y + exact hf x y + +private theorem maioranaMcFarlandFiberCharacterSum_eq_affineFiberWalshZero + (φ : FABL.F₂Cube s → FABL.F₂Cube r) + (g : BooleanFunction s) + (a : FABL.F₂Cube r) (b : FABL.F₂Cube s) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube s)) + (z : FABL.F₂Cube s) + (e : FABL.F₂Cube (s - r) ≃ₗ[FABL.𝔽₂] E) + (hfiber : ∀ y, φ y = a ↔ + ∃ x, y = (e x).1 + z) : + maioranaMcFarlandFiberCharacterSum φ g a b = + walshTransform + (coordinateAffineSubspaceRestriction + (g + FABL.affineFunction 0 b) E z e) 0 := by + classical + rw [maioranaMcFarlandFiberCharacterSum, walshTransform] + symm + apply Finset.sum_bij + (fun x (_ : x ∈ (Finset.univ : Finset (FABL.F₂Cube (s - r)))) ↦ + (e x).1 + z) + · intro x _hx + rw [Finset.mem_filter] + exact ⟨Finset.mem_univ _, (hfiber _).mpr ⟨x, rfl⟩⟩ + · intro x₁ _hx₁ x₂ _hx₂ hpoint + apply e.injective + apply Subtype.ext + exact add_right_cancel hpoint + · intro y hy + obtain ⟨x, hx⟩ := (hfiber y).mp (Finset.mem_filter.mp hy).2 + exact ⟨x, Finset.mem_univ _, hx.symm⟩ + · intro x _hx + simp [walshTerm_zero, coordinateAffineSubspaceRestriction_apply, + FABL.affineFunction] + +private theorem isBent_affineFiberRestriction_add_linear + (g : BooleanFunction s) (b z : FABL.F₂Cube s) + (E : Submodule FABL.𝔽₂ (FABL.F₂Cube s)) + (e : FABL.F₂Cube (s - r) ≃ₗ[FABL.𝔽₂] E) + (hbent : IsBent (coordinateAffineSubspaceRestriction g E z e)) : + IsBent + (coordinateAffineSubspaceRestriction + (g + FABL.affineFunction 0 b) E z e) := by + let h := coordinateAffineSubspaceRestriction g E z e + have heq : + coordinateAffineSubspaceRestriction + (g + FABL.affineFunction 0 b) E z e = + h + FABL.affineFunction (FABL.affineFunction 0 b z) + (coordinateRestrictedAffineFrequency E e b) := by + funext x + simp only [h, coordinateAffineSubspaceRestriction_apply, Pi.add_apply] + rw [show (e x).1 + z = z + (e x).1 by abel] + rw [affineFunction_coordinateAffineSubspaceRestriction + E e z b 0 x] + rw [heq, isBent_add_affineFunction_iff] + exact hbent + +/-- Carlet Proposition 20: if the fibers of `φ` are affine subspaces of +dimension `s - r` and the restrictions of `g` to the positive-dimensional +fibers are bent, then the associated general Maiorana--McFarland function is +bent. -/ +theorem isBent_maioranaMcFarlandGeneral_of_affineFibers + (f : BooleanFunction (r + s)) + (φ : FABL.F₂Cube s → FABL.F₂Cube r) + (g : BooleanFunction s) + (hf : ∀ x y, + f (Fin.append x y) = FABL.f₂DotProduct x (φ y) + g y) + (hrle : r ≤ s) (heven : Even (r + s)) + (E : FABL.F₂Cube r → Submodule FABL.𝔽₂ (FABL.F₂Cube s)) + (z : FABL.F₂Cube r → FABL.F₂Cube s) + (e : ∀ a, FABL.F₂Cube (s - r) ≃ₗ[FABL.𝔽₂] E a) + (hfiber : ∀ a y, φ y = a ↔ + ∃ x, y = (e a x).1 + z a) + (hbent : r < s → ∀ a, + IsBent (coordinateAffineSubspaceRestriction g (E a) (z a) (e a))) : + IsBent f := by + have hle : r ≤ (r + s) / 2 := by omega + have hexponent : (s - r) / 2 = (r + s) / 2 - r := by + rcases heven with ⟨k, hk⟩ + omega + apply (isBent_iff_maioranaMcFarlandFiberCharacterSum_natAbs + f φ g hf heven).mpr + refine ⟨hle, ?_⟩ + intro a b + have hrestriction : + IsBent (coordinateAffineSubspaceRestriction g (E a) (z a) (e a)) := by + by_cases hrs : r < s + · exact hbent hrs a + · apply (isBent_iff_forall_nonzero_derivative_isBalanced _).mpr + intro d hd + exfalso + apply hd + funext i + have hi := i.isLt + omega + have hlinear := isBent_affineFiberRestriction_add_linear + g b (z a) (E a) (e a) hrestriction + calc + (maioranaMcFarlandFiberCharacterSum φ g a b).natAbs = + (walshTransform + (coordinateAffineSubspaceRestriction + (g + FABL.affineFunction 0 b) (E a) (z a) (e a)) 0).natAbs := + congrArg Int.natAbs + (maioranaMcFarlandFiberCharacterSum_eq_affineFiberWalshZero + φ g a b (E a) (z a) (e a) (hfiber a)) + _ = 2 ^ ((s - r) / 2) := + natAbs_walshTransform_eq_two_pow_half_of_isBent _ hlinear 0 + _ = 2 ^ ((r + s) / 2 - r) := by rw [hexponent] + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/McElieceAx.lean b/CryptBoolean/Carlet/Chapter06/McElieceAx.lean new file mode 100644 index 0000000..2268ffb --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/McElieceAx.lean @@ -0,0 +1,218 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter05.CoveringSequences +public import FABL.Chapter06.F₂Polynomials.AlgebraicDegree + +/-! +# McEliece--Ax divisibility for Boolean character sums + +The character sum of a positive-degree Boolean polynomial in `n` variables +is divisible by the power of two whose exponent is the ceiling of `n` by +the algebraic degree. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +private theorem bitSignInt_finset_sum {α : Type*} + (s : Finset α) (g : α → FABL.𝔽₂) : + bitSignInt (∑ i ∈ s, g i) = ∏ i ∈ s, bitSignInt (g i) := by + classical + induction s using Finset.induction_on with + | empty => simp [bitSignInt] + | @insert a s ha ih => + rw [Finset.sum_insert ha, Finset.prod_insert ha, bitSignInt_add, ih] + +private theorem bitSignInt_anfEval_eq_prod + (c : FABL.ANFCoefficients n) (x : FABL.F₂Cube n) : + bitSignInt (FABL.anfEval c x) = + ∏ S ∈ FABL.anfSupport c, bitSignInt (FABL.anfMonomial S x) := by + classical + rw [FABL.anfEval] + have hsum : + (∑ S : Finset (Fin n), c S * FABL.anfMonomial S x) = + ∑ S ∈ FABL.anfSupport c, FABL.anfMonomial S x := by + rw [FABL.anfSupport, Finset.sum_filter] + apply Finset.sum_congr rfl + intro S _hS + by_cases hc : c S = 0 + · simp [hc] + · have hcOne : c S = 1 := Fin.eq_one_of_ne_zero (c S) hc + simp [hcOne] + rw [hsum, bitSignInt_finset_sum] + +private theorem bitSignInt_anfEval_eq_powersetSum + (c : FABL.ANFCoefficients n) (x : FABL.F₂Cube n) : + bitSignInt (FABL.anfEval c x) = + ∑ B ∈ (FABL.anfSupport c).powerset, + (-2 : ℤ) ^ B.card * + ∏ S ∈ B, bitValueInt (FABL.anfMonomial S x) := by + classical + rw [bitSignInt_anfEval_eq_prod] + simp_rw [bitSignInt_eq_one_sub_two_mul_bitValueInt] + conv_lhs => + enter [2, S] + rw [show 1 - 2 * bitValueInt (FABL.anfMonomial S x) = + 1 + (-2) * bitValueInt (FABL.anfMonomial S x) by ring] + rw [Finset.prod_one_add] + apply Finset.sum_congr rfl + intro B _hB + rw [Finset.prod_mul_distrib, Finset.prod_const] + +private theorem prod_bitValueInt_anfMonomial_f₂CubeOfFinset + (B : Finset (Finset (Fin n))) (U : Finset (Fin n)) : + (∏ S ∈ B, + bitValueInt (FABL.anfMonomial S (FABL.f₂CubeOfFinset U))) = + if B.biUnion id ⊆ U then 1 else 0 := by + classical + simp_rw [FABL.anfMonomial_f₂CubeOfFinset] + have hbit (T : Finset (Fin n)) : + bitValueInt (if T ⊆ U then 1 else 0) = + if T ⊆ U then 1 else 0 := by + by_cases hT : T ⊆ U <;> simp [hT, bitValueInt] + simp_rw [hbit] + rw [Finset.prod_boole] + by_cases hU : B.biUnion id ⊆ U + · rw [if_pos hU, if_pos] + exact Finset.biUnion_subset.mp hU + · rw [if_neg hU, if_neg] + intro hAll + exact hU (Finset.biUnion_subset.mpr hAll) + +private theorem sum_prod_bitValueInt_anfMonomial + (B : Finset (Finset (Fin n))) : + (∑ x : FABL.F₂Cube n, + ∏ S ∈ B, bitValueInt (FABL.anfMonomial S x)) = + (2 : ℤ) ^ (n - (B.biUnion id).card) := by + classical + calc + (∑ x : FABL.F₂Cube n, + ∏ S ∈ B, bitValueInt (FABL.anfMonomial S x)) = + ∑ U : Finset (Fin n), + ∏ S ∈ B, + bitValueInt (FABL.anfMonomial S (FABL.f₂CubeOfFinset U)) := by + apply Fintype.sum_equiv (FABL.f₂CubeEquivFinset n) + intro x + have hx : FABL.f₂CubeOfFinset (FABL.f₂Support x) = x := by + simpa using (FABL.f₂CubeEquivFinset n).symm_apply_apply x + simp only [FABL.f₂CubeEquivFinset_apply, hx] + _ = ∑ U : Finset (Fin n), + if B.biUnion id ⊆ U then 1 else 0 := by + apply Finset.sum_congr rfl + intro U _hU + exact prod_bitValueInt_anfMonomial_f₂CubeOfFinset B U + _ = ((Finset.Icc (B.biUnion id) Finset.univ).card : ℤ) := by + rw [Finset.sum_boole] + have hfilter : + Finset.univ.filter (fun U : Finset (Fin n) ↦ B.biUnion id ⊆ U) = + Finset.Icc (B.biUnion id) Finset.univ := by + ext U + simp [Finset.mem_Icc] + rw [hfilter] + _ = (2 : ℤ) ^ (n - (B.biUnion id).card) := by + rw [Finset.card_Icc_finset (Finset.subset_univ _)] + simp + +private theorem ceilDiv_le_card_add_codim_biUnion + (B : Finset (Finset (Fin n))) (d : ℕ) (hd : 0 < d) + (hcard : ∀ S ∈ B, S.card ≤ d) : + n ⌈/⌉ d ≤ B.card + (n - (B.biUnion id).card) := by + classical + let u := (B.biUnion id).card + let k := B.card + have hu : u ≤ n := by + dsimp [u] + simpa using Finset.card_le_univ (B.biUnion id) + have hud : u ≤ d * k := by + dsimp [u, k] + simpa [Nat.mul_comm] using + (Finset.card_biUnion_le_card_mul B id d hcard) + rw [ceilDiv_le_iff_le_mul hd] + calc + n = u + (n - u) := (Nat.add_sub_of_le hu).symm + _ ≤ d * k + d * (n - u) := Nat.add_le_add hud (by + simpa using Nat.mul_le_mul_right (n - u) + (Nat.one_le_iff_ne_zero.mpr hd.ne')) + _ = d * (k + (n - u)) := by ring + +private theorem two_pow_ceilDiv_dvd_powersetTerm + (B : Finset (Finset (Fin n))) (d : ℕ) (hd : 0 < d) + (hcard : ∀ S ∈ B, S.card ≤ d) : + (2 : ℤ) ^ (n ⌈/⌉ d) ∣ + (-2 : ℤ) ^ B.card * (2 : ℤ) ^ (n - (B.biUnion id).card) := by + classical + have hexponent := ceilDiv_le_card_add_codim_biUnion B d hd hcard + apply (pow_dvd_pow (2 : ℤ) hexponent).trans + refine ⟨(-1 : ℤ) ^ B.card, ?_⟩ + rw [pow_add] + calc + (-2 : ℤ) ^ B.card * (2 : ℤ) ^ (n - (B.biUnion id).card) = + ((-1 : ℤ) ^ B.card * (2 : ℤ) ^ B.card) * + (2 : ℤ) ^ (n - (B.biUnion id).card) := by + rw [← mul_pow] + norm_num + _ = ((2 : ℤ) ^ B.card * + (2 : ℤ) ^ (n - (B.biUnion id).card)) * + (-1 : ℤ) ^ B.card := by ring + +/-- The McEliece--Ax divisibility exponent for a positive-degree Boolean +function: its zero-frequency character sum is divisible by +`2 ^ ⌈n / d⌉` whenever its algebraic degree is at most `d`. -/ +theorem two_pow_ceilDiv_dvd_booleanCharacterSum_of_degree_le + (f : BooleanFunction n) (d : ℕ) (hd : 0 < d) + (hdegree : FABL.functionAlgebraicDegree f ≤ d) : + (2 : ℤ) ^ (n ⌈/⌉ d) ∣ ∑ x, bitSignInt (f x) := by + classical + let A := FABL.anfSupport (FABL.anfCoeff f) + have hsum : + (∑ x, bitSignInt (f x)) = + ∑ B ∈ A.powerset, + (-2 : ℤ) ^ B.card * + (2 : ℤ) ^ (n - (B.biUnion id).card) := by + calc + (∑ x, bitSignInt (f x)) = + ∑ x, bitSignInt (FABL.anfEval (FABL.anfCoeff f) x) := by + apply Finset.sum_congr rfl + intro x _hx + rw [congrFun (FABL.anfEval_anfCoeff f) x] + _ = ∑ x, ∑ B ∈ A.powerset, + (-2 : ℤ) ^ B.card * + ∏ S ∈ B, bitValueInt (FABL.anfMonomial S x) := by + apply Finset.sum_congr rfl + intro x _hx + exact bitSignInt_anfEval_eq_powersetSum (FABL.anfCoeff f) x + _ = ∑ B ∈ A.powerset, + (-2 : ℤ) ^ B.card * + ∑ x, ∏ S ∈ B, + bitValueInt (FABL.anfMonomial S x) := by + rw [Finset.sum_comm] + apply Finset.sum_congr rfl + intro B _hB + rw [Finset.mul_sum] + _ = ∑ B ∈ A.powerset, + (-2 : ℤ) ^ B.card * + (2 : ℤ) ^ (n - (B.biUnion id).card) := by + apply Finset.sum_congr rfl + intro B _hB + rw [sum_prod_bitValueInt_anfMonomial B] + rw [hsum] + apply Finset.dvd_sum + intro B hB + apply two_pow_ceilDiv_dvd_powersetTerm B d hd + intro S hSB + have hSA : S ∈ A := (Finset.mem_powerset.mp hB) hSB + exact (FABL.algebraicDegree_le_iff (FABL.anfCoeff f) d).mp + hdegree S (by simpa [A] using hSA) + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/NNFCharacterization.lean b/CryptBoolean/Carlet/Chapter06/NNFCharacterization.lean new file mode 100644 index 0000000..ba81952 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/NNFCharacterization.lean @@ -0,0 +1,430 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter02.FourierNNF +public import CryptBoolean.Carlet.Chapter06.WalshCongruence +public import FABL.Chapter06.F₂Polynomials.FourierToF₂Polynomial +import Mathlib.Combinatorics.Enumerative.IncidenceAlgebra +import Mathlib.Algebra.Ring.Parity + +/-! +# Numerical normal form characterization of bent functions + +Carlet Proposition 23: divisibility and top-coefficient congruence conditions +on the integral numerical normal form of a bent Boolean function. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +private theorem modEq_sub_two_mul_iff_of_double + (m t d b : ℤ) (hm : m = 2 * t) (hd : 2 * m ∣ d) : + Int.ModEq (2 * m) (d - 2 * b) m ↔ Int.ModEq m b t := by + rw [Int.modEq_iff_dvd, Int.modEq_iff_dvd] + constructor + · intro h + have hplus : 2 * m ∣ m + 2 * b := by + have hadd := dvd_add h hd + have heq : m - (d - 2 * b) + d = m + 2 * b := by ring + rwa [heq] at hadd + have hcancel : m ∣ t + b := by + have heq : m + 2 * b = 2 * (t + b) := by rw [hm]; ring + rw [heq] at hplus + exact (mul_dvd_mul_iff_left (by norm_num : (2 : ℤ) ≠ 0)).mp hplus + have hdouble : m ∣ 2 * t := by + rw [hm] + have hdiff := dvd_sub hdouble hcancel + have heq : 2 * t - (t + b) = t - b := by ring + rwa [heq] at hdiff + · intro h + have hdouble : m ∣ 2 * t := by + rw [hm] + have hplus : m ∣ t + b := by + have hdiff := dvd_sub hdouble h + have heq : 2 * t - (t - b) = t + b := by ring + rwa [heq] at hdiff + have htwice : 2 * m ∣ 2 * (t + b) := by + exact (mul_dvd_mul_iff_left (by norm_num : (2 : ℤ) ≠ 0)).mpr hplus + have hbase : 2 * m ∣ m + 2 * b := by + have heq : 2 * (t + b) = m + 2 * b := by rw [hm]; ring + rwa [heq] at htwice + have hdiff := dvd_sub hbase hd + have heq : m + 2 * b - d = m - (d - 2 * b) := by ring + rwa [heq] at hdiff + +private theorem modEq_neg_one_pow_mul_half + (m t z : ℤ) (hm : m = 2 * t) (hz : Int.ModEq m z t) (k : ℕ) : + Int.ModEq m ((-1 : ℤ) ^ k * z) t := by + rcases Nat.even_or_odd k with hk | hk + · rw [hk.neg_one_pow, one_mul] + exact hz + · rw [hk.neg_one_pow, neg_one_mul, Int.modEq_iff_dvd] + rw [Int.modEq_iff_dvd] at hz + have hdouble : m ∣ 2 * t := by rw [hm] + have hsum := dvd_sub hdouble hz + have heq : 2 * t - (t - z) = t - -z := by ring + rwa [heq] at hsum + +/-- The integral Fourier coefficient obtained from the integral numerical +normal form by Carlet Relation (30). -/ +noncomputable def booleanNNFFourierCoeffInt + (f : BooleanFunction n) (u : FABL.F₂Cube n) : ℤ := + (-1 : ℤ) ^ (FABL.f₂Support u).card * + ∑ S ∈ (Finset.univ.filter fun S : Finset (Fin n) ↦ + FABL.f₂Support u ⊆ S), + (2 : ℤ) ^ (n - S.card) * FABL.booleanNumericalCoeffInt f S + +/-- The integral NNF Fourier coefficient is the raw Fourier transform of the +zero-one embedding. -/ +theorem booleanNNFFourierCoeffInt_cast + (f : BooleanFunction n) (u : FABL.F₂Cube n) : + (booleanNNFFourierCoeffInt f u : ℝ) = + rawFourierTransform (FABL.booleanRealEmbedding f) u := by + classical + rw [← FABL.numericalEval_numericalCoeff (FABL.booleanRealEmbedding f), + rawFourierTransform_numericalEval] + simp only [booleanNNFFourierCoeffInt, Int.cast_mul, Int.cast_pow, + Int.cast_neg, Int.cast_one, Int.cast_sum, Int.cast_ofNat, + FABL.numericalCoeff_booleanRealEmbedding_eq_intCast] + +private theorem signed_booleanNNFFourierCoeffInt_eq_sum_Ici + (f : BooleanFunction n) (U : Finset (Fin n)) : + (-1 : ℤ) ^ U.card * + booleanNNFFourierCoeffInt f (FABL.f₂CubeOfFinset U) = + ∑ S ∈ Finset.Ici U, + (2 : ℤ) ^ (n - S.card) * FABL.booleanNumericalCoeffInt f S := by + classical + have hsupport : + FABL.f₂Support (FABL.f₂CubeOfFinset U) = U := + (FABL.f₂CubeEquivFinset n).right_inv U + rw [booleanNNFFourierCoeffInt, hsupport] + have hsign : (-1 : ℤ) ^ U.card * (-1 : ℤ) ^ U.card = 1 := by + rw [← mul_pow] + norm_num + rw [← mul_assoc, hsign, one_mul] + apply Finset.sum_congr + · ext S + simp + · intro S _hS + rfl + +private theorem walshTransform_cast_eq_rawFourierTransform_sub_two_mul_nnf + (f : BooleanFunction n) (u : FABL.F₂Cube n) : + (walshTransform f u : ℝ) = + rawFourierTransform (fun _ ↦ 1) u - + 2 * rawFourierTransform (FABL.booleanRealEmbedding f) u := by + calc + (walshTransform f u : ℝ) = rawFourierTransform (realSignView f) u := by + simpa [rawFourierTransform] using + walshTransform_cast_eq_sum_realSignView_mul_character f u + _ = rawFourierTransform + (fun x ↦ 1 - 2 * FABL.booleanRealEmbedding f x) u := by + congr 1 + funext x + by_cases hx : f x = 0 + · simp [realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction, FABL.booleanRealEmbedding, hx] + · have hxOne : f x = 1 := Fin.eq_one_of_ne_zero _ hx + simp [realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction, FABL.booleanRealEmbedding, hxOne] + norm_num + _ = rawFourierTransform (fun _ ↦ 1) u - + 2 * rawFourierTransform (FABL.booleanRealEmbedding f) u := by + rw [rawFourierTransform, rawFourierTransform, rawFourierTransform, + Finset.mul_sum, ← Finset.sum_sub_distrib] + apply Finset.sum_congr rfl + intro x _hx + ring + +/-- The Walsh transform is the constant Fourier coefficient minus twice the +integral zero-one Fourier coefficient. -/ +theorem walshTransform_eq_indicator_sub_two_mul_booleanNNFFourierCoeffInt + (f : BooleanFunction n) (u : FABL.F₂Cube n) : + walshTransform f u = + (if u = 0 then (2 : ℤ) ^ n else 0) - + 2 * booleanNNFFourierCoeffInt f u := by + apply Int.cast_injective (α := ℝ) + rw [walshTransform_cast_eq_rawFourierTransform_sub_two_mul_nnf, + ← booleanNNFFourierCoeffInt_cast, rawFourierTransform_one] + by_cases hu : u = 0 <;> simp [hu] + +/-- Carlet Lemma 2 in the equivalent zero-one Fourier normalization. -/ +theorem isBent_iff_forall_booleanNNFFourierCoeffInt_modeq + (f : BooleanFunction n) (hn : Even n) (hnTwo : 2 ≤ n) : + IsBent f ↔ + ∀ u : FABL.F₂Cube n, + Int.ModEq ((2 : ℤ) ^ (n / 2)) + (booleanNNFFourierCoeffInt f u) + ((2 : ℤ) ^ (n / 2 - 1)) := by + have hsplit : n = n / 2 + n / 2 := by + rcases hn with ⟨k, hk⟩ + omega + have hhalfPos : 1 ≤ n / 2 := by omega + have hdouble : (2 : ℤ) ^ (n / 2) = + 2 * (2 : ℤ) ^ (n / 2 - 1) := by + conv_lhs => rw [show n / 2 = (n / 2 - 1) + 1 by omega] + rw [pow_succ] + ring + rw [isBent_iff_forall_walshTransform_modeq f hn hnTwo] + constructor + · intro h u + have hdelta : + 2 * (2 : ℤ) ^ (n / 2) ∣ + if u = 0 then (2 : ℤ) ^ n else 0 := by + by_cases hu : u = 0 + · rw [if_pos hu] + have hle : n / 2 + 1 ≤ n := by omega + simpa [pow_succ, mul_comm] using + (pow_dvd_pow (2 : ℤ) hle) + · simp [hu] + have hw := h u + rw [walshTransform_eq_indicator_sub_two_mul_booleanNNFFourierCoeffInt] + at hw + have hw' : + Int.ModEq (2 * (2 : ℤ) ^ (n / 2)) + ((if u = 0 then (2 : ℤ) ^ n else 0) - + 2 * booleanNNFFourierCoeffInt f u) + ((2 : ℤ) ^ (n / 2)) := by + simpa [pow_succ, mul_comm] using hw + exact (modEq_sub_two_mul_iff_of_double + ((2 : ℤ) ^ (n / 2)) ((2 : ℤ) ^ (n / 2 - 1)) + (if u = 0 then (2 : ℤ) ^ n else 0) + (booleanNNFFourierCoeffInt f u) hdouble hdelta).mp hw' + · intro h u + have hdelta : + 2 * (2 : ℤ) ^ (n / 2) ∣ + if u = 0 then (2 : ℤ) ^ n else 0 := by + by_cases hu : u = 0 + · rw [if_pos hu] + have hle : n / 2 + 1 ≤ n := by omega + simpa [pow_succ, mul_comm] using + (pow_dvd_pow (2 : ℤ) hle) + · simp [hu] + have hw := (modEq_sub_two_mul_iff_of_double + ((2 : ℤ) ^ (n / 2)) ((2 : ℤ) ^ (n / 2 - 1)) + (if u = 0 then (2 : ℤ) ^ n else 0) + (booleanNNFFourierCoeffInt f u) hdouble hdelta).mpr (h u) + rw [walshTransform_eq_indicator_sub_two_mul_booleanNNFFourierCoeffInt] + simpa [pow_succ, mul_comm] using hw + +/-- The two divisibility conditions of Carlet Proposition 23. -/ +def SatisfiesBentNNFCoefficientConditions (f : BooleanFunction n) : Prop := + (∀ I : Finset (Fin n), + n / 2 < I.card → I.card < n → + (2 : ℤ) ^ (I.card - n / 2) ∣ + FABL.booleanNumericalCoeffInt f I) ∧ + Int.ModEq ((2 : ℤ) ^ (n / 2)) + (FABL.booleanNumericalCoeffInt f Finset.univ) + ((2 : ℤ) ^ (n / 2 - 1)) + +private theorem two_pow_half_dvd_weightedCoeff_of_conditions + (f : BooleanFunction n) (hn : Even n) + (hf : SatisfiesBentNNFCoefficientConditions f) + (S : Finset (Fin n)) (hS : S ≠ Finset.univ) : + (2 : ℤ) ^ (n / 2) ∣ + (2 : ℤ) ^ (n - S.card) * FABL.booleanNumericalCoeffInt f S := by + have hsplit : n = n / 2 + n / 2 := by + rcases hn with ⟨k, hk⟩ + omega + have hcardLe : S.card ≤ n := by + simpa using Finset.card_le_univ S + by_cases hcard : S.card ≤ n / 2 + · exact (pow_dvd_pow (2 : ℤ) (by omega)).mul_right _ + · have hcardLt : S.card < n := by + apply lt_of_le_of_ne hcardLe + intro hcardEq + apply hS + apply Finset.eq_univ_of_card S + simpa using hcardEq + obtain ⟨z, hz⟩ := hf.1 S (by omega) hcardLt + refine ⟨z, ?_⟩ + rw [hz, ← mul_assoc, ← pow_add] + congr 2 + omega + +private theorem forall_booleanNNFFourierCoeffInt_modeq_of_conditions + (f : BooleanFunction n) (hn : Even n) (hnTwo : 2 ≤ n) + (hf : SatisfiesBentNNFCoefficientConditions f) : + ∀ u : FABL.F₂Cube n, + Int.ModEq ((2 : ℤ) ^ (n / 2)) + (booleanNNFFourierCoeffInt f u) + ((2 : ℤ) ^ (n / 2 - 1)) := by + intro u + let U := FABL.f₂Support u + let a : Finset (Fin n) → ℤ := fun S ↦ + (2 : ℤ) ^ (n - S.card) * FABL.booleanNumericalCoeffInt f S + have hhalfPos : 1 ≤ n / 2 := by + rcases hn with ⟨k, hk⟩ + omega + have hdouble : (2 : ℤ) ^ (n / 2) = + 2 * (2 : ℤ) ^ (n / 2 - 1) := by + conv_lhs => rw [show n / 2 = (n / 2 - 1) + 1 by omega] + rw [pow_succ] + ring + have hcube : FABL.f₂CubeOfFinset U = u := by + simpa [U] using (FABL.f₂CubeEquivFinset n).symm_apply_apply u + have hrelation := signed_booleanNNFFourierCoeffInt_eq_sum_Ici f U + rw [hcube] at hrelation + change (-1 : ℤ) ^ U.card * booleanNNFFourierCoeffInt f u = + ∑ S ∈ Finset.Ici U, a S at hrelation + have huniv : (Finset.univ : Finset (Fin n)) ∈ Finset.Ici U := by simp + have hdecomp := Finset.sum_erase_add (Finset.Ici U) a huniv + have hrest : (2 : ℤ) ^ (n / 2) ∣ + ∑ S ∈ (Finset.Ici U).erase Finset.univ, a S := by + apply Finset.dvd_sum + intro S hS + exact two_pow_half_dvd_weightedCoeff_of_conditions f hn hf S + (Finset.ne_of_mem_erase hS) + have htop : (2 : ℤ) ^ (n / 2) ∣ + (2 : ℤ) ^ (n / 2 - 1) - a Finset.univ := by + have htopModeq : + Int.ModEq ((2 : ℤ) ^ (n / 2)) + (FABL.booleanNumericalCoeffInt f Finset.univ) + ((2 : ℤ) ^ (n / 2 - 1)) := hf.2 + rw [Int.modEq_iff_dvd] at htopModeq + simpa [a] using htopModeq + have hsum : (2 : ℤ) ^ (n / 2) ∣ + (2 : ℤ) ^ (n / 2 - 1) - + ∑ S ∈ Finset.Ici U, a S := by + have hdiff := dvd_sub htop hrest + have heq : + ((2 : ℤ) ^ (n / 2 - 1) - a Finset.univ) - + ∑ S ∈ (Finset.Ici U).erase Finset.univ, a S = + (2 : ℤ) ^ (n / 2 - 1) - + ∑ S ∈ Finset.Ici U, a S := by + rw [← hdecomp] + ring + rwa [heq] at hdiff + have hsigned : + Int.ModEq ((2 : ℤ) ^ (n / 2)) + ((-1 : ℤ) ^ U.card * booleanNNFFourierCoeffInt f u) + ((2 : ℤ) ^ (n / 2 - 1)) := by + rw [Int.modEq_iff_dvd, hrelation] + exact hsum + have hunsigned := modEq_neg_one_pow_mul_half + ((2 : ℤ) ^ (n / 2)) ((2 : ℤ) ^ (n / 2 - 1)) + ((-1 : ℤ) ^ U.card * booleanNNFFourierCoeffInt f u) + hdouble hsigned U.card + have hsign : (-1 : ℤ) ^ U.card * (-1 : ℤ) ^ U.card = 1 := by + rw [← mul_pow] + norm_num + simpa [← mul_assoc, hsign] using hunsigned + +private theorem conditions_of_forall_booleanNNFFourierCoeffInt_modeq + (f : BooleanFunction n) (hn : Even n) (hnTwo : 2 ≤ n) + (hf : ∀ u : FABL.F₂Cube n, + Int.ModEq ((2 : ℤ) ^ (n / 2)) + (booleanNNFFourierCoeffInt f u) + ((2 : ℤ) ^ (n / 2 - 1))) : + SatisfiesBentNNFCoefficientConditions f := by + classical + let a : Finset (Fin n) → ℤ := fun S ↦ + (2 : ℤ) ^ (n - S.card) * FABL.booleanNumericalCoeffInt f S + let g : Finset (Fin n) → ℤ := fun U ↦ + (-1 : ℤ) ^ U.card * + booleanNNFFourierCoeffInt f (FABL.f₂CubeOfFinset U) + have hsplit : n = n / 2 + n / 2 := by + rcases hn with ⟨k, hk⟩ + omega + have hhalfPos : 1 ≤ n / 2 := by omega + have hdouble : (2 : ℤ) ^ (n / 2) = + 2 * (2 : ℤ) ^ (n / 2 - 1) := by + conv_lhs => rw [show n / 2 = (n / 2 - 1) + 1 by omega] + rw [pow_succ] + ring + have hg (U : Finset (Fin n)) : + Int.ModEq ((2 : ℤ) ^ (n / 2)) (g U) + ((2 : ℤ) ^ (n / 2 - 1)) := by + exact modEq_neg_one_pow_mul_half + ((2 : ℤ) ^ (n / 2)) ((2 : ℤ) ^ (n / 2 - 1)) + (booleanNNFFourierCoeffInt f (FABL.f₂CubeOfFinset U)) + hdouble (hf (FABL.f₂CubeOfFinset U)) U.card + have hzeta (U : Finset (Fin n)) : + g U = ∑ S ∈ Finset.Ici U, a S := by + exact signed_booleanNNFFourierCoeffInt_eq_sum_Ici f U + have hinversion (I : Finset (Fin n)) : + a I = ∑ U ∈ Finset.Ici I, + IncidenceAlgebra.mu ℤ I U * g U := + IncidenceAlgebra.moebius_inversion_top a g hzeta I + have haModeq (I : Finset (Fin n)) : + Int.ModEq ((2 : ℤ) ^ (n / 2)) (a I) + (if I = Finset.univ then + (2 : ℤ) ^ (n / 2 - 1) else 0) := by + have hterms : (2 : ℤ) ^ (n / 2) ∣ + ∑ U ∈ Finset.Ici I, + IncidenceAlgebra.mu ℤ I U * + ((2 : ℤ) ^ (n / 2 - 1) - g U) := by + apply Finset.dvd_sum + intro U _hU + have hU := hg U + rw [Int.modEq_iff_dvd] at hU + exact hU.mul_left _ + have hsumEq : + (∑ U ∈ Finset.Ici I, + IncidenceAlgebra.mu ℤ I U * + ((2 : ℤ) ^ (n / 2 - 1) - g U)) = + (∑ U ∈ Finset.Ici I, IncidenceAlgebra.mu ℤ I U) * + (2 : ℤ) ^ (n / 2 - 1) - + ∑ U ∈ Finset.Ici I, + IncidenceAlgebra.mu ℤ I U * g U := by + simp_rw [mul_sub] + rw [Finset.sum_sub_distrib, Finset.sum_mul] + have hmu : + (∑ U ∈ Finset.Ici I, IncidenceAlgebra.mu ℤ I U) = + if I = Finset.univ then 1 else 0 := by + have hinterval : Finset.Ici I = + Finset.Icc I (Finset.univ : Finset (Fin n)) := by + ext U + simp + rw [hinterval] + exact IncidenceAlgebra.sum_Icc_mu_right I Finset.univ + rw [hsumEq, hmu, ← hinversion I] at hterms + rw [Int.modEq_iff_dvd] + simpa [apply_ite] using hterms + constructor + · intro I hIhalf hIn + have hIne : I ≠ (Finset.univ : Finset (Fin n)) := by + intro hI + subst I + simp at hIn + have hdivWeighted := haModeq I + rw [if_neg hIne, Int.modEq_iff_dvd] at hdivWeighted + have hdivWeighted' : (2 : ℤ) ^ (n / 2) ∣ a I := by + simpa only [zero_sub, dvd_neg] using hdivWeighted + have hpow : (2 : ℤ) ^ (n / 2) = + (2 : ℤ) ^ (n - I.card) * + (2 : ℤ) ^ (I.card - n / 2) := by + rw [← pow_add] + congr 1 + omega + change (2 : ℤ) ^ (n / 2) ∣ + (2 : ℤ) ^ (n - I.card) * + FABL.booleanNumericalCoeffInt f I at hdivWeighted' + rw [hpow] at hdivWeighted' + exact (mul_dvd_mul_iff_left + (pow_ne_zero _ (by norm_num : (2 : ℤ) ≠ 0))).mp hdivWeighted' + · have htop := haModeq (Finset.univ : Finset (Fin n)) + simpa [a] using htop + +/-- Carlet Proposition 23: in even dimension at least two, a Boolean function +is bent exactly when its integral numerical normal form satisfies the stated +intermediate divisibility conditions and top-coefficient congruence. -/ +theorem isBent_iff_nnfCoefficientConditions + (f : BooleanFunction n) (hn : Even n) (hnTwo : 2 ≤ n) : + IsBent f ↔ SatisfiesBentNNFCoefficientConditions f := by + rw [isBent_iff_forall_booleanNNFFourierCoeffInt_modeq f hn hnTwo] + constructor + · exact conditions_of_forall_booleanNNFFourierCoeffInt_modeq f hn hnTwo + · exact forall_booleanNNFFourierCoeffInt_modeq_of_conditions f hn hnTwo + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/NestedBent.lean b/CryptBoolean/Carlet/Chapter06/NestedBent.lean new file mode 100644 index 0000000..cd9c672 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/NestedBent.lean @@ -0,0 +1,196 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.Dual + +/-! +# Nested construction of bent functions + +Carlet Theorem 10: bent slices whose pointwise dual slices are bent. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n m : ℕ} + +/-- The restriction of a block Boolean function at a fixed second-block input. -/ +def firstBlockSlice + (f : BooleanFunction (n + m)) (y : FABL.F₂Cube m) : BooleanFunction n := + fun x ↦ f (Fin.append x y) + +/-- At a first-block frequency, collect the dual values of all bent first-block slices. -/ +noncomputable def dualSliceFunction + (f : BooleanFunction (n + m)) (s : FABL.F₂Cube n) : BooleanFunction m := + fun y ↦ bentDual (firstBlockSlice f y) s + +/-- The raw Walsh transform of nested bent slices factors through their dual slice. -/ +theorem walshTransform_eq_two_pow_half_mul_walshTransform_dualSliceFunction + (f : BooleanFunction (n + m)) + (hslices : ∀ y, IsBent (firstBlockSlice f y)) + (s : FABL.F₂Cube n) (t : FABL.F₂Cube m) : + walshTransform f (Fin.append s t) = + (2 ^ (n / 2) : ℤ) * walshTransform (dualSliceFunction f s) t := by + classical + apply Int.cast_injective (α := ℝ) + push_cast + rw [walshTransform_cast_eq_sum_realSignView_mul_character, + walshTransform_cast_eq_sum_realSignView_mul_character] + calc + (∑ z : FABL.F₂Cube (n + m), + realSignView f z * FABL.vectorWalshCharacter (Fin.append s t) z) = + ∑ p : FABL.F₂Cube n × FABL.F₂Cube m, + realSignView f (Fin.append p.1 p.2) * + FABL.vectorWalshCharacter (Fin.append s t) (Fin.append p.1 p.2) := by + let summand := fun z : FABL.F₂Cube (n + m) ↦ + realSignView f z * FABL.vectorWalshCharacter (Fin.append s t) z + calc + (∑ z : FABL.F₂Cube (n + m), summand z) = + ∑ z : FABL.F₂Cube (n + m), + summand (Fin.append + ((Fin.appendEquiv n m).symm z).1 + ((Fin.appendEquiv n m).symm z).2) := by + apply Finset.sum_congr rfl + intro z _hz + have hz : Fin.append + ((Fin.appendEquiv n m).symm z).1 + ((Fin.appendEquiv n m).symm z).2 = z := + (Fin.appendEquiv n m).apply_symm_apply z + exact congrArg summand hz |>.symm + _ = ∑ p : FABL.F₂Cube n × FABL.F₂Cube m, + summand (Fin.append p.1 p.2) := + Equiv.sum_comp (Fin.appendEquiv n m).symm + (fun p : FABL.F₂Cube n × FABL.F₂Cube m ↦ + summand (Fin.append p.1 p.2)) + _ = ∑ y : FABL.F₂Cube m, + (∑ x : FABL.F₂Cube n, + realSignView (firstBlockSlice f y) x * + FABL.vectorWalshCharacter s x) * + FABL.vectorWalshCharacter t y := by + rw [Fintype.sum_prod_type, Finset.sum_comm] + apply Finset.sum_congr rfl + intro y _hy + rw [Finset.sum_mul] + apply Finset.sum_congr rfl + intro x _hx + rw [FABL.vectorWalshCharacter_append] + simp [firstBlockSlice, realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction] + ring + _ = ∑ y : FABL.F₂Cube m, + (walshTransform (firstBlockSlice f y) s : ℝ) * + FABL.vectorWalshCharacter t y := by + apply Finset.sum_congr rfl + intro y _hy + rw [walshTransform_cast_eq_sum_realSignView_mul_character] + _ = ∑ y : FABL.F₂Cube m, + ((2 : ℝ) ^ (n / 2) * + (bitSignInt (dualSliceFunction f s y) : ℝ)) * + FABL.vectorWalshCharacter t y := by + apply Finset.sum_congr rfl + intro y _hy + have hdual := congrArg (fun z : ℤ ↦ (z : ℝ)) + (walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + (firstBlockSlice f y) (hslices y) s) + simpa only [dualSliceFunction, Int.cast_mul, Int.cast_pow, + Int.cast_ofNat] using congrArg + (fun z : ℝ ↦ z * FABL.vectorWalshCharacter t y) hdual + _ = (2 : ℝ) ^ (n / 2) * + ∑ y : FABL.F₂Cube m, + realSignView (dualSliceFunction f s) y * + FABL.vectorWalshCharacter t y := by + rw [Finset.mul_sum] + apply Finset.sum_congr rfl + intro y _hy + have hsign : + (bitSignInt (dualSliceFunction f s y) : ℝ) = + realSignView (dualSliceFunction f s) y := by + rw [bitSignInt_cast] + simp [realSignView, FABL.realSignEncodedFunction, + FABL.signEncodedFunction, FABL.signValue_signEncode_eq_binarySign] + rw [hsign] + ring + +/-- Carlet Theorem 10: with bent first-block slices, the whole function is +bent exactly when every function of their dual values is bent. -/ +theorem isBent_iff_forall_isBent_dualSliceFunction + (f : BooleanFunction (n + m)) + (hn : Even n) (hm : Even m) + (hslices : ∀ y, IsBent (firstBlockSlice f y)) : + IsBent f ↔ ∀ s, IsBent (dualSliceFunction f s) := by + have hhalf : (n + m) / 2 = n / 2 + m / 2 := by + rcases hn with ⟨r, hr⟩ + rcases hm with ⟨q, hq⟩ + omega + constructor + · intro hf s + apply (isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half + (dualSliceFunction f s)).mpr + intro t + have hfactor := + walshTransform_eq_two_pow_half_mul_walshTransform_dualSliceFunction + f hslices s t + have hmagnitude := + natAbs_walshTransform_eq_two_pow_half_of_isBent + f hf (Fin.append s t) + rw [hfactor, Int.natAbs_mul, Int.natAbs_pow, hhalf, pow_add] at hmagnitude + norm_num at hmagnitude + exact hmagnitude + · intro hdual + apply (isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half f).mpr + intro u + let s := ((Fin.appendEquiv n m).symm u).1 + let t := ((Fin.appendEquiv n m).symm u).2 + have hu : Fin.append s t = u := + (Fin.appendEquiv n m).apply_symm_apply u + rw [← hu, + walshTransform_eq_two_pow_half_mul_walshTransform_dualSliceFunction + f hslices s t, + Int.natAbs_mul, Int.natAbs_pow] + rw [natAbs_walshTransform_eq_two_pow_half_of_isBent + (dualSliceFunction f s) (hdual s) t, + hhalf, pow_add] + norm_num + +/-- Under Theorem 10's hypotheses, the dual is obtained by dualizing the +second-block function of first-slice dual values. -/ +theorem bentDual_append_eq_bentDual_dualSliceFunction + (f : BooleanFunction (n + m)) + (hn : Even n) (hm : Even m) + (hslices : ∀ y, IsBent (firstBlockSlice f y)) + (hdualSlices : ∀ s, IsBent (dualSliceFunction f s)) + (s : FABL.F₂Cube n) (t : FABL.F₂Cube m) : + bentDual f (Fin.append s t) = bentDual (dualSliceFunction f s) t := by + have hf := (isBent_iff_forall_isBent_dualSliceFunction + f hn hm hslices).mpr hdualSlices + have hfactor := + walshTransform_eq_two_pow_half_mul_walshTransform_dualSliceFunction + f hslices s t + have hdualF := + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + f hf (Fin.append s t) + have hdualInner := + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + (dualSliceFunction f s) (hdualSlices s) t + have hhalf : (n + m) / 2 = n / 2 + m / 2 := by + rcases hn with ⟨r, hr⟩ + rcases hm with ⟨q, hq⟩ + omega + rw [hdualInner] at hfactor + rw [hdualF, hhalf, pow_add] at hfactor + have hsign : + bitSignInt (bentDual f (Fin.append s t)) = + bitSignInt (bentDual (dualSliceFunction f s) t) := by + exact mul_left_cancel₀ + (by positivity : (2 ^ (n / 2) : ℤ) * 2 ^ (m / 2) ≠ 0) + (by simpa [mul_assoc] using hfactor) + exact bitSignInt_injective hsign + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/NormalExtension.lean b/CryptBoolean/Carlet/Chapter06/NormalExtension.lean new file mode 100644 index 0000000..cf58612 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/NormalExtension.lean @@ -0,0 +1,2556 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter05.Normality +public import CryptBoolean.Carlet.Chapter06.CompleteQuadratic +public import CryptBoolean.Carlet.Chapter06.DirectSum +public import CryptBoolean.Carlet.Chapter06.DualPoisson +public import CryptBoolean.Carlet.Chapter06.MaioranaMcFarland +public import CryptBoolean.Carlet.Chapter06.NestedBent + +import Mathlib.LinearAlgebra.Goursat +import Mathlib.LinearAlgebra.Projection + +/-! +# Normal extensions of bent Boolean functions + +Carlet Section 6.9, Definition 8 and Propositions 30--31. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {a b c k m n p r s t : ℕ} + +noncomputable local instance normalExtensionSubmoduleFintype + (S : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) : Fintype S := + Fintype.ofFinite S + +private def cubeTripleLinearEquiv (a b : ℕ) : + FABL.F₂Cube (a + (b + b)) ≃ₗ[FABL.𝔽₂] + (FABL.F₂Cube a × (FABL.F₂Cube b × FABL.F₂Cube b)) := + (cubeSplitLinearEquiv a (b + b)).trans + ((LinearEquiv.refl FABL.𝔽₂ (FABL.F₂Cube a)).prodCongr + (cubeSplitLinearEquiv b b)) + +@[simp] private theorem append_zero_addNat + (v : FABL.F₂Cube n) (i : Fin n) : + Fin.append v 0 (i.addNat n) = 0 := by + have hi : i.addNat n = Fin.natAdd n i := by + ext + simp [Fin.addNat, Fin.natAdd, Nat.add_comm] + rw [hi, Fin.append_right] + rfl + +@[simp] private theorem zero_append_addNat + (v : FABL.F₂Cube n) (i : Fin n) : + Fin.append 0 v (i.addNat n) = v i := by + have hi : i.addNat n = Fin.natAdd n i := by + ext + simp [Fin.addNat, Fin.natAdd, Nat.add_comm] + rw [hi, Fin.append_right] + +@[simp] private theorem append_addNat + (v w : FABL.F₂Cube n) (i : Fin n) : + Fin.append v w (i.addNat n) = w i := by + have hi : i.addNat n = Fin.natAdd n i := by + ext + simp [Fin.addNat, Fin.natAdd, Nat.add_comm] + rw [hi, Fin.append_right] + +private def normalExtensionReassociationLinearEquiv (a b t : ℕ) : + FABL.F₂Cube (a + ((b + t) + (b + t))) ≃ₗ[FABL.𝔽₂] + (FABL.F₂Cube (a + (b + b)) × + (FABL.F₂Cube t × FABL.F₂Cube t)) where + toFun x := + let q := cubeTripleLinearEquiv a (b + t) x + let y := cubeSplitLinearEquiv b t q.2.1 + let z := cubeSplitLinearEquiv b t q.2.2 + ((cubeTripleLinearEquiv a b).symm (q.1, (y.1, z.1)), (y.2, z.2)) + invFun x := + let q := cubeTripleLinearEquiv a b x.1 + (cubeTripleLinearEquiv a (b + t)).symm + (q.1, + ((cubeSplitLinearEquiv b t).symm (q.2.1, x.2.1), + (cubeSplitLinearEquiv b t).symm (q.2.2, x.2.2))) + left_inv x := by + simp [cubeTripleLinearEquiv] + right_inv x := by + simp [cubeTripleLinearEquiv] + map_add' x y := by + simpa [map_add] using + (cubeTripleLinearEquiv a b).symm.map_add + (((cubeTripleLinearEquiv a (b + t)) x).1, + (((cubeSplitLinearEquiv b t) + ((cubeTripleLinearEquiv a (b + t)) x).2.1).1, + ((cubeSplitLinearEquiv b t) + ((cubeTripleLinearEquiv a (b + t)) x).2.2).1)) + (((cubeTripleLinearEquiv a (b + t)) y).1, + (((cubeSplitLinearEquiv b t) + ((cubeTripleLinearEquiv a (b + t)) y).2.1).1, + ((cubeSplitLinearEquiv b t) + ((cubeTripleLinearEquiv a (b + t)) y).2.2).1)) + map_smul' c x := by + simpa [map_smul] using + (cubeTripleLinearEquiv a b).symm.map_smul c + (((cubeTripleLinearEquiv a (b + t)) x).1, + (((cubeSplitLinearEquiv b t) + ((cubeTripleLinearEquiv a (b + t)) x).2.1).1, + ((cubeSplitLinearEquiv b t) + ((cubeTripleLinearEquiv a (b + t)) x).2.2).1)) + +private def normalExtensionTransLinearEquiv + (L : FABL.F₂Cube (k + (r + r)) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube n) + (M : FABL.F₂Cube (n + (s + s)) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube p) : + FABL.F₂Cube (k + ((r + s) + (r + s))) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube p := + (normalExtensionReassociationLinearEquiv k r s).trans + ((L.prodCongr + (LinearEquiv.refl FABL.𝔽₂ + (FABL.F₂Cube s × FABL.F₂Cube s))).trans + ((cubeTripleLinearEquiv n s).symm.trans M)) + +private def normalExtensionAuxiliarySwapLinearEquiv (a b : ℕ) : + FABL.F₂Cube (a + (b + b)) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube (a + (b + b)) := + (cubeTripleLinearEquiv a b).trans + (((LinearEquiv.refl FABL.𝔽₂ (FABL.F₂Cube a)).prodCongr + (LinearEquiv.prodComm FABL.𝔽₂ + (FABL.F₂Cube b) (FABL.F₂Cube b))).trans + (cubeTripleLinearEquiv a b).symm) + +@[simp] private theorem normalExtensionAuxiliarySwapLinearEquiv_apply + (u : FABL.F₂Cube a) (w z : FABL.F₂Cube b) : + normalExtensionAuxiliarySwapLinearEquiv a b + (Fin.append u (Fin.append w z)) = + Fin.append u (Fin.append z w) := by + apply (cubeTripleLinearEquiv a b).injective + simp [normalExtensionAuxiliarySwapLinearEquiv, cubeTripleLinearEquiv, + cubeSplitLinearEquiv] + +private def normalExtensionHeadLinearMap (a b : ℕ) : + FABL.F₂Cube (a + b) →ₗ[FABL.𝔽₂] + FABL.F₂Cube (a + (b + b)) where + toFun x := + let q := cubeSplitLinearEquiv a b x + (cubeTripleLinearEquiv a b).symm (q.1, (q.2, 0)) + map_add' x y := by + simpa [map_add] using (cubeTripleLinearEquiv a b).symm.map_add + (((cubeSplitLinearEquiv a b) x).1, + (((cubeSplitLinearEquiv a b) x).2, 0)) + (((cubeSplitLinearEquiv a b) y).1, + (((cubeSplitLinearEquiv a b) y).2, 0)) + map_smul' c x := by + simpa [map_smul] using (cubeTripleLinearEquiv a b).symm.map_smul c + (((cubeSplitLinearEquiv a b) x).1, + (((cubeSplitLinearEquiv a b) x).2, 0)) + +@[simp] private theorem normalExtensionHeadLinearMap_apply + (u : FABL.F₂Cube a) (w : FABL.F₂Cube b) : + normalExtensionHeadLinearMap a b (Fin.append u w) = + Fin.append u (Fin.append w 0) := by + apply (cubeTripleLinearEquiv a b).injective + suffices (0 : FABL.F₂Cube b) = (fun _i : Fin b ↦ 0) by + simpa [normalExtensionHeadLinearMap, cubeTripleLinearEquiv, + cubeSplitLinearEquiv] using this + funext i + rfl + +private theorem normalExtensionHeadLinearMap_injective : + Function.Injective (normalExtensionHeadLinearMap a b) := by + intro x y hxy + have h := congrArg (cubeTripleLinearEquiv a b) hxy + apply (cubeSplitLinearEquiv a b).injective + apply Prod.ext + · simpa [normalExtensionHeadLinearMap] using congrArg + (fun q ↦ q.1) h + · simpa [normalExtensionHeadLinearMap] using congrArg + (fun q ↦ q.2.1) h + +private def normalExtensionHeadSubspace (a b : ℕ) : + Submodule FABL.𝔽₂ (FABL.F₂Cube (a + (b + b))) := + LinearMap.range (normalExtensionHeadLinearMap a b) + +private noncomputable def normalExtensionHeadSubspaceLinearEquiv (a b : ℕ) : + FABL.F₂Cube (a + b) ≃ₗ[FABL.𝔽₂] + normalExtensionHeadSubspace a b := + LinearEquiv.ofInjective (normalExtensionHeadLinearMap a b) + normalExtensionHeadLinearMap_injective + +@[simp] private theorem normalExtensionHeadSubspaceLinearEquiv_apply_coe + (x : FABL.F₂Cube (a + b)) : + (normalExtensionHeadSubspaceLinearEquiv a b x).1 = + normalExtensionHeadLinearMap a b x := + rfl + +private theorem normalExtensionHeadLinearMap_apply_split + (x : FABL.F₂Cube (a + b)) : + normalExtensionHeadLinearMap a b x = + Fin.append (cubeSplitLinearEquiv a b x).1 + (Fin.append (cubeSplitLinearEquiv a b x).2 0) := by + let q := cubeSplitLinearEquiv a b x + have hx : Fin.append q.1 q.2 = x := + (Fin.appendEquiv a b).apply_symm_apply x + rw [← hx, normalExtensionHeadLinearMap_apply] + have hq : cubeSplitLinearEquiv a b (Fin.append q.1 q.2) = q := by + simp [cubeSplitLinearEquiv] + rw [hq] + +private def normalExtensionPrefixLinearMap (a b : ℕ) : + FABL.F₂Cube (a + (b + b)) →ₗ[FABL.𝔽₂] + FABL.F₂Cube a where + toFun x := (cubeTripleLinearEquiv a b x).1 + map_add' x y := by simp [map_add] + map_smul' c x := by simp [map_smul] + +@[simp] private theorem normalExtensionPrefixLinearMap_apply + (u : FABL.F₂Cube a) (w z : FABL.F₂Cube b) : + normalExtensionPrefixLinearMap a b + (Fin.append u (Fin.append w z)) = u := by + simp [normalExtensionPrefixLinearMap, cubeTripleLinearEquiv, + cubeSplitLinearEquiv] + +private theorem mem_normalExtensionHeadSubspace_iff_tail_eq_zero + (x : FABL.F₂Cube (a + (b + b))) : + x ∈ normalExtensionHeadSubspace a b ↔ + (cubeTripleLinearEquiv a b x).2.2 = 0 := by + constructor + · rintro ⟨y, rfl⟩ + rw [normalExtensionHeadLinearMap_apply_split] + suffices (fun _i : Fin b ↦ (0 : FABL.𝔽₂)) = 0 by + simpa [cubeTripleLinearEquiv, cubeSplitLinearEquiv] using this + funext i + rfl + · intro hx + let q := cubeTripleLinearEquiv a b x + have hq : q.2.2 = 0 := hx + have hrecover : + Fin.append q.1 (Fin.append q.2.1 q.2.2) = x := by + exact (cubeTripleLinearEquiv a b).injective (by + simp [q, cubeTripleLinearEquiv, cubeSplitLinearEquiv]) + refine ⟨Fin.append q.1 q.2.1, ?_⟩ + rw [normalExtensionHeadLinearMap_apply, ← hq] + exact hrecover + +private def normalExtensionProjectedIntersection + (N : Submodule FABL.𝔽₂ (FABL.F₂Cube (a + (b + b)))) : + Submodule FABL.𝔽₂ (FABL.F₂Cube a) := + (N ⊓ normalExtensionHeadSubspace a b).map + (normalExtensionPrefixLinearMap a b) + +private theorem normalExtensionProjectedIntersection_mem_of_mem + {N : Submodule FABL.𝔽₂ (FABL.F₂Cube (a + (b + b)))} + {x : FABL.F₂Cube (a + (b + b))} + (hxN : x ∈ N) (hxHead : x ∈ normalExtensionHeadSubspace a b) : + normalExtensionPrefixLinearMap a b x ∈ + normalExtensionProjectedIntersection N := + ⟨x, ⟨hxN, hxHead⟩, rfl⟩ + +private theorem isConstantOn_projectedIntersection + (beta : BooleanFunction a) + (f : BooleanFunction (a + (b + b))) + (N : Submodule FABL.𝔽₂ (FABL.F₂Cube (a + (b + b)))) + (c : FABL.𝔽₂) + (hrestriction : ∀ u w, + f (Fin.append u (Fin.append w 0)) = beta u) + (hconstant : ∀ x ∈ FABL.binaryAffineSubspace N 0, f x = c) : + ∀ u ∈ normalExtensionProjectedIntersection N, beta u = c := by + intro u hu + obtain ⟨x, hx, hxu⟩ := hu + obtain ⟨y, hy⟩ := hx.2 + let q := cubeSplitLinearEquiv a b y + have hySplit : Fin.append q.1 q.2 = y := + (Fin.appendEquiv a b).apply_symm_apply y + have hxSplit : x = Fin.append q.1 (Fin.append q.2 0) := by + rw [← hy, ← hySplit, normalExtensionHeadLinearMap_apply] + have huq : u = q.1 := by + rw [← hxu, hxSplit, normalExtensionPrefixLinearMap_apply] + rw [huq, ← hrestriction q.1 q.2, ← hxSplit] + apply hconstant + simpa [FABL.mem_binaryAffineSubspace_iff_add_mem] using hx.1 + +private theorem normalExtensionHead_perpendicular_dot_eq_zero + (γ : FABL.perpendicularSubspace (normalExtensionHeadSubspace a b)) + (u : FABL.F₂Cube a) (w : FABL.F₂Cube b) : + FABL.f₂DotProduct γ.1 (Fin.append u (Fin.append w 0)) = 0 := by + exact (FABL.mem_perpendicularSubspace_iff + (normalExtensionHeadSubspace a b) γ.1).1 γ.2 + (Fin.append u (Fin.append w 0)) + ⟨Fin.append u w, normalExtensionHeadLinearMap_apply u w⟩ + +private theorem normalExtensionHead_perpendicular_prefix_eq_zero + (γ : FABL.perpendicularSubspace (normalExtensionHeadSubspace a b)) : + (cubeTripleLinearEquiv a b γ.1).1 = 0 ∧ + (cubeTripleLinearEquiv a b γ.1).2.1 = 0 := by + constructor + · funext i + have h := normalExtensionHead_perpendicular_dot_eq_zero γ + (Pi.single i 1) 0 + simpa [cubeTripleLinearEquiv, cubeSplitLinearEquiv, + FABL.f₂DotProduct, dotProduct, Pi.single_apply, + Fin.sum_univ_add] using h + · funext i + have h := normalExtensionHead_perpendicular_dot_eq_zero γ + 0 (Pi.single i 1) + simpa [cubeTripleLinearEquiv, cubeSplitLinearEquiv, + FABL.f₂DotProduct, dotProduct, Pi.single_apply, + Fin.sum_univ_add] using h + +private def normalExtensionTailPerpendicularLinearMap (a b : ℕ) : + FABL.F₂Cube b →ₗ[FABL.𝔽₂] + FABL.perpendicularSubspace (normalExtensionHeadSubspace a b) where + toFun z := ⟨Fin.append 0 (Fin.append 0 z), by + rw [FABL.mem_perpendicularSubspace_iff] + intro x hx + obtain ⟨y, rfl⟩ := hx + let q := cubeSplitLinearEquiv a b y + rw [show y = Fin.append q.1 q.2 by + exact (Fin.appendEquiv a b).apply_symm_apply y |>.symm, + normalExtensionHeadLinearMap_apply, + FABL.f₂DotProduct_append, FABL.f₂DotProduct_append] + simp [FABL.f₂DotProduct, dotProduct]⟩ + map_add' x y := by + apply Subtype.ext + apply (cubeTripleLinearEquiv a b).injective + have hcoordinates : + (fun _i : Fin a ↦ (0 : FABL.𝔽₂)) = 0 ∧ + (fun _i : Fin b ↦ (0 : FABL.𝔽₂)) = 0 ∧ + (fun i : Fin b ↦ x i + y i) = x + y := by + constructor + · funext i + rfl + · constructor <;> funext i <;> rfl + simpa [cubeTripleLinearEquiv, cubeSplitLinearEquiv, map_add] using + hcoordinates + map_smul' c x := by + apply Subtype.ext + apply (cubeTripleLinearEquiv a b).injective + simp [cubeTripleLinearEquiv, cubeSplitLinearEquiv, map_smul, + funext_iff] + +@[simp] private theorem normalExtensionTailPerpendicularLinearMap_apply_coe + (z : FABL.F₂Cube b) : + (normalExtensionTailPerpendicularLinearMap a b z).1 = + Fin.append 0 (Fin.append 0 z) := + rfl + +private theorem normalExtensionTailPerpendicularLinearMap_injective : + Function.Injective (normalExtensionTailPerpendicularLinearMap a b) := by + intro x y hxy + have h := congrArg + (fun z : FABL.perpendicularSubspace + (normalExtensionHeadSubspace a b) ↦ z.1) hxy + have hsplit := congrArg (cubeTripleLinearEquiv a b) h + simpa [cubeTripleLinearEquiv, cubeSplitLinearEquiv] using + congrArg (fun q ↦ q.2.2) hsplit + +private theorem normalExtensionTailPerpendicularLinearMap_surjective : + Function.Surjective (normalExtensionTailPerpendicularLinearMap a b) := by + intro γ + let q := cubeTripleLinearEquiv a b γ.1 + refine ⟨q.2.2, ?_⟩ + have hprefix := normalExtensionHead_perpendicular_prefix_eq_zero γ + apply Subtype.ext + apply (cubeTripleLinearEquiv a b).injective + have htail : cubeTripleLinearEquiv a b + (Fin.append 0 (Fin.append 0 q.2.2)) = (0, (0, q.2.2)) := by + have hcoordinates : + (fun i : Fin a ↦ Fin.append 0 (Fin.append 0 q.2.2) + (Fin.castAdd (b + b) i)) = 0 ∧ + (fun i : Fin b ↦ Fin.append 0 q.2.2 + (Fin.castAdd b i)) = 0 := by + constructor <;> funext i + · exact Fin.append_left 0 (Fin.append 0 q.2.2) i + · exact Fin.append_left 0 q.2.2 i + simpa [cubeTripleLinearEquiv, cubeSplitLinearEquiv] using hcoordinates + rw [normalExtensionTailPerpendicularLinearMap_apply_coe, htail] + exact Prod.ext hprefix.1.symm (Prod.ext hprefix.2.symm rfl) + +private noncomputable def normalExtensionTailPerpendicularLinearEquiv + (a b : ℕ) : + FABL.F₂Cube b ≃ₗ[FABL.𝔽₂] + FABL.perpendicularSubspace (normalExtensionHeadSubspace a b) := + LinearEquiv.ofBijective (normalExtensionTailPerpendicularLinearMap a b) + ⟨normalExtensionTailPerpendicularLinearMap_injective, + normalExtensionTailPerpendicularLinearMap_surjective⟩ + +@[simp] private theorem normalExtensionTailPerpendicularLinearEquiv_apply_coe + (z : FABL.F₂Cube b) : + (normalExtensionTailPerpendicularLinearEquiv a b z).1 = + Fin.append 0 (Fin.append 0 z) := + rfl + +@[simp] private theorem + normalExtensionTailPerpendicularLinearEquiv_toEquiv_apply_coe + (z : FABL.F₂Cube b) : + ((normalExtensionTailPerpendicularLinearEquiv a b).toEquiv z).1 = + Fin.append 0 (Fin.append 0 z) := + rfl + +/-- The adjoint of a cube linear equivalence for the standard binary dot +pairings. -/ +noncomputable def walshAdjointLinearEquiv + (L : FABL.F₂Cube r ≃ₗ[FABL.𝔽₂] FABL.F₂Cube s) : + FABL.F₂Cube s ≃ₗ[FABL.𝔽₂] FABL.F₂Cube r := + (dotProductEquiv FABL.𝔽₂ (Fin s)).trans + (L.dualMap.trans (dotProductEquiv FABL.𝔽₂ (Fin r)).symm) + +private theorem f₂DotProduct_walshAdjointLinearEquiv + (L : FABL.F₂Cube r ≃ₗ[FABL.𝔽₂] FABL.F₂Cube s) + (a : FABL.F₂Cube s) (x : FABL.F₂Cube r) : + FABL.f₂DotProduct (walshAdjointLinearEquiv L a) x = + FABL.f₂DotProduct a (L x) := by + change dotProduct (walshAdjointLinearEquiv L a) x = dotProduct a (L x) + calc + dotProduct (walshAdjointLinearEquiv L a) x = + (dotProductEquiv FABL.𝔽₂ (Fin r)) + (walshAdjointLinearEquiv L a) x := + (dotProductEquiv_apply_apply FABL.𝔽₂ (Fin r) _ _).symm + _ = ((dotProductEquiv FABL.𝔽₂ (Fin s)) a).comp L.toLinearMap x := by + exact DFunLike.congr_fun + ((dotProductEquiv FABL.𝔽₂ (Fin r)).apply_symm_apply + (((dotProductEquiv FABL.𝔽₂ (Fin s)) a).comp L.toLinearMap)) x + _ = dotProduct a (L x) := + dotProductEquiv_apply_apply FABL.𝔽₂ (Fin s) _ _ + +/-- A linear change of input coordinates transports Walsh frequencies by +the inverse adjoint map. -/ +theorem walshTransform_comp_linearEquiv + (f : BooleanFunction s) + (L : FABL.F₂Cube r ≃ₗ[FABL.𝔽₂] FABL.F₂Cube s) + (a : FABL.F₂Cube r) : + walshTransform (f ∘ L) a = + walshTransform f (walshAdjointLinearEquiv L.symm a) := by + classical + rw [walshTransform, walshTransform] + apply Fintype.sum_equiv L.toEquiv + intro x + rw [walshTerm, walshTerm] + change bitSignInt (f (L x) + FABL.f₂DotProduct a x) = + bitSignInt (f (L x) + + FABL.f₂DotProduct (walshAdjointLinearEquiv L.symm a) (L x)) + rw [f₂DotProduct_walshAdjointLinearEquiv, L.symm_apply_apply] + +/-- Bent duals transform contragrediently under a linear change of input +coordinates. -/ +theorem bentDual_comp_linearEquiv + (f : BooleanFunction s) + (L : FABL.F₂Cube r ≃ₗ[FABL.𝔽₂] FABL.F₂Cube s) + (a : FABL.F₂Cube r) : + bentDual (f ∘ L) a = + bentDual f (walshAdjointLinearEquiv L.symm a) := by + rw [bentDual, bentDual, walshTransform_comp_linearEquiv] + +private theorem sum_walshTransform_canonical_normalExtension + (β : BooleanFunction k) + (f : BooleanFunction (k + (r + r))) + (hrestriction : ∀ u w, + f (Fin.append u (Fin.append w 0)) = β u) + (a : FABL.F₂Cube k) : + (∑ z : FABL.F₂Cube r, + (walshTransform f (Fin.append a (Fin.append 0 z)) : ℝ)) = + (2 : ℝ) ^ r * ((2 : ℝ) ^ r * (walshTransform β a : ℝ)) := by + classical + let E := normalExtensionHeadSubspace k r + let e := normalExtensionHeadSubspaceLinearEquiv k r + let c : FABL.F₂Cube (k + r) := Fin.append a 0 + let d : FABL.F₂Cube (k + (r + r)) := Fin.append a (Fin.append 0 0) + have hd : ∀ y : FABL.F₂Cube (k + r), + FABL.f₂DotProduct d (e y).1 = FABL.f₂DotProduct c y := by + intro y + let q := cubeSplitLinearEquiv k r y + have hy : Fin.append q.1 q.2 = y := + (Fin.appendEquiv k r).apply_symm_apply y + rw [← hy] + rw [normalExtensionHeadSubspaceLinearEquiv_apply_coe, + normalExtensionHeadLinearMap_apply] + change FABL.f₂DotProduct + (Fin.append a (Fin.append 0 0)) + (Fin.append q.1 (Fin.append q.2 0)) = + FABL.f₂DotProduct (Fin.append a 0) (Fin.append q.1 q.2) + simp_rw [FABL.f₂DotProduct_append] + simp [FABL.f₂DotProduct, dotProduct] + have hpoisson := sum_walshTransform_perpendicularCoset_eq_restriction + f E 0 e c d hd + have hlocal : + coordinateAffineSubspaceRestriction f E 0 e = + booleanDirectSum β (0 : BooleanFunction r) := by + funext y + let q := cubeSplitLinearEquiv k r y + rw [coordinateAffineSubspaceRestriction_apply] + rw [add_zero] + change f ((e y).1) = booleanDirectSum β (0 : BooleanFunction r) y + rw [normalExtensionHeadSubspaceLinearEquiv_apply_coe, + normalExtensionHeadLinearMap_apply_split, hrestriction] + simp [booleanDirectSum, cubeSplitLinearEquiv] + have hcard : Nat.card (FABL.perpendicularSubspace E) = 2 ^ r := by + calc + Nat.card (FABL.perpendicularSubspace E) = + Nat.card (FABL.F₂Cube r) := + Nat.card_congr + (normalExtensionTailPerpendicularLinearEquiv k r).symm.toEquiv + _ = 2 ^ r := by + rw [Nat.card_eq_fintype_card, card_f₂Cube] + have hlhs : + (∑ u : FABL.perpendicularSubspace E, + FABL.vectorWalshCharacter 0 (d + u.1) * + (walshTransform f (d + u.1) : ℝ)) = + ∑ z : FABL.F₂Cube r, + (walshTransform f (Fin.append a (Fin.append 0 z)) : ℝ) := by + rw [← Fintype.sum_equiv + (normalExtensionTailPerpendicularLinearEquiv k r).toEquiv + (fun z : FABL.F₂Cube r ↦ + (walshTransform f (Fin.append a (Fin.append 0 z)) : ℝ)) + (fun u : FABL.perpendicularSubspace E ↦ + FABL.vectorWalshCharacter 0 (d + u.1) * + (walshTransform f (d + u.1) : ℝ))] + intro z + rw [normalExtensionTailPerpendicularLinearEquiv_toEquiv_apply_coe] + have hadd : + d + Fin.append 0 (Fin.append 0 z) = + Fin.append a (Fin.append 0 z) := by + apply (cubeTripleLinearEquiv k r).injective + simp [d, cubeTripleLinearEquiv, cubeSplitLinearEquiv, map_add, + funext_iff] + rw [hadd] + simp + have hzeroWalsh : + walshTransform (0 : BooleanFunction r) 0 = (2 : ℤ) ^ r := by + rw [walshTransform] + calc + (∑ x : FABL.F₂Cube r, walshTerm (0 : BooleanFunction r) 0 x) = + ∑ _x : FABL.F₂Cube r, (1 : ℤ) := by + apply Finset.sum_congr rfl + intro x _hx + norm_num [walshTerm, bitSignInt, FABL.f₂DotProduct, dotProduct] + _ = (2 : ℤ) ^ r := by simp + have hwalshLocal : + walshTransform (coordinateAffineSubspaceRestriction f E 0 e) c = + walshTransform β a * (2 : ℤ) ^ r := by + rw [hlocal, show c = Fin.append a 0 by rfl, + walshTransform_booleanDirectSum_append, hzeroWalsh] + rw [hlhs, hcard, hwalshLocal] at hpoisson + simpa [mul_assoc, mul_left_comm, mul_comm] using hpoisson + +/-- In standard extension coordinates, duality exchanges the two equal +complementary blocks. -/ +theorem bentDual_canonical_normalExtension + (β : BooleanFunction k) + (f : BooleanFunction (k + (r + r))) + (hβ : IsBent β) (hf : IsBent f) + (hrestriction : ∀ u w, + f (Fin.append u (Fin.append w 0)) = β u) + (a : FABL.F₂Cube k) (z : FABL.F₂Cube r) : + bentDual f (Fin.append a (Fin.append 0 z)) = bentDual β a := by + classical + have hhalf : (k + (r + r)) / 2 = k / 2 + r := by + rcases even_of_isBent β hβ with ⟨q, hq⟩ + omega + have hfWalsh (y : FABL.F₂Cube r) : + (walshTransform f (Fin.append a (Fin.append 0 y)) : ℝ) = + (2 : ℝ) ^ ((k + (r + r)) / 2) * + (bitSignInt + (bentDual f (Fin.append a (Fin.append 0 y))) : ℝ) := by + exact_mod_cast + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + f hf (Fin.append a (Fin.append 0 y)) + have hβWalsh : + (walshTransform β a : ℝ) = + (2 : ℝ) ^ (k / 2) * (bitSignInt (bentDual β a) : ℝ) := by + exact_mod_cast + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual β hβ a + have hsum := sum_walshTransform_canonical_normalExtension + β f hrestriction a + have hscaled : + (2 : ℝ) ^ (k / 2 + r) * + (∑ y : FABL.F₂Cube r, + (bitSignInt + (bentDual f (Fin.append a (Fin.append 0 y))) : ℝ)) = + (2 : ℝ) ^ (k / 2 + r) * + ((2 : ℝ) ^ r * (bitSignInt (bentDual β a) : ℝ)) := by + calc + (2 : ℝ) ^ (k / 2 + r) * + (∑ y : FABL.F₂Cube r, + (bitSignInt + (bentDual f (Fin.append a (Fin.append 0 y))) : ℝ)) = + ∑ y : FABL.F₂Cube r, + (walshTransform f (Fin.append a (Fin.append 0 y)) : ℝ) := by + rw [Finset.mul_sum] + apply Finset.sum_congr rfl + intro y _hy + rw [hfWalsh, hhalf] + _ = (2 : ℝ) ^ r * + ((2 : ℝ) ^ r * (walshTransform β a : ℝ)) := hsum + _ = (2 : ℝ) ^ (k / 2 + r) * + ((2 : ℝ) ^ r * (bitSignInt (bentDual β a) : ℝ)) := by + rw [hβWalsh, pow_add] + ring + have hsignSumReal : + (∑ y : FABL.F₂Cube r, + (bitSignInt + (bentDual f (Fin.append a (Fin.append 0 y))) : ℝ)) = + (2 : ℝ) ^ r * (bitSignInt (bentDual β a) : ℝ) := + mul_left_cancel₀ (by positivity : (2 : ℝ) ^ (k / 2 + r) ≠ 0) hscaled + have hsignSum : + (∑ y : FABL.F₂Cube r, + bitSignInt (bentDual f (Fin.append a (Fin.append 0 y)))) = + (2 : ℤ) ^ r * bitSignInt (bentDual β a) := by + exact_mod_cast hsignSumReal + let mismatch : BooleanFunction r := fun y ↦ + bentDual f (Fin.append a (Fin.append 0 y)) + bentDual β a + have hsignSelf : + bitSignInt (bentDual β a) * bitSignInt (bentDual β a) = 1 := by + by_cases ht : bentDual β a = 1 + · simp [bitSignInt_eq_if_one, ht] + · have htZero : bentDual β a = 0 := by + by_contra hzero + exact ht (Fin.eq_one_of_ne_zero (bentDual β a) hzero) + simp [bitSignInt_eq_if_one, htZero] + have hmismatchWalsh : walshTransform mismatch 0 = (2 : ℤ) ^ r := by + rw [walshTransform] + calc + (∑ y : FABL.F₂Cube r, walshTerm mismatch 0 y) = + ∑ y : FABL.F₂Cube r, + bitSignInt (bentDual β a) * + bitSignInt + (bentDual f (Fin.append a (Fin.append 0 y))) := by + apply Finset.sum_congr rfl + intro y _hy + rw [walshTerm] + have hdot : FABL.f₂DotProduct 0 y = 0 := by + simp [FABL.f₂DotProduct, dotProduct] + rw [hdot, add_zero] + change bitSignInt + (bentDual f (Fin.append a (Fin.append 0 y)) + bentDual β a) = + bitSignInt (bentDual β a) * + bitSignInt (bentDual f (Fin.append a (Fin.append 0 y))) + rw [bitSignInt_add] + ring + _ = bitSignInt (bentDual β a) * + ∑ y : FABL.F₂Cube r, + bitSignInt + (bentDual f (Fin.append a (Fin.append 0 y))) := by + rw [Finset.mul_sum] + _ = bitSignInt (bentDual β a) * + ((2 : ℤ) ^ r * bitSignInt (bentDual β a)) := by + rw [hsignSum] + _ = (2 : ℤ) ^ r := by + calc + bitSignInt (bentDual β a) * + ((2 : ℤ) ^ r * bitSignInt (bentDual β a)) = + (2 : ℤ) ^ r * + (bitSignInt (bentDual β a) * bitSignInt (bentDual β a)) := by + ring + _ = (2 : ℤ) ^ r := by rw [hsignSelf, mul_one] + have hmismatchWeight : hammingWeight mismatch = 0 := by + have hweight := walshTransform_zero_eq_two_pow_sub_two_weight mismatch + rw [hmismatchWalsh] at hweight + omega + have hmismatchZero : mismatch z = 0 := by + rw [hammingWeight_eq_card_support] at hmismatchWeight + by_contra hz + have hzOne : mismatch z = 1 := Fin.eq_one_of_ne_zero (mismatch z) hz + have hzMem : z ∈ support mismatch := (mem_support mismatch z).2 hzOne + have hpositive : 0 < (support mismatch).card := Finset.card_pos.mpr ⟨z, hzMem⟩ + omega + have h := congrArg (fun q : FABL.𝔽₂ ↦ q + bentDual β a) hmismatchZero + simpa [mismatch, add_assoc, ZModModule.add_self] using h + +/-- Replace the restriction on the distinguished `W₂ = 0` flat in +standard normal-extension coordinates. -/ +def canonicalNormalExtensionReplacement + (β' : BooleanFunction k) + (f : BooleanFunction (k + (r + r))) : + BooleanFunction (k + (r + r)) := fun x ↦ + let p := (Fin.appendEquiv k (r + r)).symm x + let q := (Fin.appendEquiv r r).symm p.2 + if q.2 = 0 then β' p.1 else f x + +@[simp] theorem canonicalNormalExtensionReplacement_apply_append + (β' : BooleanFunction k) + (f : BooleanFunction (k + (r + r))) + (u : FABL.F₂Cube k) (w z : FABL.F₂Cube r) : + canonicalNormalExtensionReplacement β' f + (Fin.append u (Fin.append w z)) = + if z = 0 then β' u else f (Fin.append u (Fin.append w z)) := by + simp [canonicalNormalExtensionReplacement] + +private theorem canonicalNormalExtensionReplacement_eq_on_head + (beta' : BooleanFunction k) + (f : BooleanFunction (k + (r + r))) + (x : FABL.F₂Cube (k + (r + r))) + (hx : x ∈ normalExtensionHeadSubspace k r) : + canonicalNormalExtensionReplacement beta' f x = + beta' (normalExtensionPrefixLinearMap k r x) := by + let q := cubeTripleLinearEquiv k r x + have hq : q.2.2 = 0 := + (mem_normalExtensionHeadSubspace_iff_tail_eq_zero x).1 hx + have hxSplit : Fin.append q.1 (Fin.append q.2.1 q.2.2) = x := by + exact (cubeTripleLinearEquiv k r).injective (by + simp [q, cubeTripleLinearEquiv, cubeSplitLinearEquiv]) + rw [← hxSplit, canonicalNormalExtensionReplacement_apply_append, + if_pos hq, normalExtensionPrefixLinearMap_apply] + +private theorem canonicalNormalExtensionReplacement_eq_off_head + (beta' : BooleanFunction k) + (f : BooleanFunction (k + (r + r))) + (x : FABL.F₂Cube (k + (r + r))) + (hx : x ∉ normalExtensionHeadSubspace k r) : + canonicalNormalExtensionReplacement beta' f x = f x := by + let q := cubeTripleLinearEquiv k r x + have hq : q.2.2 ≠ 0 := by + intro hzero + exact hx ((mem_normalExtensionHeadSubspace_iff_tail_eq_zero x).2 hzero) + have hxSplit : Fin.append q.1 (Fin.append q.2.1 q.2.2) = x := by + exact (cubeTripleLinearEquiv k r).injective (by + simp [q, cubeTripleLinearEquiv, cubeSplitLinearEquiv]) + rw [← hxSplit, canonicalNormalExtensionReplacement_apply_append, + if_neg hq, hxSplit] + +private theorem walshTerm_canonicalNormalExtensionReplacement_sub + (β β' : BooleanFunction k) + (f : BooleanFunction (k + (r + r))) + (hrestriction : ∀ u w, + f (Fin.append u (Fin.append w 0)) = β u) + (a u : FABL.F₂Cube k) (b z w c : FABL.F₂Cube r) : + walshTerm (canonicalNormalExtensionReplacement β' f) + (Fin.append a (Fin.append b z)) + (Fin.append u (Fin.append w c)) - + walshTerm f (Fin.append a (Fin.append b z)) + (Fin.append u (Fin.append w c)) = + if c = 0 then + (bitSignInt (β' u + FABL.f₂DotProduct a u) - + bitSignInt (β u + FABL.f₂DotProduct a u)) * + bitSignInt (FABL.f₂DotProduct b w) + else 0 := by + by_cases hc : c = 0 + · subst c + rw [if_pos rfl, walshTerm, walshTerm, + canonicalNormalExtensionReplacement_apply_append, if_pos rfl, + hrestriction, FABL.f₂DotProduct_append, + FABL.f₂DotProduct_append] + simp only [FABL.f₂DotProduct, dotProduct_zero, add_zero] + simp_rw [bitSignInt_add] + ring + · rw [if_neg hc, walshTerm, walshTerm, + canonicalNormalExtensionReplacement_apply_append, if_neg hc] + ring + +private theorem walshTransform_canonicalNormalExtensionReplacement_sub + (β β' : BooleanFunction k) + (f : BooleanFunction (k + (r + r))) + (hrestriction : ∀ u w, + f (Fin.append u (Fin.append w 0)) = β u) + (a : FABL.F₂Cube k) (b z : FABL.F₂Cube r) : + walshTransform (canonicalNormalExtensionReplacement β' f) + (Fin.append a (Fin.append b z)) - + walshTransform f (Fin.append a (Fin.append b z)) = + (walshTransform β' a - walshTransform β a) * + walshTransform (0 : BooleanFunction r) b := by + classical + rw [walshTransform, walshTransform, ← Finset.sum_sub_distrib] + calc + (∑ x : FABL.F₂Cube (k + (r + r)), + (walshTerm (canonicalNormalExtensionReplacement β' f) + (Fin.append a (Fin.append b z)) x - + walshTerm f (Fin.append a (Fin.append b z)) x)) = + ∑ p : FABL.F₂Cube k × (FABL.F₂Cube r × FABL.F₂Cube r), + (walshTerm (canonicalNormalExtensionReplacement β' f) + (Fin.append a (Fin.append b z)) + (Fin.append p.1 (Fin.append p.2.1 p.2.2)) - + walshTerm f (Fin.append a (Fin.append b z)) + (Fin.append p.1 (Fin.append p.2.1 p.2.2))) := by + apply Fintype.sum_equiv (cubeTripleLinearEquiv k r).toEquiv + intro x + have hx : + Fin.append ((cubeTripleLinearEquiv k r x).1) + (Fin.append (cubeTripleLinearEquiv k r x).2.1 + (cubeTripleLinearEquiv k r x).2.2) = x := by + apply (cubeTripleLinearEquiv k r).injective + simp [cubeTripleLinearEquiv, cubeSplitLinearEquiv] + exact (congrArg + (fun y ↦ + walshTerm (canonicalNormalExtensionReplacement β' f) + (Fin.append a (Fin.append b z)) y - + walshTerm f (Fin.append a (Fin.append b z)) y) hx).symm + _ = ∑ u : FABL.F₂Cube k, + ∑ w : FABL.F₂Cube r, + ∑ c : FABL.F₂Cube r, + (walshTerm (canonicalNormalExtensionReplacement β' f) + (Fin.append a (Fin.append b z)) + (Fin.append u (Fin.append w c)) - + walshTerm f (Fin.append a (Fin.append b z)) + (Fin.append u (Fin.append w c))) := by + rw [Fintype.sum_prod_type] + apply Finset.sum_congr rfl + intro u _hu + rw [Fintype.sum_prod_type] + _ = ∑ u : FABL.F₂Cube k, + ∑ w : FABL.F₂Cube r, + (bitSignInt (β' u + FABL.f₂DotProduct a u) - + bitSignInt (β u + FABL.f₂DotProduct a u)) * + bitSignInt (FABL.f₂DotProduct b w) := by + apply Finset.sum_congr rfl + intro u _hu + apply Finset.sum_congr rfl + intro w _hw + simp_rw [walshTerm_canonicalNormalExtensionReplacement_sub + β β' f hrestriction a u b z w] + simp + _ = (∑ u : FABL.F₂Cube k, + (bitSignInt (β' u + FABL.f₂DotProduct a u) - + bitSignInt (β u + FABL.f₂DotProduct a u))) * + ∑ w : FABL.F₂Cube r, + bitSignInt (FABL.f₂DotProduct b w) := by + rw [Finset.sum_mul] + apply Finset.sum_congr rfl + intro u _hu + rw [Finset.mul_sum] + _ = (walshTransform β' a - walshTransform β a) * + walshTransform (0 : BooleanFunction r) b := by + congr 1 + · rw [walshTransform, walshTransform, + ← Finset.sum_sub_distrib] + rfl + · rw [walshTransform] + apply Finset.sum_congr rfl + intro w _hw + simp [walshTerm, FABL.f₂DotProduct, dotProduct] + +/-- Carlet Proposition 31 in standard decomposition coordinates: replacing +the smaller bent restriction preserves bentness. -/ +theorem isBent_canonicalNormalExtensionReplacement + (β β' : BooleanFunction k) + (f : BooleanFunction (k + (r + r))) + (hβ : IsBent β) (hβ' : IsBent β') (hf : IsBent f) + (hrestriction : ∀ u w, + f (Fin.append u (Fin.append w 0)) = β u) : + IsBent (canonicalNormalExtensionReplacement β' f) := by + classical + apply (isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half + (canonicalNormalExtensionReplacement β' f)).2 + intro x + let q := cubeTripleLinearEquiv k r x + have hx : Fin.append q.1 (Fin.append q.2.1 q.2.2) = x := by + change (cubeTripleLinearEquiv k r).symm q = x + exact (cubeTripleLinearEquiv k r).symm_apply_apply x + rw [← hx] + have hzeroWalsh : + walshTransform (0 : BooleanFunction r) q.2.1 = + if q.2.1 = 0 then (2 : ℤ) ^ r else 0 := by + have hzeroFunction : + (0 : BooleanFunction r) = FABL.affineFunction 0 0 := by + funext y + simp [FABL.affineFunction, FABL.f₂DotProduct, dotProduct] + rw [hzeroFunction, walshTransform_affineFunction] + simp [bitSignInt_eq_if_one] + have hdifference := walshTransform_canonicalNormalExtensionReplacement_sub + β β' f hrestriction q.1 q.2.1 q.2.2 + by_cases hq : q.2.1 = 0 + · have hhalf : (k + (r + r)) / 2 = k / 2 + r := by + rcases even_of_isBent β hβ with ⟨s, hs⟩ + omega + have hrawF := + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + f hf (Fin.append q.1 (Fin.append q.2.1 q.2.2)) + have hdual := bentDual_canonical_normalExtension + β f hβ hf hrestriction q.1 q.2.2 + have hrawβ := + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual β hβ q.1 + have hrawβ' := + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual β' hβ' q.1 + rw [hq, if_pos rfl] at hzeroWalsh + rw [hq] at hrawF hdifference + rw [hdual] at hrawF + rw [hzeroWalsh] at hdifference + have hreplacement : + walshTransform (canonicalNormalExtensionReplacement β' f) + (Fin.append q.1 (Fin.append 0 q.2.2)) = + (2 : ℤ) ^ ((k + (r + r)) / 2) * + bitSignInt (bentDual β' q.1) := by + calc + walshTransform (canonicalNormalExtensionReplacement β' f) + (Fin.append q.1 (Fin.append 0 q.2.2)) = + walshTransform f (Fin.append q.1 (Fin.append 0 q.2.2)) + + (walshTransform β' q.1 - walshTransform β q.1) * + (2 : ℤ) ^ r := by + omega + _ = (2 : ℤ) ^ ((k + (r + r)) / 2) * + bitSignInt (bentDual β' q.1) := by + rw [hrawF, hrawβ, hrawβ', hhalf, pow_add] + ring + rw [hq, hreplacement, Int.natAbs_mul, Int.natAbs_pow] + have hsign : (bitSignInt (bentDual β' q.1)).natAbs = 1 := by + rw [bitSignInt_eq_if_one] + split <;> simp + rw [hsign, mul_one] + norm_num + · rw [if_neg hq] at hzeroWalsh + rw [hzeroWalsh, mul_zero] at hdifference + have heq : + walshTransform (canonicalNormalExtensionReplacement β' f) + (Fin.append q.1 (Fin.append q.2.1 q.2.2)) = + walshTransform f (Fin.append q.1 (Fin.append q.2.1 q.2.2)) := by + omega + rw [heq] + exact natAbs_walshTransform_eq_two_pow_half_of_isBent f hf _ + +/-- Carlet Definition 8, expressed invariantly under a linear choice of +coordinates for the decomposition `V = U ⊕ W₁ ⊕ W₂`. -/ +def IsNormalExtension + (β : BooleanFunction k) (f : BooleanFunction n) : Prop := + IsBent β ∧ IsBent f ∧ + ∃ m : ℕ, + ∃ L : FABL.F₂Cube (k + (m + m)) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube n, + ∀ u w, + f (L (Fin.append u (Fin.append w 0))) = β u + +/-- The Boolean function on the zero-dimensional cube with value `ε`. -/ +def zeroDimensionalBooleanFunction (ε : FABL.𝔽₂) : BooleanFunction 0 := + fun _ ↦ ε + +@[simp] theorem zeroDimensionalBooleanFunction_apply + (ε : FABL.𝔽₂) (x : FABL.F₂Cube 0) : + zeroDimensionalBooleanFunction ε x = ε := + rfl + +/-- Every Boolean function on the zero-dimensional cube is bent. -/ +theorem isBent_zeroDimensionalBooleanFunction (ε : FABL.𝔽₂) : + IsBent (zeroDimensionalBooleanFunction ε) := by + apply (isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half + (zeroDimensionalBooleanFunction ε)).2 + intro a + have ha : a = 0 := Subsingleton.elim _ _ + subst a + fin_cases ε <;> + simp [walshTransform, walshTerm, zeroDimensionalBooleanFunction, + bitSignInt_eq_if_one, FABL.f₂DotProduct, dotProduct] <;> + split <;> simp + +/-- The linear-subspace convention for normality used in Carlet Section 6.9: +`f` is constant on a subspace of half the ambient dimension. -/ +def IsSubspaceNormal (f : BooleanFunction n) : Prop := + ∃ H : Submodule FABL.𝔽₂ (FABL.F₂Cube n), + Module.finrank FABL.𝔽₂ H = n / 2 ∧ + IsConstantOnAffineFlat f H 0 + +/-- Linear changes of input coordinates preserve the linear-subspace +normality convention of Section 6.9. -/ +theorem isSubspaceNormal_comp_linearEquiv_iff + (f : BooleanFunction n) + (L : FABL.F₂Cube n ≃ₗ[FABL.𝔽₂] FABL.F₂Cube n) : + IsSubspaceNormal (f ∘ L) ↔ IsSubspaceNormal f := by + classical + have transport + (g : BooleanFunction n) + (A : FABL.F₂Cube n ≃ₗ[FABL.𝔽₂] FABL.F₂Cube n) + (h : IsSubspaceNormal (g ∘ A)) : IsSubspaceNormal g := by + obtain ⟨H, hHrank, c, hconstant⟩ := h + let K := H.map A.toLinearMap + refine ⟨K, ?_, c, ?_⟩ + · dsimp [K] + rw [LinearEquiv.finrank_map_eq, hHrank] + · intro y hy + have hyK : y ∈ K := by + simpa [FABL.mem_binaryAffineSubspace_iff_add_mem] using hy + obtain ⟨x, hxH, hxy⟩ := hyK + have hxFlat : x ∈ FABL.binaryAffineSubspace H 0 := by + simpa [FABL.mem_binaryAffineSubspace_iff_add_mem] using hxH + have hxValue := hconstant x hxFlat + change g (A x) = c at hxValue + change A x = y at hxy + rw [hxy] at hxValue + exact hxValue + constructor + · exact transport f L + · intro hf + apply transport (f ∘ L) L.symm + convert hf using 1 + funext x + simp + +private theorem exists_superSubspace_finrank_eq + (H : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hHk : Module.finrank FABL.𝔽₂ H ≤ k) + (hkn : k ≤ n) : + ∃ P : Submodule FABL.𝔽₂ (FABL.F₂Cube n), + H ≤ P ∧ Module.finrank FABL.𝔽₂ P = k := by + have hambient : Module.finrank FABL.𝔽₂ (FABL.F₂Cube n) = n := by + simp [Module.finrank_fintype_fun_eq_card] + induction k, hHk using Nat.le_induction with + | base => exact ⟨H, le_rfl, rfl⟩ + | succ k _hk ih => + have hkn' : k ≤ n := (Nat.le_succ k).trans hkn + obtain ⟨P, hHP, hPrank⟩ := ih hkn' + have hPambient : Module.finrank FABL.𝔽₂ P < + Module.finrank FABL.𝔽₂ (FABL.F₂Cube n) := by + rw [hPrank, hambient] + exact hkn + obtain ⟨v, hv⟩ := P.exists_of_finrank_lt hPambient + have hvP : v ∉ P := by simpa using hv 1 one_ne_zero + let Q := P ⊔ Submodule.span FABL.𝔽₂ {v} + refine ⟨Q, hHP.trans le_sup_left, ?_⟩ + dsimp [Q] + rw [Submodule.finrank_sup_span_singleton hvP, hPrank] + +private theorem exists_subspace_le_finrank_eq + (H : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hk : k ≤ Module.finrank FABL.𝔽₂ H) : + ∃ P : Submodule FABL.𝔽₂ (FABL.F₂Cube n), + P ≤ H ∧ Module.finrank FABL.𝔽₂ P = k := by + obtain ⟨v, hv⟩ := exists_linearIndependent_of_le_finrank hk + let w : Fin k → FABL.F₂Cube n := fun i ↦ (v i).1 + have hw : LinearIndependent FABL.𝔽₂ w := by + exact hv.map' H.subtype (Submodule.ker_subtype H) + let P := Submodule.span FABL.𝔽₂ (Set.range w) + refine ⟨P, ?_, ?_⟩ + · apply Submodule.span_le.2 + rintro x ⟨i, rfl⟩ + exact (v i).2 + · dsimp [P] + rw [finrank_span_eq_card hw] + simp + +private theorem exists_bent_eq_zero_on_subspace + (H : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hn : Even n) + (hH : Module.finrank FABL.𝔽₂ H ≤ n / 2) : + ∃ γ : BooleanFunction n, IsBent γ ∧ + ∀ x ∈ H, γ x = 0 := by + rcases hn with ⟨d, rfl⟩ + have hhalf : (d + d) / 2 = d := by omega + rw [hhalf] at hH + obtain ⟨P, hHP, hPrank⟩ := + exists_superSubspace_finrank_eq H hH (by omega) + obtain ⟨Q, hcompl⟩ := P.exists_isCompl + have hQrank : Module.finrank FABL.𝔽₂ Q = d := by + have hsum : Module.finrank FABL.𝔽₂ P + + Module.finrank FABL.𝔽₂ Q = d + d := by + simpa [Module.finrank_fintype_fun_eq_card] using + Submodule.finrank_add_eq_of_isCompl hcompl + rw [hPrank] at hsum + omega + let eP : FABL.F₂Cube d ≃ₗ[FABL.𝔽₂] P := + LinearEquiv.ofFinrankEq _ _ (by + simp [hPrank, Module.finrank_fintype_fun_eq_card]) + let eQ : FABL.F₂Cube d ≃ₗ[FABL.𝔽₂] Q := + LinearEquiv.ofFinrankEq _ _ (by + simp [hQrank, Module.finrank_fintype_fun_eq_card]) + let L : FABL.F₂Cube (d + d) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube (d + d) := + (cubeSplitLinearEquiv d d).trans + ((eP.prodCongr eQ).trans (P.prodEquivOfIsCompl Q hcompl)) + let base : BooleanFunction (d + d) := FABL.innerProductModTwoBit + let γ : BooleanFunction (d + d) := base ∘ L.symm + have hbase : IsBent base := by + change FABL.IsBent (FABL.innerProductModTwo d) + exact FABL.isBent_innerProductModTwo d + have hγ : IsBent γ := + (isBent_comp_affineEquiv_iff base L.symm.toAffineEquiv).2 hbase + refine ⟨γ, hγ, ?_⟩ + intro x hx + have hxP : x ∈ P := hHP hx + let u : FABL.F₂Cube d := eP.symm ⟨x, hxP⟩ + have hL : L (Fin.append u 0) = x := by + change (P.prodEquivOfIsCompl Q hcompl) + ((eP.prodCongr eQ) + ((cubeSplitLinearEquiv d d) (Fin.append u 0))) = x + simp [cubeSplitLinearEquiv, u, funext_iff] + change base (L.symm x) = 0 + rw [← hL, L.symm_apply_apply] + change FABL.innerProductModTwoBit + (FABL.joinF₂CubeBlocks u 0) = 0 + rw [FABL.innerProductModTwoBit_joinF₂CubeBlocks] + simp [FABL.f₂DotProduct, dotProduct] + +/-- The affine-input closure of normal extension. It retains Definition 8 +after choosing an affinely equivalent representative of the ambient bent +function. -/ +def IsAffineNormalExtension + (β : BooleanFunction k) (f : BooleanFunction n) : Prop := + ∃ A : FABL.F₂Cube n ≃ᵃ[FABL.𝔽₂] FABL.F₂Cube n, + IsNormalExtension β (f ∘ A) + +/-- Normality on affine flats is invariant under an affine change of input +coordinates. -/ +theorem isKNormal_comp_affineEquiv_iff + (f : BooleanFunction n) + (A : FABL.F₂Cube n ≃ᵃ[FABL.𝔽₂] FABL.F₂Cube n) : + IsKNormal (f ∘ A) k ↔ IsKNormal f k := by + classical + have transport + (g : BooleanFunction n) + (B : FABL.F₂Cube n ≃ᵃ[FABL.𝔽₂] FABL.F₂Cube n) + (h : IsKNormal (g ∘ B) k) : IsKNormal g k := by + obtain ⟨H, a, hHrank, b, hconstant⟩ := h + let K : Submodule FABL.𝔽₂ (FABL.F₂Cube n) := + H.map B.linear.toLinearMap + refine ⟨K, B a, ?_, b, ?_⟩ + · dsimp [K] + rw [LinearEquiv.finrank_map_eq, hHrank] + · intro y hy + have hyK : y + B a ∈ K := + (FABL.mem_binaryAffineSubspace_iff_add_mem K (B a) y).1 hy + let x : FABL.F₂Cube n := B.linear.symm (y + B a) + have hxH : x ∈ H := by + dsimp [K] at hyK + rw [Submodule.map_equiv_eq_comap_symm] at hyK + exact hyK + have hxa : x + a ∈ FABL.binaryAffineSubspace H a := by + rw [FABL.mem_binaryAffineSubspace_iff_add_mem] + rw [add_assoc, ZModModule.add_self, add_zero] + exact hxH + have hBy : B (x + a) = y := by + calc + B (x + a) = B.linear x + B a := by + simpa using B.map_vadd a x + _ = y := by + dsimp [x] + rw [LinearEquiv.apply_symm_apply, add_assoc, + ZModModule.add_self, add_zero] + have hvalue := hconstant (x + a) hxa + change g (B (x + a)) = b at hvalue + simpa [hBy] using hvalue + constructor + · exact transport f A + · intro hf + apply transport (f ∘ A) A.symm + convert hf using 1 + funext x + simp + +/-- Under the linear-subspace convention of Section 6.9, a bent function is +normal exactly when a zero-dimensional constant bent function normally +extends to it. -/ +theorem exists_isNormalExtension_zeroDimensional_iff_isSubspaceNormal + (f : BooleanFunction n) (hf : IsBent f) : + (∃ ε : FABL.𝔽₂, + IsNormalExtension (zeroDimensionalBooleanFunction ε) f) ↔ + IsSubspaceNormal f := by + classical + constructor + · rintro ⟨ε, _hεBent, _hf, m, L, hrestriction⟩ + let H : Submodule FABL.𝔽₂ (FABL.F₂Cube n) := + (normalExtensionHeadSubspace 0 m).map L.toLinearMap + have hambient : m + m = n := by + have hfinrank := LinearEquiv.finrank_eq L + simpa [Module.finrank_fintype_fun_eq_card] using hfinrank + have hhalf : n / 2 = m := by omega + refine ⟨H, ?_, ε, ?_⟩ + · dsimp [H] + rw [LinearEquiv.finrank_map_eq] + have hhead := + LinearEquiv.finrank_eq (normalExtensionHeadSubspaceLinearEquiv 0 m) + simpa [Module.finrank_fintype_fun_eq_card, hhalf] using hhead.symm + · intro x hx + have hxH : x ∈ H := by + simpa [FABL.mem_binaryAffineSubspace_iff_add_mem] using hx + obtain ⟨y, hy, rfl⟩ := hxH + obtain ⟨z, rfl⟩ := hy + let q := cubeSplitLinearEquiv 0 m z + have hz : + normalExtensionHeadLinearMap 0 m z = + Fin.append q.1 (Fin.append q.2 0) := by + exact normalExtensionHeadLinearMap_apply_split z + rw [hz] + simpa using hrestriction q.1 q.2 + · rintro ⟨H, hHrank, ε, hconstant⟩ + obtain ⟨H', hcompl⟩ := H.exists_isCompl + let m := n / 2 + have hnEven := even_of_isBent f hf + have hdouble : m + m = n := by + rcases hnEven with ⟨t, rfl⟩ + omega + have hH'rank : Module.finrank FABL.𝔽₂ H' = m := by + have hsum : Module.finrank FABL.𝔽₂ H + + Module.finrank FABL.𝔽₂ H' = n := by + simpa [Module.finrank_fintype_fun_eq_card] using + Submodule.finrank_add_eq_of_isCompl hcompl + rw [hHrank] at hsum + omega + let eH : FABL.F₂Cube m ≃ₗ[FABL.𝔽₂] H := + LinearEquiv.ofFinrankEq _ _ (by + simp [m, hHrank, Module.finrank_fintype_fun_eq_card]) + let eH' : FABL.F₂Cube m ≃ₗ[FABL.𝔽₂] H' := + LinearEquiv.ofFinrankEq _ _ (by + simp [hH'rank, Module.finrank_fintype_fun_eq_card]) + let L : FABL.F₂Cube (0 + (m + m)) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube n := + (cubeSplitLinearEquiv 0 (m + m)).trans + ((LinearEquiv.uniqueProd (R := FABL.𝔽₂)).trans + ((cubeSplitLinearEquiv m m).trans + ((eH.prodCongr eH').trans + (H.prodEquivOfIsCompl H' hcompl)))) + refine ⟨ε, isBent_zeroDimensionalBooleanFunction ε, hf, m, L, ?_⟩ + intro u w + have hu : u = 0 := Subsingleton.elim _ _ + subst u + have houter : + (cubeSplitLinearEquiv 0 (m + m)) + (Fin.append 0 (Fin.append w 0)) = + (0, Fin.append w 0) := by + exact (Fin.appendEquiv 0 (m + m)).symm_apply_apply + (0, Fin.append w 0) + have hcoordinates : + (cubeSplitLinearEquiv m m) + ((LinearEquiv.uniqueProd + (R := FABL.𝔽₂) (M := FABL.F₂Cube (m + m)) + (M₂ := FABL.F₂Cube 0)) + ((cubeSplitLinearEquiv 0 (m + m)) + (Fin.append 0 (Fin.append w 0)))) = + (w, 0) := by + rw [houter] + exact (Fin.appendEquiv m m).symm_apply_apply (w, 0) + have hL : + L (Fin.append 0 (Fin.append w 0)) = (eH w : FABL.F₂Cube n) := by + change (H.prodEquivOfIsCompl H' hcompl) + ((eH.prodCongr eH') + ((cubeSplitLinearEquiv m m) + ((LinearEquiv.uniqueProd + (R := FABL.𝔽₂) (M := FABL.F₂Cube (m + m)) + (M₂ := FABL.F₂Cube 0)) + ((cubeSplitLinearEquiv 0 (m + m)) + (Fin.append 0 (Fin.append w 0)))))) = _ + rw [hcoordinates] + simp + rw [hL] + apply hconstant + rw [FABL.mem_binaryAffineSubspace_iff_add_mem] + simpa only [add_zero] using (eH w).2 + +/-- With Chapter 5's affine-flat definition of normality, the +zero-dimensional characterization of Section 6.9 holds after taking the +affine-input closure of the normal-extension relation. -/ +theorem exists_isAffineNormalExtension_zeroDimensional_iff_isKNormal + (f : BooleanFunction n) (hf : IsBent f) : + (∃ ε : FABL.𝔽₂, + IsAffineNormalExtension (zeroDimensionalBooleanFunction ε) f) ↔ + IsKNormal f (n / 2) := by + constructor + · rintro ⟨ε, A, hextension⟩ + have hsubspace : IsSubspaceNormal (f ∘ A) := + (exists_isNormalExtension_zeroDimensional_iff_isSubspaceNormal + (f ∘ A) hextension.2.1).1 ⟨ε, hextension⟩ + obtain ⟨H, hHrank, hconstant⟩ := hsubspace + apply (isKNormal_comp_affineEquiv_iff f A).1 + exact ⟨H, 0, hHrank, hconstant⟩ + · rintro ⟨H, a, hHrank, ε, hconstant⟩ + let A : FABL.F₂Cube n ≃ᵃ[FABL.𝔽₂] FABL.F₂Cube n := + AffineEquiv.constVAdd FABL.𝔽₂ (FABL.F₂Cube n) a + have hAf : IsBent (f ∘ A) := + (isBent_comp_affineEquiv_iff f A).2 hf + have hsubspace : IsSubspaceNormal (f ∘ A) := by + refine ⟨H, hHrank, ε, ?_⟩ + intro x hx + apply hconstant + rw [FABL.mem_binaryAffineSubspace_iff_add_mem] at hx ⊢ + have hxH : x ∈ H := by simpa only [add_zero] using hx + change a + x + a ∈ H + rw [add_comm a x, add_assoc, ZModModule.add_self, add_zero] + exact hxH + obtain ⟨δ, hextension⟩ := + (exists_isNormalExtension_zeroDimensional_iff_isSubspaceNormal + (f ∘ A) hAf).2 hsubspace + exact ⟨δ, A, hextension⟩ + +private def affineOnlyNormalBentExample : BooleanFunction 2 := + fun x ↦ (x 0 + 1) * (x 1 + 1) + +private theorem isBent_affineOnlyNormalBentExample : + IsBent affineOnlyNormalBentExample := by + let oneVector : FABL.F₂Cube 2 := fun _ ↦ 1 + have hfunction : affineOnlyNormalBentExample = + (FABL.completeQuadraticBit : BooleanFunction 2) + + FABL.affineFunction 1 oneVector := by + funext x + rw [Pi.add_apply, completeQuadraticBit_two_dimension] + simp [affineOnlyNormalBentExample, FABL.affineFunction, + FABL.f₂DotProduct, dotProduct, oneVector, Fin.sum_univ_two] + ring + rw [hfunction] + exact (isBent_add_affineFunction_iff + (FABL.completeQuadraticBit : BooleanFunction 2) 1 oneVector).2 + isBent_completeQuadraticBit_two_dimension + +@[simp] private theorem affineOnlyNormalBentExample_zero : + affineOnlyNormalBentExample 0 = 1 := by + simp [affineOnlyNormalBentExample] + +private theorem affineOnlyNormalBentExample_eq_zero_of_ne_zero + (x : FABL.F₂Cube 2) (hx : x ≠ 0) : + affineOnlyNormalBentExample x = 0 := by + have hfirst : x 0 = 0 ∨ x 0 = 1 := by + by_cases h : x 0 = 0 + · exact Or.inl h + · exact Or.inr (Fin.eq_one_of_ne_zero (x 0) h) + have hsecond : x 1 = 0 ∨ x 1 = 1 := by + by_cases h : x 1 = 0 + · exact Or.inl h + · exact Or.inr (Fin.eq_one_of_ne_zero (x 1) h) + rcases hfirst with hfirst | hfirst <;> + rcases hsecond with hsecond | hsecond + · exfalso + apply hx + funext i + fin_cases i <;> assumption + · simp [affineOnlyNormalBentExample, hfirst, hsecond] + · simp [affineOnlyNormalBentExample, hfirst, hsecond] + · simp [affineOnlyNormalBentExample, hfirst, hsecond] + +private theorem isKNormal_affineOnlyNormalBentExample : + IsKNormal affineOnlyNormalBentExample 1 := by + let e₀ : FABL.F₂Cube 2 := Pi.single 0 1 + let e₁ : FABL.F₂Cube 2 := Pi.single 1 1 + let H : Submodule FABL.𝔽₂ (FABL.F₂Cube 2) := FABL.𝔽₂ ∙ e₁ + have he₁ : e₁ ≠ 0 := by + intro h + have hcoordinate := congrFun h 1 + simp [e₁] at hcoordinate + refine ⟨H, e₀, ?_, 0, ?_⟩ + · exact finrank_span_singleton he₁ + · intro x hx + have hxH : x + e₀ ∈ H := + (FABL.mem_binaryAffineSubspace_iff_add_mem H e₀ x).1 hx + obtain ⟨c, hc⟩ := Submodule.mem_span_singleton.mp hxH + have hxEq : x = c • e₁ + e₀ := by + calc + x = (x + e₀) + e₀ := by + rw [add_assoc, ZModModule.add_self, add_zero] + _ = c • e₁ + e₀ := by rw [hc] + rw [hxEq] + simp [affineOnlyNormalBentExample, e₀, e₁] + +private theorem not_isSubspaceNormal_affineOnlyNormalBentExample : + ¬ IsSubspaceNormal affineOnlyNormalBentExample := by + rintro ⟨H, hHrank, b, hconstant⟩ + have hpositive : 0 < Module.finrank FABL.𝔽₂ H := by + norm_num at hHrank + omega + obtain ⟨v, hv⟩ := + (Module.finrank_pos_iff_exists_ne_zero (R := FABL.𝔽₂) (M := H)).1 + hpositive + have hvAmbient : (v.1 : FABL.F₂Cube 2) ≠ 0 := by + exact fun h ↦ hv (Subtype.ext h) + have hzeroMem : + (0 : FABL.F₂Cube 2) ∈ FABL.binaryAffineSubspace H 0 := by + rw [FABL.mem_binaryAffineSubspace_iff_add_mem] + exact H.zero_mem + have hvMem : + (v.1 : FABL.F₂Cube 2) ∈ FABL.binaryAffineSubspace H 0 := by + rw [FABL.mem_binaryAffineSubspace_iff_add_mem] + simpa only [add_zero] using v.2 + have hzero := hconstant 0 hzeroMem + have hvValue := hconstant v.1 hvMem + rw [affineOnlyNormalBentExample_zero] at hzero + rw [affineOnlyNormalBentExample_eq_zero_of_ne_zero v.1 hvAmbient] at hvValue + have : (1 : FABL.𝔽₂) = 0 := hzero.trans hvValue.symm + exact one_ne_zero this + +/-- Chapter 5 affine-flat normality does not imply the unclosed statement +`ε ⊑ f`: a translated two-variable quadratic bent function is normal only +on affine lines and on no one-dimensional linear subspace. -/ +theorem exists_isKNormal_not_isNormalExtension_zeroDimensional : + ∃ f : BooleanFunction 2, + IsBent f ∧ IsKNormal f 1 ∧ + ¬ ∃ ε : FABL.𝔽₂, + IsNormalExtension (zeroDimensionalBooleanFunction ε) f := by + refine ⟨affineOnlyNormalBentExample, + isBent_affineOnlyNormalBentExample, + isKNormal_affineOnlyNormalBentExample, ?_⟩ + rw [exists_isNormalExtension_zeroDimensional_iff_isSubspaceNormal + affineOnlyNormalBentExample isBent_affineOnlyNormalBentExample] + exact not_isSubspaceNormal_affineOnlyNormalBentExample + +/-- A normal extension includes bentness of its smaller function. -/ +theorem IsNormalExtension.isBent_left + {β : BooleanFunction k} {f : BooleanFunction n} + (h : IsNormalExtension β f) : IsBent β := + h.1 + +/-- A normal extension includes bentness of its larger function. -/ +theorem IsNormalExtension.isBent_right + {β : BooleanFunction k} {f : BooleanFunction n} + (h : IsNormalExtension β f) : IsBent f := + h.2.1 + +/-- Every bent function is a zero-codimension normal extension of itself. -/ +theorem isNormalExtension_refl + (f : BooleanFunction n) (hf : IsBent f) : + IsNormalExtension f f := by + refine ⟨hf, hf, 0, LinearEquiv.refl FABL.𝔽₂ (FABL.F₂Cube n), ?_⟩ + intro u w + congr 1 + rw [Fin.append_right_nil u (Fin.append w 0) rfl] + rfl + +/-- Carlet's normal-extension relation is transitive. -/ +theorem IsNormalExtension.trans + {β : BooleanFunction k} {f : BooleanFunction n} + {g : BooleanFunction p} + (hβf : IsNormalExtension β f) (hfg : IsNormalExtension f g) : + IsNormalExtension β g := by + obtain ⟨hβ, hf, r, L, hL⟩ := hβf + obtain ⟨_hf, hg, s, M, hM⟩ := hfg + refine ⟨hβ, hg, r + s, normalExtensionTransLinearEquiv L M, ?_⟩ + intro u w + let y := (cubeSplitLinearEquiv r s) w + have happly : + normalExtensionTransLinearEquiv L M + (Fin.append u (Fin.append w 0)) = + M (Fin.append + (L (Fin.append u (Fin.append y.1 0))) + (Fin.append y.2 0)) := by + dsimp [normalExtensionTransLinearEquiv] + refine congrArg M ?_ + apply (cubeTripleLinearEquiv n s).injective + suffices + Fin.append (fun i ↦ u i) + (Fin.append (fun i ↦ w (Fin.castAdd s i)) (fun _i ↦ 0)) = + Fin.append u (Fin.append (fun i ↦ w (Fin.castAdd s i)) 0) by + simpa [normalExtensionReassociationLinearEquiv, cubeTripleLinearEquiv, + cubeSplitLinearEquiv, Fin.appendEquiv, y] using this + rfl + rw [happly] + rw [hM, hL] + +/-- Normal extension is preserved by bent duality; the two complementary +directions are exchanged by the dual coordinate decomposition. -/ +theorem IsNormalExtension.bentDual + {β : BooleanFunction k} {f : BooleanFunction n} + (h : IsNormalExtension β f) : + IsNormalExtension (CryptBoolean.bentDual β) + (CryptBoolean.bentDual f) := by + obtain ⟨hβ, hf, m, L, hrestriction⟩ := h + have hdim : k + (m + m) = n := by + have hfinrank := LinearEquiv.finrank_eq L + simpa [Module.finrank_fintype_fun_eq_card] using hfinrank + subst n + let g : BooleanFunction (k + (m + m)) := f ∘ L + have hg : IsBent g := by + exact (isBent_comp_affineEquiv_iff f L.toAffineEquiv).2 hf + let Ldual : FABL.F₂Cube (k + (m + m)) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube (k + (m + m)) := + (normalExtensionAuxiliarySwapLinearEquiv k m).trans + (walshAdjointLinearEquiv L.symm) + refine ⟨isBent_bentDual β hβ, isBent_bentDual f hf, m, Ldual, ?_⟩ + intro u w + change CryptBoolean.bentDual f + (walshAdjointLinearEquiv L.symm + (normalExtensionAuxiliarySwapLinearEquiv k m + (Fin.append u (Fin.append w 0)))) = + CryptBoolean.bentDual β u + rw [normalExtensionAuxiliarySwapLinearEquiv_apply] + rw [← bentDual_comp_linearEquiv f L] + exact bentDual_canonical_normalExtension β g hβ hg hrestriction u w + +/-- Replace the distinguished restriction of a normal extension after +transporting to the coordinates of its direct-sum decomposition. -/ +def normalExtensionReplacement + (β' : BooleanFunction k) (f : BooleanFunction n) + (L : FABL.F₂Cube (k + (r + r)) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube n) : + BooleanFunction n := + canonicalNormalExtensionReplacement β' (f ∘ L) ∘ L.symm + +@[simp] theorem normalExtensionReplacement_apply + (β' : BooleanFunction k) (f : BooleanFunction n) + (L : FABL.F₂Cube (k + (r + r)) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube n) + (u : FABL.F₂Cube k) (w : FABL.F₂Cube r) : + normalExtensionReplacement β' f L + (L (Fin.append u (Fin.append w 0))) = β' u := by + simp [normalExtensionReplacement, + canonicalNormalExtensionReplacement_apply_append] + +/-- Carlet Proposition 31: the restriction of a normal extension can be +replaced by any bent function on the smaller space. -/ +theorem normalExtensionReplacement_isNormalExtension + (β β' : BooleanFunction k) (f : BooleanFunction n) + (hβ : IsBent β) (hβ' : IsBent β') (hf : IsBent f) + (L : FABL.F₂Cube (k + (r + r)) ≃ₗ[FABL.𝔽₂] FABL.F₂Cube n) + (hrestriction : ∀ u w, + f (L (Fin.append u (Fin.append w 0))) = β u) : + IsNormalExtension β' (normalExtensionReplacement β' f L) := by + have hdim : k + (r + r) = n := by + have hfinrank := LinearEquiv.finrank_eq L + simpa [Module.finrank_fintype_fun_eq_card] using hfinrank + subst n + let g : BooleanFunction (k + (r + r)) := f ∘ L + have hg : IsBent g := + (isBent_comp_affineEquiv_iff f L.toAffineEquiv).2 hf + have hgrestriction : ∀ u w, + g (Fin.append u (Fin.append w 0)) = β u := hrestriction + have hcanonical : + IsBent (canonicalNormalExtensionReplacement β' g) := + isBent_canonicalNormalExtensionReplacement + β β' g hβ hβ' hg hgrestriction + have hreplacement : + IsBent (normalExtensionReplacement β' f L) := by + exact (isBent_comp_affineEquiv_iff + (canonicalNormalExtensionReplacement β' g) + L.symm.toAffineEquiv).2 hcanonical + refine ⟨hβ', hreplacement, r, L, ?_⟩ + exact normalExtensionReplacement_apply β' f L + +private theorem half_le_finrank_projectedIntersection + (beta : BooleanFunction k) + (f : BooleanFunction (k + (r + r))) + (hbeta : IsBent beta) (hf : IsBent f) + (hrestriction : ∀ u w, + f (Fin.append u (Fin.append w 0)) = beta u) + (N : Submodule FABL.𝔽₂ (FABL.F₂Cube (k + (r + r)))) + (hNrank : Module.finrank FABL.𝔽₂ N = (k + (r + r)) / 2) + (c : FABL.𝔽₂) + (hconstant : ∀ x ∈ FABL.binaryAffineSubspace N 0, f x = c) : + k / 2 ≤ Module.finrank FABL.𝔽₂ + (normalExtensionProjectedIntersection N) := by + classical + rcases even_of_isBent beta hbeta with ⟨d, hd⟩ + subst k + have hhalf : (d + d) / 2 = d := by omega + have htotalHalf : ((d + d) + (r + r)) / 2 = d + r := by omega + rw [hhalf] + have hNrank' : Module.finrank FABL.𝔽₂ N = d + r := by + simpa [htotalHalf] using hNrank + let N0 := normalExtensionProjectedIntersection N + by_contra hnot + change ¬ d ≤ Module.finrank FABL.𝔽₂ N0 at hnot + have hN0lt : Module.finrank FABL.𝔽₂ N0 < d := by omega + have hN0ambient : Module.finrank FABL.𝔽₂ N0 < + Module.finrank FABL.𝔽₂ (FABL.F₂Cube (d + d)) := by + simp [Module.finrank_fintype_fun_eq_card] + omega + obtain ⟨u0, hu0all⟩ := N0.exists_of_finrank_lt hN0ambient + have hu0 : u0 ∉ N0 := by simpa using hu0all 1 one_ne_zero + let T := N0 ⊔ Submodule.span FABL.𝔽₂ {u0} + have hTrank : Module.finrank FABL.𝔽₂ T = + Module.finrank FABL.𝔽₂ N0 + 1 := by + exact Submodule.finrank_sup_span_singleton hu0 + have hTle : Module.finrank FABL.𝔽₂ T ≤ (d + d) / 2 := by + rw [hTrank, hhalf] + omega + obtain ⟨gamma0, hgamma0, hgamma0T⟩ := + exists_bent_eq_zero_on_subspace T (by exact ⟨d, rfl⟩) hTle + obtain ⟨ell, hellu0Ne, hN0ker⟩ := N0.exists_le_ker_of_notMem hu0 + have hellu0 : ell u0 = 1 := Fin.eq_one_of_ne_zero _ hellu0Ne + have hellN0 (u : FABL.F₂Cube (d + d)) (hu : u ∈ N0) : + ell u = 0 := + LinearMap.mem_ker.mp (hN0ker hu) + have hellLinear : FABL.IsF₂Linear (fun u ↦ ell u) := by + intro x y + exact ell.map_add x y + obtain ⟨a, ha⟩ := + (FABL.isF₂Linear_iff_exists_dotProduct (fun u ↦ ell u)).1 + hellLinear + let gamma1 : BooleanFunction (d + d) := + gamma0 + FABL.affineFunction c 0 + let gamma2 : BooleanFunction (d + d) := + gamma0 + FABL.affineFunction c a + have hgamma1 : IsBent gamma1 := + (isBent_add_affineFunction_iff gamma0 c 0).2 hgamma0 + have hgamma2 : IsBent gamma2 := + (isBent_add_affineFunction_iff gamma0 c a).2 hgamma0 + have hN0T : N0 ≤ T := le_sup_left + have hu0T : u0 ∈ T := by + change u0 ∈ N0 ⊔ Submodule.span FABL.𝔽₂ {u0} + have hu0Span : u0 ∈ Submodule.span FABL.𝔽₂ {u0} := + Submodule.subset_span (by simp) + exact + (show Submodule.span FABL.𝔽₂ {u0} ≤ + N0 ⊔ Submodule.span FABL.𝔽₂ {u0} from le_sup_right) hu0Span + have hgamma1N0 (u : FABL.F₂Cube (d + d)) (hu : u ∈ N0) : + gamma1 u = c := by + simp [gamma1, hgamma0T u (hN0T hu), FABL.affineFunction, + FABL.f₂DotProduct, dotProduct] + have hgamma2N0 (u : FABL.F₂Cube (d + d)) (hu : u ∈ N0) : + gamma2 u = c := by + have hdot : FABL.f₂DotProduct a u = 0 := by + rw [← ha u, hellN0 u hu] + simp [gamma2, hgamma0T u (hN0T hu), FABL.affineFunction, hdot] + have hgamma1Shift (u : FABL.F₂Cube (d + d)) (hu : u ∈ N0) : + gamma1 (u0 + u) = c := by + have hsumT : u0 + u ∈ T := T.add_mem hu0T (hN0T hu) + simp [gamma1, hgamma0T (u0 + u) hsumT, FABL.affineFunction, + FABL.f₂DotProduct, dotProduct] + have hgamma2Shift (u : FABL.F₂Cube (d + d)) (hu : u ∈ N0) : + gamma2 (u0 + u) = c + 1 := by + have hsumT : u0 + u ∈ T := T.add_mem hu0T (hN0T hu) + have hellSum : ell (u0 + u) = 1 := by + rw [ell.map_add, hellu0, hellN0 u hu, add_zero] + have hdot : FABL.f₂DotProduct a (u0 + u) = 1 := by + rw [← ha (u0 + u), hellSum] + simp [gamma2, hgamma0T (u0 + u) hsumT, + FABL.affineFunction, hdot] + let F1 := canonicalNormalExtensionReplacement gamma1 f + let F2 := canonicalNormalExtensionReplacement gamma2 f + have hF1 : IsBent F1 := + isBent_canonicalNormalExtensionReplacement + beta gamma1 f hbeta hgamma1 hf hrestriction + have hF2 : IsBent F2 := + isBent_canonicalNormalExtensionReplacement + beta gamma2 f hbeta hgamma2 hf hrestriction + have replacementConstant + (gamma : BooleanFunction (d + d)) + (hgammaN0 : ∀ u ∈ N0, gamma u = c) : + ∀ x ∈ FABL.binaryAffineSubspace N 0, + canonicalNormalExtensionReplacement gamma f x = c := by + intro x hx + have hxN : x ∈ N := by + simpa [FABL.mem_binaryAffineSubspace_iff_add_mem] using hx + by_cases hxHead : x ∈ normalExtensionHeadSubspace (d + d) r + · rw [canonicalNormalExtensionReplacement_eq_on_head _ _ _ hxHead] + exact hgammaN0 _ + (normalExtensionProjectedIntersection_mem_of_mem hxN hxHead) + · rw [canonicalNormalExtensionReplacement_eq_off_head _ _ _ hxHead] + exact hconstant x hx + have hF1constant : ∀ x ∈ FABL.binaryAffineSubspace N 0, F1 x = c := + replacementConstant gamma1 hgamma1N0 + have hF2constant : ∀ x ∈ FABL.binaryAffineSubspace N 0, F2 x = c := + replacementConstant gamma2 hgamma2N0 + let G1 : BooleanFunction ((d + d) + (r + r)) := + F1 + FABL.affineFunction c 0 + let G2 : BooleanFunction ((d + d) + (r + r)) := + F2 + FABL.affineFunction c 0 + have hdpos : 0 < d := by omega + let eN : FABL.F₂Cube (d + r) ≃ₗ[FABL.𝔽₂] N := + LinearEquiv.ofFinrankEq _ _ (by + simp [hNrank', Module.finrank_fintype_fun_eq_card]) + let x0 : FABL.F₂Cube ((d + d) + (r + r)) := + Fin.append u0 (Fin.append 0 0) + have hx0Head : x0 ∈ normalExtensionHeadSubspace (d + d) r := by + rw [mem_normalExtensionHeadSubspace_iff_tail_eq_zero] + suffices (fun _i : Fin r ↦ (0 : FABL.𝔽₂)) = 0 by + simpa [x0, cubeTripleLinearEquiv, cubeSplitLinearEquiv] using this + funext i + rfl + have hx0NotN : x0 ∉ N := by + intro hx0N + apply hu0 + have hprojected := + normalExtensionProjectedIntersection_mem_of_mem hx0N hx0Head + simpa [x0] using hprojected + have hnonlinearity1 : nonlinearity F1 = + 2 ^ (((d + d) + (r + r)) - 1) - 2 ^ ((d + r) - 1) := by + have hvalue := nonlinearity_eq_two_pow_sub_two_pow_half_of_isBent + F1 hF1 (by omega) + simpa [htotalHalf] using hvalue + have hnonlinearity2 : nonlinearity F2 = + 2 ^ (((d + d) + (r + r)) - 1) - 2 ^ ((d + r) - 1) := by + have hvalue := nonlinearity_eq_two_pow_sub_two_pow_half_of_isBent + F2 hF2 (by omega) + simpa [htotalHalf] using hvalue + have hbalanced1 : IsBalanced + (coordinateAffineSubspaceRestriction + G1 N x0 eN) := by + change IsBalanced + (coordinateAffineSubspaceRestriction + (F1 + FABL.affineFunction c 0) N x0 eN) + apply isBalanced_coordinateAffineSubspaceRestriction_add_affineFunction_of_eq_bound + F1 N 0 eN (by omega) c 0 + · intro x hx + rw [hF1constant x hx] + simp [FABL.affineFunction, FABL.f₂DotProduct, dotProduct] + · exact hnonlinearity1 + · simpa only [add_zero] using hx0NotN + have hbalanced2 : IsBalanced + (coordinateAffineSubspaceRestriction + G2 N x0 eN) := by + change IsBalanced + (coordinateAffineSubspaceRestriction + (F2 + FABL.affineFunction c 0) N x0 eN) + apply isBalanced_coordinateAffineSubspaceRestriction_add_affineFunction_of_eq_bound + F2 N 0 eN (by omega) c 0 + · intro x hx + rw [hF2constant x hx] + simp [FABL.affineFunction, FABL.f₂DotProduct, dotProduct] + · exact hnonlinearity2 + · simpa only [add_zero] using hx0NotN + have hsum1 : + (∑ y : FABL.F₂Cube (d + r), + bitSignInt (G1 ((eN y).1 + x0))) = 0 := by + have hwalsh := + (isBalanced_iff_walshTransform_zero_eq_zero _).1 hbalanced1 + rw [walshTransform] at hwalsh + simpa [walshTerm, coordinateAffineSubspaceRestriction_apply, + FABL.f₂DotProduct, dotProduct, G1] using hwalsh + have hsum2 : + (∑ y : FABL.F₂Cube (d + r), + bitSignInt (G2 ((eN y).1 + x0))) = 0 := by + have hwalsh := + (isBalanced_iff_walshTransform_zero_eq_zero _).1 hbalanced2 + rw [walshTransform] at hwalsh + simpa [walshTerm, coordinateAffineSubspaceRestriction_apply, + FABL.f₂DotProduct, dotProduct, G2] using hwalsh + let S : Finset (FABL.F₂Cube (d + r)) := Finset.univ.filter fun y ↦ + (eN y).1 + x0 ∈ normalExtensionHeadSubspace (d + d) r + have hzeroS : (0 : FABL.F₂Cube (d + r)) ∈ S := by + simp [S, hx0Head] + have hterm (y : FABL.F₂Cube (d + r)) : + bitSignInt (G1 ((eN y).1 + x0)) - + bitSignInt (G2 ((eN y).1 + x0)) = + if (eN y).1 + x0 ∈ normalExtensionHeadSubspace (d + d) r + then 2 else 0 := by + let x := (eN y).1 + x0 + by_cases hxHead : x ∈ normalExtensionHeadSubspace (d + d) r + · rw [if_pos hxHead] + have heNHead : (eN y).1 ∈ + normalExtensionHeadSubspace (d + d) r := by + have hadd := + (normalExtensionHeadSubspace (d + d) r).add_mem hxHead hx0Head + simpa [x, add_assoc, ZModModule.add_self] using hadd + have hvN0 : normalExtensionPrefixLinearMap (d + d) r (eN y).1 ∈ + N0 := normalExtensionProjectedIntersection_mem_of_mem + (eN y).2 heNHead + have hprefix : normalExtensionPrefixLinearMap (d + d) r x = + u0 + normalExtensionPrefixLinearMap (d + d) r (eN y).1 := by + dsimp [x] + rw [map_add, normalExtensionPrefixLinearMap_apply] + abel + have hF1x : F1 x = c := by + change canonicalNormalExtensionReplacement gamma1 f x = c + rw [canonicalNormalExtensionReplacement_eq_on_head _ _ _ hxHead, + hprefix, hgamma1Shift _ hvN0] + have hF2x : F2 x = c + 1 := by + change canonicalNormalExtensionReplacement gamma2 f x = c + 1 + rw [canonicalNormalExtensionReplacement_eq_on_head _ _ _ hxHead, + hprefix, hgamma2Shift _ hvN0] + have hG1x : G1 x = 0 := by + change F1 x + FABL.affineFunction c 0 x = 0 + rw [hF1x] + simpa [FABL.affineFunction, FABL.f₂DotProduct, dotProduct] using + ZModModule.add_self c + have hG2x : G2 x = 1 := by + change F2 x + FABL.affineFunction c 0 x = 1 + have haffineZero : FABL.affineFunction c 0 x = c := by + simp [FABL.affineFunction, FABL.f₂DotProduct, dotProduct] + rw [hF2x, haffineZero] + calc + (c + 1) + c = (c + c) + 1 := by abel + _ = 1 := by rw [ZModModule.add_self, zero_add] + change bitSignInt (G1 x) - bitSignInt (G2 x) = 2 + rw [hG1x, hG2x] + norm_num [bitSignInt_eq_if_one] + · rw [if_neg hxHead] + have hF1x : F1 x = f x := by + change canonicalNormalExtensionReplacement gamma1 f x = f x + exact canonicalNormalExtensionReplacement_eq_off_head + gamma1 f x hxHead + have hF2x : F2 x = f x := by + change canonicalNormalExtensionReplacement gamma2 f x = f x + exact canonicalNormalExtensionReplacement_eq_off_head + gamma2 f x hxHead + have hG : G1 x = G2 x := by + simp [G1, G2, hF1x, hF2x] + change bitSignInt (G1 x) - bitSignInt (G2 x) = 0 + rw [hG, sub_self] + have hsumDifference : + (∑ y : FABL.F₂Cube (d + r), + (bitSignInt (G1 ((eN y).1 + x0)) - + bitSignInt (G2 ((eN y).1 + x0)))) = 0 := by + rw [Finset.sum_sub_distrib, hsum1, hsum2, sub_self] + have hsumCard : + (∑ y : FABL.F₂Cube (d + r), + (bitSignInt (G1 ((eN y).1 + x0)) - + bitSignInt (G2 ((eN y).1 + x0)))) = + (S.card : ℤ) * 2 := by + calc + _ = ∑ y : FABL.F₂Cube (d + r), + if (eN y).1 + x0 ∈ normalExtensionHeadSubspace (d + d) r + then 2 else 0 := by + apply Finset.sum_congr rfl + intro y _hy + exact hterm y + _ = (S.card : ℤ) * 2 := by + rw [← Finset.sum_filter] + change (∑ _y ∈ S, (2 : ℤ)) = (S.card : ℤ) * 2 + simp + have hScard : 0 < S.card := Finset.card_pos.mpr ⟨0, hzeroS⟩ + have hzeroCard : (S.card : ℤ) * 2 = 0 := by + rw [← hsumCard] + exact hsumDifference + have hcastZero : (S.card : ℤ) = 0 := + (mul_eq_zero.mp hzeroCard).resolve_right (by norm_num) + have hNatZero : S.card = 0 := by + exact_mod_cast hcastZero + omega + +private theorem isSubspaceNormal_of_canonicalNormalExtension + (beta : BooleanFunction k) + (f : BooleanFunction (k + (r + r))) + (hbeta : IsBent beta) (hf : IsBent f) + (hrestriction : ∀ u w, + f (Fin.append u (Fin.append w 0)) = beta u) + (hnormal : IsSubspaceNormal f) : + IsSubspaceNormal beta := by + obtain ⟨N, hNrank, c, hconstant⟩ := hnormal + let N0 := normalExtensionProjectedIntersection N + have hN0rank : k / 2 ≤ Module.finrank FABL.𝔽₂ N0 := + half_le_finrank_projectedIntersection beta f hbeta hf hrestriction + N hNrank c hconstant + obtain ⟨H, hHN0, hHrank⟩ := + exists_subspace_le_finrank_eq N0 hN0rank + refine ⟨H, hHrank, c, ?_⟩ + intro u hu + have huH : u ∈ H := by + simpa [FABL.mem_binaryAffineSubspace_iff_add_mem] using hu + exact isConstantOn_projectedIntersection beta f N c + hrestriction hconstant u (hHN0 huH) + +/-- Carlet Proposition 30: linear-subspace normality descends along a +normal extension. -/ +theorem IsNormalExtension.isSubspaceNormal_left + {beta : BooleanFunction k} {f : BooleanFunction n} + (hextension : IsNormalExtension beta f) + (hnormal : IsSubspaceNormal f) : + IsSubspaceNormal beta := by + obtain ⟨hbeta, hf, r, L, hrestriction⟩ := hextension + have hdim : k + (r + r) = n := by + have hfinrank := LinearEquiv.finrank_eq L + simpa [Module.finrank_fintype_fun_eq_card] using hfinrank + subst n + let g : BooleanFunction (k + (r + r)) := f ∘ L + have hg : IsBent g := + (isBent_comp_affineEquiv_iff f L.toAffineEquiv).2 hf + have hgnormal : IsSubspaceNormal g := + (isSubspaceNormal_comp_linearEquiv_iff f L).2 hnormal + exact isSubspaceNormal_of_canonicalNormalExtension + beta g hbeta hg hrestriction hgnormal + +/-- Linear equivalence up to addition of a constant Boolean function. -/ +def AreLinearlyEquivalentOrComplementary + (f : BooleanFunction n) (g : BooleanFunction m) : Prop := + ∃ L : FABL.F₂Cube n ≃ₗ[FABL.𝔽₂] FABL.F₂Cube m, + ∃ c : FABL.𝔽₂, ∀ x, f x = g (L x) + c + +private def prop29CubeThreeLinearEquiv (a b c : ℕ) : + FABL.F₂Cube (a + (b + c)) ≃ₗ[FABL.𝔽₂] + (FABL.F₂Cube a × (FABL.F₂Cube b × FABL.F₂Cube c)) := + (cubeSplitLinearEquiv a (b + c)).trans + ((LinearEquiv.refl FABL.𝔽₂ (FABL.F₂Cube a)).prodCongr + (cubeSplitLinearEquiv b c)) + +@[simp] private theorem finAppend_add + (u₁ u₂ : FABL.F₂Cube a) (v₁ v₂ : FABL.F₂Cube b) : + Fin.append (u₁ + u₂) (v₁ + v₂) = + Fin.append u₁ v₁ + Fin.append u₂ v₂ := by + funext i + refine Fin.addCases (fun j ↦ ?_) (fun j ↦ ?_) i <;> simp + +@[simp] private theorem finAppend_smul + (c : FABL.𝔽₂) (u : FABL.F₂Cube a) (v : FABL.F₂Cube b) : + Fin.append (c • u) (c • v) = c • Fin.append u v := by + funext i + refine Fin.addCases (fun j ↦ ?_) (fun j ↦ ?_) i <;> simp + +@[simp] private theorem finAppend_add_zero + (u₁ u₂ : FABL.F₂Cube a) : + Fin.append (u₁ + u₂) (0 : FABL.F₂Cube b) = + Fin.append u₁ 0 + Fin.append u₂ 0 := by + rw [← finAppend_add] + simp + +@[simp] private theorem finAppend_smul_zero + (c : FABL.𝔽₂) (u : FABL.F₂Cube a) : + Fin.append (c • u) (0 : FABL.F₂Cube b) = + c • Fin.append u 0 := by + rw [← finAppend_smul] + simp + +@[simp] private theorem cubeSplitLinearEquiv_symm_apply_prop29 + (u : FABL.F₂Cube a) (v : FABL.F₂Cube b) : + (cubeSplitLinearEquiv a b).symm (u, v) = Fin.append u v := by + apply (cubeSplitLinearEquiv a b).injective + simp [cubeSplitLinearEquiv] + +@[simp] private theorem cubeTripleLinearEquiv_symm_apply + (u : FABL.F₂Cube a) (v w : FABL.F₂Cube b) : + (cubeTripleLinearEquiv a b).symm (u, (v, w)) = + Fin.append u (Fin.append v w) := by + apply (cubeTripleLinearEquiv a b).injective + simp [cubeTripleLinearEquiv, cubeSplitLinearEquiv] + +@[simp] private theorem cubeTripleLinearEquiv_apply_append + (u : FABL.F₂Cube a) (v w : FABL.F₂Cube b) : + cubeTripleLinearEquiv a b (Fin.append u (Fin.append v w)) = + (u, (v, w)) := by + simp [cubeTripleLinearEquiv, cubeSplitLinearEquiv] + +@[simp] private theorem prop29CubeThreeLinearEquiv_apply_append + (u : FABL.F₂Cube a) (v : FABL.F₂Cube b) + (w : FABL.F₂Cube c) : + prop29CubeThreeLinearEquiv a b c (Fin.append u (Fin.append v w)) = + (u, (v, w)) := by + simp [prop29CubeThreeLinearEquiv, cubeSplitLinearEquiv] + +private def compatibleNormalExtensionsLinearMap + {k₁ k₂ n m r₁ r₂ : ℕ} + (L₁ : FABL.F₂Cube (k₁ + (r₁ + r₁)) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube n) + (L₂ : FABL.F₂Cube (k₂ + (r₂ + r₂)) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube m) + (E : FABL.F₂Cube k₁ ≃ₗ[FABL.𝔽₂] FABL.F₂Cube k₂) : + FABL.F₂Cube (k₁ + (r₁ + r₂)) →ₗ[FABL.𝔽₂] + FABL.F₂Cube (n + m) where + toFun x := + let q := prop29CubeThreeLinearEquiv k₁ r₁ r₂ x + (cubeSplitLinearEquiv n m).symm + ( + (L₁ ((cubeTripleLinearEquiv k₁ r₁).symm + (q.1, (q.2.1, 0)))) + , L₂ ((cubeTripleLinearEquiv k₂ r₂).symm + (E q.1, (q.2.2, 0)))) + map_add' x y := by + simp [map_add] + map_smul' c x := by + simp [map_smul] + +@[simp] private theorem compatibleNormalExtensionsLinearMap_apply + {k₁ k₂ n m r₁ r₂ : ℕ} + (L₁ : FABL.F₂Cube (k₁ + (r₁ + r₁)) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube n) + (L₂ : FABL.F₂Cube (k₂ + (r₂ + r₂)) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube m) + (E : FABL.F₂Cube k₁ ≃ₗ[FABL.𝔽₂] FABL.F₂Cube k₂) + (u : FABL.F₂Cube k₁) (w₁ : FABL.F₂Cube r₁) + (w₂ : FABL.F₂Cube r₂) : + compatibleNormalExtensionsLinearMap L₁ L₂ E + (Fin.append u (Fin.append w₁ w₂)) = + Fin.append + (L₁ (Fin.append u (Fin.append w₁ 0))) + (L₂ (Fin.append (E u) (Fin.append w₂ 0))) := by + simp [compatibleNormalExtensionsLinearMap] + +private theorem booleanDirectSum_apply_append + (f : BooleanFunction n) (g : BooleanFunction m) + (x : FABL.F₂Cube n) (y : FABL.F₂Cube m) : + booleanDirectSum f g (Fin.append x y) = f x + g y := by + simp [booleanDirectSum] + +private theorem compatibleNormalExtensionsLinearMap_injective + {k₁ k₂ n m r₁ r₂ : ℕ} + (L₁ : FABL.F₂Cube (k₁ + (r₁ + r₁)) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube n) + (L₂ : FABL.F₂Cube (k₂ + (r₂ + r₂)) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube m) + (E : FABL.F₂Cube k₁ ≃ₗ[FABL.𝔽₂] FABL.F₂Cube k₂) : + Function.Injective (compatibleNormalExtensionsLinearMap L₁ L₂ E) := by + intro x y hxy + let qx := prop29CubeThreeLinearEquiv k₁ r₁ r₂ x + let qy := prop29CubeThreeLinearEquiv k₁ r₁ r₂ y + have hpairs : + (L₁ ((cubeTripleLinearEquiv k₁ r₁).symm + (qx.1, (qx.2.1, 0))), + L₂ ((cubeTripleLinearEquiv k₂ r₂).symm + (E qx.1, (qx.2.2, 0)))) = + (L₁ ((cubeTripleLinearEquiv k₁ r₁).symm + (qy.1, (qy.2.1, 0))), + L₂ ((cubeTripleLinearEquiv k₂ r₂).symm + (E qy.1, (qy.2.2, 0)))) := by + apply (cubeSplitLinearEquiv n m).symm.injective + simpa [compatibleNormalExtensionsLinearMap, qx, qy] using hxy + have hleft := L₁.injective (congrArg Prod.fst hpairs) + have hleftCoordinates := congrArg + (cubeTripleLinearEquiv k₁ r₁) hleft + have hu : qx.1 = qy.1 := by + simpa using congrArg (fun z ↦ z.1) hleftCoordinates + have hw₁ : qx.2.1 = qy.2.1 := by + simpa using congrArg (fun z ↦ z.2.1) hleftCoordinates + have hright := L₂.injective (congrArg Prod.snd hpairs) + have hrightCoordinates := congrArg + (cubeTripleLinearEquiv k₂ r₂) hright + have hw₂ : qx.2.2 = qy.2.2 := by + simpa using congrArg (fun z ↦ z.2.1) hrightCoordinates + apply (prop29CubeThreeLinearEquiv k₁ r₁ r₂).injective + apply Prod.ext hu + exact Prod.ext hw₁ hw₂ + +private theorem isSubspaceNormal_booleanDirectSum_of_compatibleNormalExtensions + {k₁ k₂ n m : ℕ} + {beta₁ : BooleanFunction k₁} {beta₂ : BooleanFunction k₂} + {f₁ : BooleanFunction n} {f₂ : BooleanFunction m} + (hext₁ : IsNormalExtension beta₁ f₁) + (hext₂ : IsNormalExtension beta₂ f₂) + (hcompatible : AreLinearlyEquivalentOrComplementary beta₁ beta₂) : + IsSubspaceNormal (booleanDirectSum f₁ f₂) := by + classical + obtain ⟨hbeta₁, _hf₁, r₁, L₁, hL₁⟩ := hext₁ + obtain ⟨_hbeta₂, _hf₂, r₂, L₂, hL₂⟩ := hext₂ + obtain ⟨E, c, hrelation⟩ := hcompatible + let T := compatibleNormalExtensionsLinearMap L₁ L₂ E + let H : Submodule FABL.𝔽₂ (FABL.F₂Cube (n + m)) := LinearMap.range T + have hTinjective : Function.Injective T := + compatibleNormalExtensionsLinearMap_injective L₁ L₂ E + have hHdimension : Module.finrank FABL.𝔽₂ H = k₁ + (r₁ + r₂) := by + have hfinrank := LinearEquiv.finrank_eq + (LinearEquiv.ofInjective T hTinjective) + simpa [H, Module.finrank_fintype_fun_eq_card] using hfinrank.symm + have hL₁dimension : k₁ + (r₁ + r₁) = n := by + have hfinrank := LinearEquiv.finrank_eq L₁ + simpa [Module.finrank_fintype_fun_eq_card] using hfinrank + have hL₂dimension : k₂ + (r₂ + r₂) = m := by + have hfinrank := LinearEquiv.finrank_eq L₂ + simpa [Module.finrank_fintype_fun_eq_card] using hfinrank + have hEdimension : k₁ = k₂ := by + have hfinrank := LinearEquiv.finrank_eq E + simpa [Module.finrank_fintype_fun_eq_card] using hfinrank + have hHrank : Module.finrank FABL.𝔽₂ H = (n + m) / 2 := by + rcases even_of_isBent beta₁ hbeta₁ with ⟨d, hd⟩ + omega + refine ⟨H, hHrank, c, ?_⟩ + intro x hx + have hxH : x ∈ H := by + simpa [FABL.mem_binaryAffineSubspace_iff_add_mem] using hx + obtain ⟨y, rfl⟩ := hxH + let q := prop29CubeThreeLinearEquiv k₁ r₁ r₂ y + have hy : Fin.append q.1 (Fin.append q.2.1 q.2.2) = y := by + change (prop29CubeThreeLinearEquiv k₁ r₁ r₂).symm q = y + exact (prop29CubeThreeLinearEquiv k₁ r₁ r₂).symm_apply_apply y + rw [← hy, compatibleNormalExtensionsLinearMap_apply] + rw [booleanDirectSum_apply_append, hL₁, hL₂, hrelation] + calc + (beta₂ (E q.1) + c) + beta₂ (E q.1) = + (beta₂ (E q.1) + beta₂ (E q.1)) + c := by abel + _ = c := by rw [ZModModule.add_self, zero_add] + +private theorem isBent_of_maxWalshMagnitude_sq_le_two_pow + (f : BooleanFunction k) + (hmax : (maxWalshMagnitude f : ℝ) ^ 2 ≤ (2 : ℝ) ^ k) : + IsBent f := by + have hlower : (2 : ℝ) ^ k ≤ (maxWalshMagnitude f : ℝ) ^ 2 := by + have hsum : + (∑ a : FABL.F₂Cube k, (walshTransform f a : ℝ) ^ 2) ≤ + ∑ _a : FABL.F₂Cube k, + (maxWalshMagnitude f : ℝ) ^ 2 := by + apply Finset.sum_le_sum + intro a _ha + have habs := abs_walshTransform_le_maxWalshMagnitude f a + simpa only [sq_abs] using + (sq_le_sq₀ (abs_nonneg (walshTransform f a : ℝ)) + (Nat.cast_nonneg (maxWalshMagnitude f))).2 habs + rw [sum_walshTransform_sq_eq_two_pow_sq, Finset.sum_const, + Finset.card_univ, card_f₂Cube, nsmul_eq_mul] at hsum + norm_num only [Nat.cast_pow, Nat.cast_ofNat] at hsum + have hpow : (0 : ℝ) < (2 : ℝ) ^ k := by positivity + nlinarith + have hmaxEq : (maxWalshMagnitude f : ℝ) ^ 2 = (2 : ℝ) ^ k := + le_antisymm hmax hlower + apply (hasFlatWalshSpectrum_iff_isBent f).1 + intro a + have hcoeff : (walshTransform f a : ℝ) ^ 2 ≤ + (maxWalshMagnitude f : ℝ) ^ 2 := by + have habs := abs_walshTransform_le_maxWalshMagnitude f a + simpa only [sq_abs] using + (sq_le_sq₀ (abs_nonneg (walshTransform f a : ℝ)) + (Nat.cast_nonneg (maxWalshMagnitude f))).2 habs + have hcoeffEq : (walshTransform f a : ℝ) ^ 2 = + (maxWalshMagnitude f : ℝ) ^ 2 := by + apply le_antisymm hcoeff + by_contra hnot + have hstrict : (walshTransform f a : ℝ) ^ 2 < + (maxWalshMagnitude f : ℝ) ^ 2 := lt_of_not_ge hnot + have hsumStrict : + (∑ b : FABL.F₂Cube k, (walshTransform f b : ℝ) ^ 2) < + ∑ _b : FABL.F₂Cube k, + (maxWalshMagnitude f : ℝ) ^ 2 := by + apply Finset.sum_lt_sum + · intro b _hb + have hb := abs_walshTransform_le_maxWalshMagnitude f b + simpa only [sq_abs] using + (sq_le_sq₀ (abs_nonneg (walshTransform f b : ℝ)) + (Nat.cast_nonneg (maxWalshMagnitude f))).2 hb + · exact ⟨a, Finset.mem_univ a, hstrict⟩ + rw [sum_walshTransform_sq_eq_two_pow_sq, Finset.sum_const, + Finset.card_univ, card_f₂Cube, nsmul_eq_mul, hmaxEq] at hsumStrict + norm_num only [Nat.cast_pow, Nat.cast_ofNat] at hsumStrict + have hpow : (2 : ℝ) ^ k * (2 : ℝ) ^ k = + ((2 : ℝ) ^ k) ^ 2 := by ring + rw [hpow] at hsumStrict + exact (lt_irrefl _ hsumStrict).elim + have hsquare : (walshTransform f a : ℝ) ^ 2 = (2 : ℝ) ^ k := + hcoeffEq.trans hmaxEq + have hsqrt := Real.sq_sqrt (show 0 ≤ (2 : ℝ) ^ k by positivity) + have habsSquare : |(walshTransform f a : ℝ)| ^ 2 = (2 : ℝ) ^ k := by + rw [sq_abs] + exact hsquare + nlinarith [abs_nonneg (walshTransform f a : ℝ), + Real.sqrt_nonneg ((2 : ℝ) ^ k)] + +private theorem natAbs_mul_two_pow_le_of_abs_intCast_le + (z : ℤ) (r s : ℕ) + (h : |((z * (2 : ℤ) ^ r : ℤ) : ℝ)| ≤ + ((2 ^ s : ℕ) : ℝ)) : + 2 ^ r * z.natAbs ≤ 2 ^ s := by + have hcast : (((z * (2 : ℤ) ^ r).natAbs : ℕ) : ℝ) ≤ + ((2 ^ s : ℕ) : ℝ) := by + simpa only [Nat.cast_natAbs, Int.cast_abs] using h + have hnat : (z * (2 : ℤ) ^ r).natAbs ≤ 2 ^ s := by + exact_mod_cast hcast + norm_num only [Int.natAbs_mul, Int.natAbs_pow, Int.natAbs_of_nonneg, + OfNat.ofNat, Nat.zero_le, mul_comm] at hnat ⊢ + exact hnat + +private theorem natAbs_walshTransform_eq_of_eq_add_constant + {f g : BooleanFunction k} (c : FABL.𝔽₂) + (hfg : ∀ x, f x = g x + c) (a : FABL.F₂Cube k) : + (walshTransform f a).natAbs = (walshTransform g a).natAbs := by + have hwalsh : walshTransform f a = bitSignInt c * walshTransform g a := by + rw [walshTransform, walshTransform] + calc + (∑ x : FABL.F₂Cube k, walshTerm f a x) = + ∑ x : FABL.F₂Cube k, bitSignInt c * walshTerm g a x := by + apply Finset.sum_congr rfl + intro x _hx + rw [walshTerm, walshTerm, hfg x, ← bitSignInt_add] + congr 1 + abel + _ = bitSignInt c * ∑ x : FABL.F₂Cube k, walshTerm g a x := by + rw [Finset.mul_sum] + rw [hwalsh, Int.natAbs_mul] + have hsign : (bitSignInt c).natAbs = 1 := by + rw [bitSignInt_eq_if_one] + split <;> simp + rw [hsign, one_mul] + +private theorem exists_natAbs_walshTransform_eq_maxWalshMagnitude + (f : BooleanFunction k) : + ∃ a, (walshTransform f a).natAbs = maxWalshMagnitude f := by + unfold maxWalshMagnitude + obtain ⟨a, _ha, hmax⟩ := Finset.exists_mem_eq_sup' + (s := (Finset.univ : Finset (FABL.F₂Cube k))) Finset.univ_nonempty + (fun u ↦ (walshTransform f u).natAbs) + exact ⟨a, hmax.symm⟩ + +private theorem exists_compatibleNormalExtensions_of_isSubspaceNormal_booleanDirectSum + {f₁ : BooleanFunction n} {f₂ : BooleanFunction m} + (hf₁ : IsBent f₁) (hf₂ : IsBent f₂) + (hnormal : IsSubspaceNormal (booleanDirectSum f₁ f₂)) : + ∃ k₁ k₂, ∃ beta₁ : BooleanFunction k₁, + ∃ beta₂ : BooleanFunction k₂, + IsNormalExtension beta₁ f₁ ∧ + IsNormalExtension beta₂ f₂ ∧ + AreLinearlyEquivalentOrComplementary beta₁ beta₂ := by + classical + obtain ⟨N, hNrank, c, hconstant⟩ := hnormal + let S := cubeSplitLinearEquiv n m + let R : Submodule FABL.𝔽₂ + (FABL.F₂Cube n × FABL.F₂Cube m) := N.map S.toLinearMap + have hconstantR (z : FABL.F₂Cube n × FABL.F₂Cube m) (hz : z ∈ R) : + f₁ z.1 + f₂ z.2 = c := by + obtain ⟨x, hxN, hxz⟩ := hz + have hxFlat : x ∈ FABL.binaryAffineSubspace N 0 := by + simpa [FABL.mem_binaryAffineSubspace_iff_add_mem] using hxN + have hxValue := hconstant x hxFlat + rw [← hxz] + simpa [booleanDirectSum, S, cubeSplitLinearEquiv] using hxValue + let M₁ := R.map (LinearMap.fst FABL.𝔽₂ (FABL.F₂Cube n) (FABL.F₂Cube m)) + let M₂ := R.map (LinearMap.snd FABL.𝔽₂ (FABL.F₂Cube n) (FABL.F₂Cube m)) + let P : R →ₗ[FABL.𝔽₂] M₁ := + (LinearMap.fst FABL.𝔽₂ (FABL.F₂Cube n) (FABL.F₂Cube m)).submoduleMap R + let Q : R →ₗ[FABL.𝔽₂] M₂ := + (LinearMap.snd FABL.𝔽₂ (FABL.F₂Cube n) (FABL.F₂Cube m)).submoduleMap R + let R' : Submodule FABL.𝔽₂ (M₁ × M₂) := LinearMap.range (P.prod Q) + have hconstantR' (z : M₁ × M₂) (hz : z ∈ R') : + f₁ z.1.1 + f₂ z.2.1 = c := by + obtain ⟨q, hq⟩ := hz + rw [← hq] + exact hconstantR q.1 q.2 + have hR₁ : Function.Surjective (Prod.fst ∘ R'.subtype) := by + intro x + obtain ⟨z, hzR, hzx⟩ := x.2 + let zR : R := ⟨z, hzR⟩ + have hP : P zR = x := by + apply Subtype.ext + exact hzx + let y : M₂ := Q zR + let q : R' := ⟨(P zR, y), ⟨zR, rfl⟩⟩ + exact ⟨q, by simp [q, hP]⟩ + have hR₂ : Function.Surjective (Prod.snd ∘ R'.subtype) := by + intro y + obtain ⟨z, hzR, hzy⟩ := y.2 + let zR : R := ⟨z, hzR⟩ + have hQ : Q zR = y := by + apply Subtype.ext + exact hzy + let x : M₁ := P zR + let q : R' := ⟨(x, Q zR), ⟨zR, rfl⟩⟩ + exact ⟨q, by simp [q, hQ]⟩ + let W₁ := R'.goursatFst + let W₂ := R'.goursatSnd + obtain ⟨e, he⟩ := Submodule.goursat_surjective hR₁ hR₂ + have hinvariant₁ (x : M₁) (w : W₁) : + f₁ (x + w.1).1 = f₁ x.1 := by + obtain ⟨q, hqx⟩ := hR₁ x + change q.1.1 = x at hqx + have hwPair : (w.1, (0 : M₂)) ∈ R' := by + apply R'.goursatFst_prod_goursatSnd_le + exact ⟨w.2, W₂.zero_mem⟩ + have hbase := hconstantR' q.1 q.2 + have hshift := hconstantR' (q.1 + (w.1, 0)) + (R'.add_mem q.2 hwPair) + apply add_right_cancel (b := f₂ q.1.2.1) + simpa [hqx] using hshift.trans hbase.symm + have hinvariant₂ (y : M₂) (w : W₂) : + f₂ (y + w.1).1 = f₂ y.1 := by + obtain ⟨q, hqy⟩ := hR₂ y + change q.1.2 = y at hqy + have hwPair : ((0 : M₁), w.1) ∈ R' := by + apply R'.goursatFst_prod_goursatSnd_le + exact ⟨W₁.zero_mem, w.2⟩ + have hbase := hconstantR' q.1 q.2 + have hshift := hconstantR' (q.1 + (0, w.1)) + (R'.add_mem q.2 hwPair) + apply add_left_cancel (a := f₁ q.1.1.1) + simpa [hqy] using hshift.trans hbase.symm + obtain ⟨U₁, hW₁U₁⟩ := W₁.exists_isCompl + obtain ⟨U₂, hW₂U₂⟩ := W₂.exists_isCompl + let k₀ := Module.finrank FABL.𝔽₂ (M₁ ⧸ W₁) + let r₁₀ := Module.finrank FABL.𝔽₂ W₁ + let r₂₀ := Module.finrank FABL.𝔽₂ W₂ + have hU₁rank : Module.finrank FABL.𝔽₂ U₁ = k₀ := by + have hfinrank := LinearEquiv.finrank_eq + (W₁.quotientEquivOfIsCompl U₁ hW₁U₁) + simpa [k₀] using hfinrank.symm + have hU₂rank : Module.finrank FABL.𝔽₂ U₂ = k₀ := by + have heRank := LinearEquiv.finrank_eq e + have hquotient₂ : Module.finrank FABL.𝔽₂ (M₂ ⧸ W₂) = k₀ := by + simpa [k₀] using heRank.symm + have hfinrank := LinearEquiv.finrank_eq + (W₂.quotientEquivOfIsCompl U₂ hW₂U₂) + exact hfinrank.symm.trans hquotient₂ + have hM₁rank : Module.finrank FABL.𝔽₂ M₁ = k₀ + r₁₀ := by + have hquotient := W₁.finrank_quotient_add_finrank + simpa [k₀, r₁₀] using hquotient.symm + have hM₂rank : Module.finrank FABL.𝔽₂ M₂ = k₀ + r₂₀ := by + have heRank := LinearEquiv.finrank_eq e + have hquotient₂ : Module.finrank FABL.𝔽₂ (M₂ ⧸ W₂) = k₀ := by + simpa [k₀] using heRank.symm + have hquotient := W₂.finrank_quotient_add_finrank + omega + have hPQinjective : Function.Injective (P.prod Q) := by + intro x y hxy + apply Subtype.ext + apply Prod.ext + · exact congrArg (fun z ↦ z.1.1) hxy + · exact congrArg (fun z ↦ z.2.1) hxy + have hRrank : Module.finrank FABL.𝔽₂ R = (n + m) / 2 := by + have hmap := LinearEquiv.finrank_map_eq S N + simpa [R, hNrank] using hmap + have hR'rank : Module.finrank FABL.𝔽₂ R' = (n + m) / 2 := by + have hfinrank := LinearEquiv.finrank_eq + (LinearEquiv.ofInjective (P.prod Q) hPQinjective) + simpa [R', hRrank] using hfinrank.symm + let p₁ : R' →ₗ[FABL.𝔽₂] M₁ := + (LinearMap.fst FABL.𝔽₂ M₁ M₂).comp R'.subtype + let K₂ := LinearMap.ker p₁ + let s₂ : K₂ →ₗ[FABL.𝔽₂] M₂ := + ((LinearMap.snd FABL.𝔽₂ M₁ M₂).comp R'.subtype).domRestrict K₂ + have hs₂injective : Function.Injective s₂ := by + intro x y hxy + apply Subtype.ext + apply Subtype.ext + apply Prod.ext + · have hx := x.2 + have hy := y.2 + change x.1.1.1 = 0 at hx + change y.1.1.1 = 0 at hy + rw [hx, hy] + · exact hxy + have hs₂range : LinearMap.range s₂ = W₂ := by + change LinearMap.range + (((LinearMap.snd FABL.𝔽₂ M₁ M₂).comp R'.subtype).domRestrict + (LinearMap.ker + ((LinearMap.fst FABL.𝔽₂ M₁ M₂).comp R'.subtype))) = + R'.goursatSnd + rw [LinearMap.range_domRestrict] + rfl + have hK₂rank : Module.finrank FABL.𝔽₂ K₂ = r₂₀ := by + have hfinrank := LinearEquiv.finrank_eq + (LinearEquiv.ofInjective s₂ hs₂injective) + rw [hs₂range] at hfinrank + simpa [r₂₀] using hfinrank + have hR'dimension : (n + m) / 2 = k₀ + r₁₀ + r₂₀ := by + have hp₁Range : LinearMap.range p₁ = ⊤ := + LinearMap.range_eq_top.2 hR₁ + have hrankNullity := p₁.finrank_range_add_finrank_ker + rw [hp₁Range] at hrankNullity + simpa [K₂, hM₁rank, hK₂rank, hR'rank] using hrankNullity.symm + let phi : U₁ ≃ₗ[FABL.𝔽₂] U₂ := + (W₁.quotientEquivOfIsCompl U₁ hW₁U₁).symm |>.trans + (e.trans (W₂.quotientEquivOfIsCompl U₂ hW₂U₂)) + let eU₁ : FABL.F₂Cube k₀ ≃ₗ[FABL.𝔽₂] U₁ := + LinearEquiv.ofFinrankEq _ _ (by + simp [hU₁rank, Module.finrank_fintype_fun_eq_card]) + let eU₂ : FABL.F₂Cube k₀ ≃ₗ[FABL.𝔽₂] U₂ := eU₁.trans phi + let eW₁ : FABL.F₂Cube r₁₀ ≃ₗ[FABL.𝔽₂] W₁ := + LinearEquiv.ofFinrankEq _ _ (by + simp [r₁₀, Module.finrank_fintype_fun_eq_card]) + let eW₂ : FABL.F₂Cube r₂₀ ≃ₗ[FABL.𝔽₂] W₂ := + LinearEquiv.ofFinrankEq _ _ (by + simp [r₂₀, Module.finrank_fintype_fun_eq_card]) + let eM₁ : FABL.F₂Cube (k₀ + r₁₀) ≃ₗ[FABL.𝔽₂] M₁ := + (cubeSplitLinearEquiv k₀ r₁₀).trans + ((eU₁.prodCongr eW₁).trans + (U₁.prodEquivOfIsCompl W₁ hW₁U₁.symm)) + let eM₂ : FABL.F₂Cube (k₀ + r₂₀) ≃ₗ[FABL.𝔽₂] M₂ := + (cubeSplitLinearEquiv k₀ r₂₀).trans + ((eU₂.prodCongr eW₂).trans + (U₂.prodEquivOfIsCompl W₂ hW₂U₂.symm)) + let beta₁ : BooleanFunction k₀ := fun u ↦ + f₁ (eU₁ u).1.1 + let beta₂ : BooleanFunction k₀ := fun u ↦ + f₂ (eU₂ u).1.1 + have hrestriction₁ (u : FABL.F₂Cube k₀) (w : FABL.F₂Cube r₁₀) : + f₁ (eM₁ (Fin.append u w)).1 = beta₁ u := by + have h := hinvariant₁ (eU₁ u).1 (eW₁ w) + simpa [eM₁, beta₁, cubeSplitLinearEquiv] using h + have hrestriction₂ (u : FABL.F₂Cube k₀) (w : FABL.F₂Cube r₂₀) : + f₂ (eM₂ (Fin.append u w)).1 = beta₂ u := by + have h := hinvariant₂ (eU₂ u).1 (eW₂ w) + simpa [eM₂, beta₂, cubeSplitLinearEquiv] using h + have hphiValue (u : U₁) : + f₁ u.1.1 + f₂ (phi u).1.1 = c := by + have hgraph : + (W₁.mkQ u.1, W₂.mkQ (phi u).1) ∈ e.graph := by + rw [LinearMap.mem_graph_iff] + simp [phi, Submodule.mk_quotientEquivOfIsCompl_apply] + rw [← he] at hgraph + obtain ⟨q, hq⟩ := hgraph + have hq₁ : W₁.mkQ q.1.1 = W₁.mkQ u.1 := by + exact congrArg Prod.fst hq + have hq₂ : W₂.mkQ q.1.2 = W₂.mkQ (phi u).1 := by + exact congrArg Prod.snd hq + have hdiff₁ : q.1.1 - u.1 ∈ W₁ := + (Submodule.Quotient.eq W₁).mp hq₁ + have hdiff₂ : q.1.2 - (phi u).1 ∈ W₂ := + (Submodule.Quotient.eq W₂).mp hq₂ + let w₁ : W₁ := ⟨q.1.1 - u.1, hdiff₁⟩ + let w₂ : W₂ := ⟨q.1.2 - (phi u).1, hdiff₂⟩ + have hvalue₁ : f₁ q.1.1.1 = f₁ u.1.1 := by + have h := hinvariant₁ u.1 w₁ + simpa [w₁, sub_eq_add_neg, add_assoc, ZModModule.add_self, + add_zero] using h + have hvalue₂ : f₂ q.1.2.1 = f₂ (phi u).1.1 := by + have h := hinvariant₂ (phi u).1 w₂ + simpa [w₂, sub_eq_add_neg, add_assoc, ZModModule.add_self, + add_zero] using h + rw [← hvalue₁, ← hvalue₂] + exact hconstantR' q.1 q.2 + have hbetaRelation (u : FABL.F₂Cube k₀) : + beta₁ u = beta₂ u + c := by + have hvalue := hphiValue (eU₁ u) + change beta₁ u + beta₂ u = c at hvalue + apply add_right_cancel (b := beta₂ u) + calc + beta₁ u + beta₂ u = c := hvalue + _ = (beta₂ u + c) + beta₂ u := by + symm + calc + (beta₂ u + c) + beta₂ u = + (beta₂ u + beta₂ u) + c := by abel + _ = c := by rw [ZModModule.add_self, zero_add] + have hcoordinate₁ : + coordinateAffineSubspaceRestriction f₁ M₁ 0 eM₁ = + booleanDirectSum beta₁ (0 : BooleanFunction r₁₀) := by + funext x + let q := cubeSplitLinearEquiv k₀ r₁₀ x + have hx : Fin.append q.1 q.2 = x := by + change (cubeSplitLinearEquiv k₀ r₁₀).symm q = x + exact (cubeSplitLinearEquiv k₀ r₁₀).symm_apply_apply x + rw [← hx, coordinateAffineSubspaceRestriction_apply, add_zero, + hrestriction₁] + simp [booleanDirectSum] + have hcoordinate₂ : + coordinateAffineSubspaceRestriction f₂ M₂ 0 eM₂ = + booleanDirectSum beta₂ (0 : BooleanFunction r₂₀) := by + funext x + let q := cubeSplitLinearEquiv k₀ r₂₀ x + have hx : Fin.append q.1 q.2 = x := by + change (cubeSplitLinearEquiv k₀ r₂₀).symm q = x + exact (cubeSplitLinearEquiv k₀ r₂₀).symm_apply_apply x + rw [← hx, coordinateAffineSubspaceRestriction_apply, add_zero, + hrestriction₂] + simp [booleanDirectSum] + have hzeroWalsh (r : ℕ) : + walshTransform (0 : BooleanFunction r) 0 = (2 : ℤ) ^ r := by + rw [walshTransform] + calc + (∑ x : FABL.F₂Cube r, walshTerm (0 : BooleanFunction r) 0 x) = + ∑ _x : FABL.F₂Cube r, (1 : ℤ) := by + apply Finset.sum_congr rfl + intro x _hx + norm_num [walshTerm, bitSignInt, FABL.f₂DotProduct, dotProduct] + _ = (2 : ℤ) ^ r := by simp + have hbound₁ (a : FABL.F₂Cube k₀) : + 2 ^ r₁₀ * (walshTransform beta₁ a).natAbs ≤ 2 ^ (n / 2) := by + have h := abs_walshTransform_coordinateAffineSubspaceRestriction_le + f₁ M₁ 0 eM₁ (Fin.append a 0) + rw [hcoordinate₁, walshTransform_directSum, hzeroWalsh, + maxWalshMagnitude_eq_two_pow_half_of_isBent f₁ hf₁] at h + change + |(((walshTransform beta₁ a) * (2 : ℤ) ^ r₁₀ : ℤ) : ℝ)| ≤ + ((2 ^ (n / 2) : ℕ) : ℝ) at h + exact natAbs_mul_two_pow_le_of_abs_intCast_le + (walshTransform beta₁ a) r₁₀ (n / 2) h + have hbound₂ (a : FABL.F₂Cube k₀) : + 2 ^ r₂₀ * (walshTransform beta₂ a).natAbs ≤ 2 ^ (m / 2) := by + have h := abs_walshTransform_coordinateAffineSubspaceRestriction_le + f₂ M₂ 0 eM₂ (Fin.append a 0) + rw [hcoordinate₂, walshTransform_directSum, hzeroWalsh, + maxWalshMagnitude_eq_two_pow_half_of_isBent f₂ hf₂] at h + change + |(((walshTransform beta₂ a) * (2 : ℤ) ^ r₂₀ : ℤ) : ℝ)| ≤ + ((2 ^ (m / 2) : ℕ) : ℝ) at h + exact natAbs_mul_two_pow_le_of_abs_intCast_le + (walshTransform beta₂ a) r₂₀ (m / 2) h + have htotalHalf : (n + m) / 2 = n / 2 + m / 2 := by + rcases even_of_isBent f₁ hf₁ with ⟨d₁, hd₁⟩ + rcases even_of_isBent f₂ hf₂ with ⟨d₂, hd₂⟩ + omega + have hdimension : n / 2 + m / 2 = k₀ + r₁₀ + r₂₀ := by + rw [← htotalHalf] + exact hR'dimension + have hwalshRelation (a : FABL.F₂Cube k₀) : + (walshTransform beta₁ a).natAbs = + (walshTransform beta₂ a).natAbs := + natAbs_walshTransform_eq_of_eq_add_constant c hbetaRelation a + obtain ⟨aMax, haMax⟩ := + exists_natAbs_walshTransform_eq_maxWalshMagnitude beta₁ + have hproduct := Nat.mul_le_mul (hbound₁ aMax) (hbound₂ aMax) + rw [← hwalshRelation aMax, haMax] at hproduct + have hproduct' : + 2 ^ (r₁₀ + r₂₀) * (maxWalshMagnitude beta₁) ^ 2 ≤ + 2 ^ (n / 2 + m / 2) := by + calc + 2 ^ (r₁₀ + r₂₀) * (maxWalshMagnitude beta₁) ^ 2 = + (2 ^ r₁₀ * maxWalshMagnitude beta₁) * + (2 ^ r₂₀ * maxWalshMagnitude beta₁) := by + rw [pow_add] + ring + _ ≤ 2 ^ (n / 2) * 2 ^ (m / 2) := hproduct + _ = 2 ^ (n / 2 + m / 2) := by rw [pow_add] + have hfactor : 2 ^ (n / 2 + m / 2) = + 2 ^ (r₁₀ + r₂₀) * 2 ^ k₀ := by + rw [hdimension] + have hexponent : k₀ + r₁₀ + r₂₀ = + (r₁₀ + r₂₀) + k₀ := by omega + rw [hexponent, pow_add] + rw [hfactor] at hproduct' + have hmaxSquareNat : (maxWalshMagnitude beta₁) ^ 2 ≤ 2 ^ k₀ := + Nat.le_of_mul_le_mul_left hproduct' (by positivity) + have hmaxSquareReal : (maxWalshMagnitude beta₁ : ℝ) ^ 2 ≤ + (2 : ℝ) ^ k₀ := by + exact_mod_cast hmaxSquareNat + have hbeta₁ : IsBent beta₁ := + isBent_of_maxWalshMagnitude_sq_le_two_pow beta₁ hmaxSquareReal + have hbetaFunction : beta₁ = beta₂ + FABL.affineFunction c 0 := by + funext u + rw [hbetaRelation u] + simp [FABL.affineFunction, FABL.f₂DotProduct, dotProduct] + have hbeta₂ : IsBent beta₂ := by + have hsum : IsBent (beta₂ + FABL.affineFunction c 0) := by + rw [← hbetaFunction] + exact hbeta₁ + exact (isBent_add_affineFunction_iff beta₂ c 0).1 hsum + have hkEven := even_of_isBent beta₁ hbeta₁ + have hpowBound₁ : 2 ^ (r₁₀ + k₀ / 2) ≤ 2 ^ (n / 2) := by + rw [pow_add] + simpa only [natAbs_walshTransform_eq_two_pow_half_of_isBent + beta₁ hbeta₁] using hbound₁ 0 + have hpowBound₂ : 2 ^ (r₂₀ + k₀ / 2) ≤ 2 ^ (m / 2) := by + rw [pow_add] + simpa only [natAbs_walshTransform_eq_two_pow_half_of_isBent + beta₂ hbeta₂] using hbound₂ 0 + have hdimLe₁ : r₁₀ + k₀ / 2 ≤ n / 2 := + (Nat.pow_le_pow_iff_right (by omega : 1 < 2)).1 hpowBound₁ + have hdimLe₂ : r₂₀ + k₀ / 2 ≤ m / 2 := + (Nat.pow_le_pow_iff_right (by omega : 1 < 2)).1 hpowBound₂ + have hdimEq₁ : r₁₀ + k₀ / 2 = n / 2 := by + rcases hkEven with ⟨d, hd⟩ + omega + have hdimEq₂ : r₂₀ + k₀ / 2 = m / 2 := by + rcases hkEven with ⟨d, hd⟩ + omega + have hnDimension : n = k₀ + (r₁₀ + r₁₀) := by + rcases even_of_isBent f₁ hf₁ with ⟨d₁, hd₁⟩ + rcases hkEven with ⟨d, hd⟩ + omega + have hmDimension : m = k₀ + (r₂₀ + r₂₀) := by + rcases even_of_isBent f₂ hf₂ with ⟨d₂, hd₂⟩ + rcases hkEven with ⟨d, hd⟩ + omega + obtain ⟨C₁, hM₁C₁⟩ := M₁.exists_isCompl + obtain ⟨C₂, hM₂C₂⟩ := M₂.exists_isCompl + have hC₁rank : Module.finrank FABL.𝔽₂ C₁ = r₁₀ := by + have hsum := Submodule.finrank_add_eq_of_isCompl hM₁C₁ + rw [hM₁rank] at hsum + simp only [Module.finrank_fintype_fun_eq_card, Fintype.card_fin] at hsum + omega + have hC₂rank : Module.finrank FABL.𝔽₂ C₂ = r₂₀ := by + have hsum := Submodule.finrank_add_eq_of_isCompl hM₂C₂ + rw [hM₂rank] at hsum + simp only [Module.finrank_fintype_fun_eq_card, Fintype.card_fin] at hsum + omega + let eC₁ : FABL.F₂Cube r₁₀ ≃ₗ[FABL.𝔽₂] C₁ := + LinearEquiv.ofFinrankEq _ _ (by + simp [hC₁rank, Module.finrank_fintype_fun_eq_card]) + let eC₂ : FABL.F₂Cube r₂₀ ≃ₗ[FABL.𝔽₂] C₂ := + LinearEquiv.ofFinrankEq _ _ (by + simp [hC₂rank, Module.finrank_fintype_fun_eq_card]) + let L₁ : FABL.F₂Cube (k₀ + (r₁₀ + r₁₀)) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube n := + (cubeTripleLinearEquiv k₀ r₁₀).trans + ((eU₁.prodCongr (eW₁.prodCongr eC₁)).trans + ((LinearEquiv.prodAssoc FABL.𝔽₂ U₁ W₁ C₁).symm.trans + (((U₁.prodEquivOfIsCompl W₁ hW₁U₁.symm).prodCongr + (LinearEquiv.refl FABL.𝔽₂ C₁)).trans + (M₁.prodEquivOfIsCompl C₁ hM₁C₁)))) + let L₂ : FABL.F₂Cube (k₀ + (r₂₀ + r₂₀)) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube m := + (cubeTripleLinearEquiv k₀ r₂₀).trans + ((eU₂.prodCongr (eW₂.prodCongr eC₂)).trans + ((LinearEquiv.prodAssoc FABL.𝔽₂ U₂ W₂ C₂).symm.trans + (((U₂.prodEquivOfIsCompl W₂ hW₂U₂.symm).prodCongr + (LinearEquiv.refl FABL.𝔽₂ C₂)).trans + (M₂.prodEquivOfIsCompl C₂ hM₂C₂)))) + have hL₁ (u : FABL.F₂Cube k₀) (w : FABL.F₂Cube r₁₀) : + f₁ (L₁ (Fin.append u (Fin.append w 0))) = beta₁ u := by + have hzero : (fun _i : Fin r₁₀ ↦ (0 : FABL.𝔽₂)) = 0 := rfl + simpa [L₁, cubeTripleLinearEquiv, cubeSplitLinearEquiv, + LinearEquiv.prodAssoc, hzero, + eC₁, eM₁] using hrestriction₁ u w + have hL₂ (u : FABL.F₂Cube k₀) (w : FABL.F₂Cube r₂₀) : + f₂ (L₂ (Fin.append u (Fin.append w 0))) = beta₂ u := by + have hzero : (fun _i : Fin r₂₀ ↦ (0 : FABL.𝔽₂)) = 0 := rfl + simpa [L₂, cubeTripleLinearEquiv, cubeSplitLinearEquiv, + LinearEquiv.prodAssoc, hzero, + eC₂, eM₂] using hrestriction₂ u w + have hext₁ : IsNormalExtension beta₁ f₁ := + ⟨hbeta₁, hf₁, r₁₀, L₁, hL₁⟩ + have hext₂ : IsNormalExtension beta₂ f₂ := + ⟨hbeta₂, hf₂, r₂₀, L₂, hL₂⟩ + exact ⟨k₀, k₀, beta₁, beta₂, hext₁, hext₂, + LinearEquiv.refl FABL.𝔽₂ (FABL.F₂Cube k₀), c, hbetaRelation⟩ + +/-- Carlet Proposition 29: a direct sum of bent functions is normal on a +linear subspace exactly when there are linearly equivalent or complementary +normal extensions of its summands. -/ +theorem isSubspaceNormal_booleanDirectSum_iff + {f₁ : BooleanFunction n} {f₂ : BooleanFunction m} + (hf₁ : IsBent f₁) (hf₂ : IsBent f₂) : + IsSubspaceNormal (booleanDirectSum f₁ f₂) ↔ + ∃ k₁ k₂, ∃ beta₁ : BooleanFunction k₁, + ∃ beta₂ : BooleanFunction k₂, + IsNormalExtension beta₁ f₁ ∧ + IsNormalExtension beta₂ f₂ ∧ + AreLinearlyEquivalentOrComplementary beta₁ beta₂ := by + constructor + · exact exists_compatibleNormalExtensions_of_isSubspaceNormal_booleanDirectSum hf₁ hf₂ + · rintro ⟨k₁, k₂, beta₁, beta₂, hext₁, hext₂, hcompatible⟩ + exact isSubspaceNormal_booleanDirectSum_of_compatibleNormalExtensions + hext₁ hext₂ hcompatible +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/PartialBent.lean b/CryptBoolean/Carlet/Chapter06/PartialBent.lean new file mode 100644 index 0000000..c324f42 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/PartialBent.lean @@ -0,0 +1,38 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter02.FourierOperations +public import FABL.Chapter06.F₂Polynomials.Encoding + +/-! +# Partial bent functions + +Carlet's two-level Fourier definition on the punctured binary cube. +-/ + +open scoped BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The raw Fourier transform of the zero-one embedding takes exactly the +levels `level` and `level + 2^(n/2)` on the punctured cube. -/ +def HasPartialBentFourierLevels + (f : BooleanFunction n) (level : ℤ) : Prop := + Set.range (fun u : {u : FABL.F₂Cube n // u ≠ 0} ↦ + rawFourierTransform (FABL.booleanRealEmbedding f) u.1) = + ({(level : ℝ), (level : ℝ) + (2 : ℝ) ^ (n / 2)} : Set ℝ) + +/-- A partial bent function has even dimension and exactly two raw Fourier +levels, separated by `2^(n/2)`, on the punctured cube. -/ +def IsPartialBent (f : BooleanFunction n) : Prop := + Even n ∧ ∃ level : ℤ, HasPartialBentFourierLevels f level + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/PartialBentCounterexamples.lean b/CryptBoolean/Carlet/Chapter06/PartialBentCounterexamples.lean new file mode 100644 index 0000000..ca0a898 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/PartialBentCounterexamples.lean @@ -0,0 +1,238 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.PartialBentDual +public import FABL.Chapter06.F₂Polynomials.ExtremalBounds + +/-! +# Counterexamples for printed partial-bent assertions + +Finite two-variable counterexamples to the algebraic-degree and disjoint-support +sum assertions printed on Carlet p. 105 under the exact punctured two-level definition. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +/-- The indicator of the singleton binary point `![1, 0]`. -/ +def partialBentDegreeCounterexample : BooleanFunction 2 := + fun x ↦ if x = ![1, 0] then 1 else 0 + +/-- The indicator of the two points whose second coordinate is one. -/ +def partialBentSumCounterexampleCompanion : BooleanFunction 2 := + fun x ↦ x 1 + +private theorem partialBentIntegerFourier_partialBentDegreeCounterexample + (u : FABL.F₂Cube 2) : + partialBentIntegerFourier partialBentDegreeCounterexample u = + if u = 0 then 1 else if u 0 = 0 then 1 else -1 := by + decide +revert + +private theorem partialBentIntegerFourier_partialBentSumCounterexampleCompanion + (u : FABL.F₂Cube 2) : + partialBentIntegerFourier partialBentSumCounterexampleCompanion u = + if u = 0 then 2 else if u = ![0, 1] then -2 else 0 := by + decide +revert + +private theorem partialBentIntegerFourier_add_partialBentCounterexamples + (u : FABL.F₂Cube 2) : + partialBentIntegerFourier + (partialBentDegreeCounterexample + partialBentSumCounterexampleCompanion) u = + if u = 0 then 3 else -1 := by + decide +revert + +private theorem rawFourierTransform_partialBentDegreeCounterexample + (u : FABL.F₂Cube 2) : + rawFourierTransform + (FABL.booleanRealEmbedding partialBentDegreeCounterexample) u = + if u = 0 then 1 else if u 0 = 0 then 1 else -1 := by + rw [← partialBentIntegerFourier_cast, + partialBentIntegerFourier_partialBentDegreeCounterexample] + split <;> norm_num + +private theorem rawFourierTransform_partialBentSumCounterexampleCompanion + (u : FABL.F₂Cube 2) : + rawFourierTransform + (FABL.booleanRealEmbedding partialBentSumCounterexampleCompanion) u = + if u = 0 then 2 else if u = ![0, 1] then -2 else 0 := by + rw [← partialBentIntegerFourier_cast, + partialBentIntegerFourier_partialBentSumCounterexampleCompanion] + split <;> norm_num + +private theorem rawFourierTransform_add_partialBentCounterexamples + (u : FABL.F₂Cube 2) : + rawFourierTransform + (FABL.booleanRealEmbedding + (partialBentDegreeCounterexample + partialBentSumCounterexampleCompanion)) u = + if u = 0 then 3 else -1 := by + rw [← partialBentIntegerFourier_cast, + partialBentIntegerFourier_add_partialBentCounterexamples] + split <;> norm_num + +private theorem hasPartialBentFourierLevels_partialBentDegreeCounterexample : + HasPartialBentFourierLevels partialBentDegreeCounterexample (-1) := by + rw [HasPartialBentFourierLevels] + ext z + constructor + · rintro ⟨u, rfl⟩ + change rawFourierTransform + (FABL.booleanRealEmbedding partialBentDegreeCounterexample) u.1 ∈ _ + rw [rawFourierTransform_partialBentDegreeCounterexample, if_neg u.2] + split <;> norm_num + · intro hz + norm_num at hz + rcases hz with rfl | rfl + · have hpoint : ![1, 0] ≠ (0 : FABL.F₂Cube 2) := by decide + refine ⟨⟨![1, 0], hpoint⟩, ?_⟩ + change rawFourierTransform + (FABL.booleanRealEmbedding partialBentDegreeCounterexample) ![1, 0] = -1 + rw [rawFourierTransform_partialBentDegreeCounterexample] + norm_num + · have hpoint : ![0, 1] ≠ (0 : FABL.F₂Cube 2) := by decide + refine ⟨⟨![0, 1], hpoint⟩, ?_⟩ + change rawFourierTransform + (FABL.booleanRealEmbedding partialBentDegreeCounterexample) ![0, 1] = 1 + rw [rawFourierTransform_partialBentDegreeCounterexample] + norm_num + +private theorem hasPartialBentFourierLevels_partialBentSumCounterexampleCompanion : + HasPartialBentFourierLevels partialBentSumCounterexampleCompanion (-2) := by + rw [HasPartialBentFourierLevels] + ext z + constructor + · rintro ⟨u, rfl⟩ + change rawFourierTransform + (FABL.booleanRealEmbedding partialBentSumCounterexampleCompanion) u.1 ∈ _ + rw [rawFourierTransform_partialBentSumCounterexampleCompanion, if_neg u.2] + split <;> norm_num + · intro hz + norm_num at hz + rcases hz with rfl | rfl + · have hpoint : ![0, 1] ≠ (0 : FABL.F₂Cube 2) := by decide + refine ⟨⟨![0, 1], hpoint⟩, ?_⟩ + change rawFourierTransform + (FABL.booleanRealEmbedding partialBentSumCounterexampleCompanion) ![0, 1] = -2 + rw [rawFourierTransform_partialBentSumCounterexampleCompanion] + norm_num + · have hpoint : ![1, 0] ≠ (0 : FABL.F₂Cube 2) := by decide + refine ⟨⟨![1, 0], hpoint⟩, ?_⟩ + change rawFourierTransform + (FABL.booleanRealEmbedding partialBentSumCounterexampleCompanion) ![1, 0] = 0 + rw [rawFourierTransform_partialBentSumCounterexampleCompanion] + norm_num + +private theorem isPartialBent_partialBentDegreeCounterexample : + IsPartialBent partialBentDegreeCounterexample := + ⟨by norm_num, -1, hasPartialBentFourierLevels_partialBentDegreeCounterexample⟩ + +private theorem isPartialBent_partialBentSumCounterexampleCompanion : + IsPartialBent partialBentSumCounterexampleCompanion := + ⟨by norm_num, -2, hasPartialBentFourierLevels_partialBentSumCounterexampleCompanion⟩ + +private theorem functionAlgebraicDegree_partialBentDegreeCounterexample : + FABL.functionAlgebraicDegree partialBentDegreeCounterexample = 2 := by + apply (FABL.functionAlgebraicDegree_eq_dimension_iff_card_f₂OneSupport_odd + partialBentDegreeCounterexample (by norm_num)).2 + decide + +/-- The exact punctured two-level definition permits algebraic degree +strictly greater than half the dimension. -/ +theorem partialBentDegreeCounterexample_refutes_bound : + IsPartialBent partialBentDegreeCounterexample ∧ + FABL.functionAlgebraicDegree partialBentDegreeCounterexample = 2 ∧ + 2 / 2 < FABL.functionAlgebraicDegree partialBentDegreeCounterexample := by + refine ⟨isPartialBent_partialBentDegreeCounterexample, + functionAlgebraicDegree_partialBentDegreeCounterexample, ?_⟩ + rw [functionAlgebraicDegree_partialBentDegreeCounterexample] + norm_num + +private theorem partialBentDegreeCounterexample_has_first_type : + partialBentIntegerFourier partialBentDegreeCounterexample 0 - + bitValueInt (partialBentDegreeCounterexample 0) = + -((-1 : ℤ) - bitValueInt (partialBentDegreeCounterexample 0)) * + ((2 : ℤ) ^ (2 / 2) - 1) := by + decide + +private theorem partialBentSumCounterexampleCompanion_has_first_type : + partialBentIntegerFourier partialBentSumCounterexampleCompanion 0 - + bitValueInt (partialBentSumCounterexampleCompanion 0) = + -((-2 : ℤ) - bitValueInt (partialBentSumCounterexampleCompanion 0)) * + ((2 : ℤ) ^ (2 / 2) - 1) := by + decide + +private theorem partialBentCounterexamples_support_inter_subset_zero : + support partialBentDegreeCounterexample ∩ support partialBentSumCounterexampleCompanion ⊆ + ({0} : Finset (FABL.F₂Cube 2)) := by + decide + +private theorem not_isPartialBent_add_partialBentCounterexamples : + ¬ IsPartialBent + (partialBentDegreeCounterexample + partialBentSumCounterexampleCompanion) := by + rintro ⟨_even, level, hlevels⟩ + rw [HasPartialBentFourierLevels] at hlevels + have hlevelRange : (level : ℝ) ∈ + Set.range (fun u : {u : FABL.F₂Cube 2 // u ≠ 0} ↦ + rawFourierTransform + (FABL.booleanRealEmbedding + (partialBentDegreeCounterexample + partialBentSumCounterexampleCompanion)) u.1) := by + rw [hlevels] + simp + obtain ⟨u, hu⟩ := hlevelRange + change rawFourierTransform + (FABL.booleanRealEmbedding + (partialBentDegreeCounterexample + partialBentSumCounterexampleCompanion)) u.1 = + (level : ℝ) at hu + rw [rawFourierTransform_add_partialBentCounterexamples, if_neg u.2] at hu + have hupperRange : (level : ℝ) + (2 : ℝ) ^ (2 / 2) ∈ + Set.range (fun u : {u : FABL.F₂Cube 2 // u ≠ 0} ↦ + rawFourierTransform + (FABL.booleanRealEmbedding + (partialBentDegreeCounterexample + partialBentSumCounterexampleCompanion)) u.1) := by + rw [hlevels] + simp + obtain ⟨v, hv⟩ := hupperRange + change rawFourierTransform + (FABL.booleanRealEmbedding + (partialBentDegreeCounterexample + partialBentSumCounterexampleCompanion)) v.1 = + (level : ℝ) + (2 : ℝ) ^ (2 / 2) at hv + rw [rawFourierTransform_add_partialBentCounterexamples, if_neg v.2] at hv + norm_num at hv + linarith + +/-- Two partial bent functions of the corrected first Fourier type can +have disjoint supports while their sum fails to be partial bent. -/ +theorem partialBentCounterexamples_refute_disjoint_support_sum : + HasPartialBentFourierLevels partialBentDegreeCounterexample (-1) ∧ + HasPartialBentFourierLevels partialBentSumCounterexampleCompanion (-2) ∧ + IsPartialBent partialBentDegreeCounterexample ∧ + IsPartialBent partialBentSumCounterexampleCompanion ∧ + (partialBentIntegerFourier partialBentDegreeCounterexample 0 - + bitValueInt (partialBentDegreeCounterexample 0) = + -((-1 : ℤ) - bitValueInt (partialBentDegreeCounterexample 0)) * + ((2 : ℤ) ^ (2 / 2) - 1)) ∧ + (partialBentIntegerFourier partialBentSumCounterexampleCompanion 0 - + bitValueInt (partialBentSumCounterexampleCompanion 0) = + -((-2 : ℤ) - bitValueInt (partialBentSumCounterexampleCompanion 0)) * + ((2 : ℤ) ^ (2 / 2) - 1)) ∧ + support partialBentDegreeCounterexample ∩ support partialBentSumCounterexampleCompanion ⊆ + ({0} : Finset (FABL.F₂Cube 2)) ∧ + ¬ IsPartialBent + (partialBentDegreeCounterexample + partialBentSumCounterexampleCompanion) := by + exact ⟨hasPartialBentFourierLevels_partialBentDegreeCounterexample, + hasPartialBentFourierLevels_partialBentSumCounterexampleCompanion, + isPartialBent_partialBentDegreeCounterexample, + isPartialBent_partialBentSumCounterexampleCompanion, + partialBentDegreeCounterexample_has_first_type, + partialBentSumCounterexampleCompanion_has_first_type, + partialBentCounterexamples_support_inter_subset_zero, + not_isPartialBent_add_partialBentCounterexamples⟩ + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/PartialBentDual.lean b/CryptBoolean/Carlet/Chapter06/PartialBentDual.lean new file mode 100644 index 0000000..ac58c5f --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/PartialBentDual.lean @@ -0,0 +1,648 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.PartialBent +public import CryptBoolean.Carlet.Chapter05.CoveringSequences + +/-! +# Duality and Fourier types of partial bent functions + +The punctured two-level Fourier definition, its involutive duality, and the +corrected Parseval dichotomy for the two Fourier types. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The integral raw Fourier transform of a Boolean function's zero-one embedding. -/ +def partialBentIntegerFourier + (f : BooleanFunction n) (u : FABL.F₂Cube n) : ℤ := + integerWalshTransform (fun x ↦ bitValueInt (f x)) u + +/-- The integral partial-bent transform casts to the raw real Fourier transform. -/ +theorem partialBentIntegerFourier_cast + (f : BooleanFunction n) (u : FABL.F₂Cube n) : + (partialBentIntegerFourier f u : ℝ) = + rawFourierTransform (FABL.booleanRealEmbedding f) u := by + rw [partialBentIntegerFourier, + integerWalshTransform_cast_eq_rawFourierTransform] + congr 2 + funext x + by_cases hx : f x = 1 <;> + simp [bitValueInt, FABL.booleanRealEmbedding, hx] + +private theorem sum_bitSignInt_dotProduct_eq_zero + (u : FABL.F₂Cube n) (hu : u ≠ 0) : + ∑ x, bitSignInt (FABL.f₂DotProduct x u) = 0 := by + have hzero : + integerWalshTransform (fun _ : FABL.F₂Cube n ↦ (1 : ℤ)) u = 0 := by + apply Int.cast_injective (α := ℝ) + norm_num only [Int.cast_zero] + calc + (integerWalshTransform (fun _ : FABL.F₂Cube n ↦ (1 : ℤ)) u : ℝ) = + rawFourierTransform (fun _ : FABL.F₂Cube n ↦ (1 : ℝ)) u := by + simpa using integerWalshTransform_cast_eq_rawFourierTransform + (fun _ : FABL.F₂Cube n ↦ (1 : ℤ)) u + _ = 0 := by rw [rawFourierTransform_one, if_neg hu] + simpa [integerWalshTransform] using hzero + +private theorem partialBentIntegerFourier_eq_of_constant_punctured + (f : BooleanFunction n) (b : FABL.𝔽₂) + (hconstant : ∀ x ≠ 0, f x = b) + (u : FABL.F₂Cube n) (hu : u ≠ 0) : + partialBentIntegerFourier f u = + bitValueInt (f 0) - bitValueInt b := by + rw [partialBentIntegerFourier, integerWalshTransform] + have hsum := sum_bitSignInt_dotProduct_eq_zero u hu + rw [← Finset.sum_erase_add _ _ (Finset.mem_univ (0 : FABL.F₂Cube n))] at hsum ⊢ + have hrest : + ∑ x ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + bitValueInt (f x) * bitSignInt (FABL.f₂DotProduct x u) = + bitValueInt b * + ∑ x ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + bitSignInt (FABL.f₂DotProduct x u) := by + rw [Finset.mul_sum] + apply Finset.sum_congr rfl + intro x hx + have hx0 : x ≠ 0 := by + simpa using (Finset.mem_erase.mp hx).1 + rw [hconstant x hx0] + rw [hrest] + simp [FABL.f₂DotProduct, bitSignInt] at hsum ⊢ + linear_combination bitValueInt b * hsum + +private theorem exists_punctured_zero_and_one_of_partialBentLevels + (f : BooleanFunction n) (level : ℤ) + (hlevels : HasPartialBentFourierLevels f level) : + (∃ x ≠ 0, f x = 0) ∧ (∃ x ≠ 0, f x = 1) := by + have hq : (0 : ℝ) < (2 : ℝ) ^ (n / 2) := by positivity + have hdistinct : + (level : ℝ) ≠ (level : ℝ) + (2 : ℝ) ^ (n / 2) := by + linarith + have hexistsLevel : + ∃ u : {u : FABL.F₂Cube n // u ≠ 0}, + rawFourierTransform (FABL.booleanRealEmbedding f) u.1 = (level : ℝ) := by + have hmem : (level : ℝ) ∈ + ({(level : ℝ), (level : ℝ) + (2 : ℝ) ^ (n / 2)} : Set ℝ) := by + simp + rw [← hlevels] at hmem + exact hmem + have hexistsUpper : + ∃ u : {u : FABL.F₂Cube n // u ≠ 0}, + rawFourierTransform (FABL.booleanRealEmbedding f) u.1 = + (level : ℝ) + (2 : ℝ) ^ (n / 2) := by + have hmem : (level : ℝ) + (2 : ℝ) ^ (n / 2) ∈ + ({(level : ℝ), (level : ℝ) + (2 : ℝ) ^ (n / 2)} : Set ℝ) := by + simp + rw [← hlevels] at hmem + exact hmem + obtain ⟨u, hu⟩ := hexistsLevel + obtain ⟨v, hv⟩ := hexistsUpper + constructor + · by_contra hzero + push Not at hzero + have hconstant : ∀ x ≠ 0, f x = 1 := by + intro x hx + exact Fin.eq_one_of_ne_zero _ (hzero x hx) + have heu := partialBentIntegerFourier_eq_of_constant_punctured + f 1 hconstant u.1 u.2 + have hev := partialBentIntegerFourier_eq_of_constant_punctured + f 1 hconstant v.1 v.2 + have hucast := partialBentIntegerFourier_cast f u.1 + have hvcast := partialBentIntegerFourier_cast f v.1 + rw [heu, hu] at hucast + rw [hev, hv] at hvcast + linarith + · by_contra hone + push Not at hone + have hconstant : ∀ x ≠ 0, f x = 0 := by + intro x hx + by_contra hzero + exact hone x hx (Fin.eq_one_of_ne_zero _ hzero) + have heu := partialBentIntegerFourier_eq_of_constant_punctured + f 0 hconstant u.1 u.2 + have hev := partialBentIntegerFourier_eq_of_constant_punctured + f 0 hconstant v.1 v.2 + have hucast := partialBentIntegerFourier_cast f u.1 + have hvcast := partialBentIntegerFourier_cast f v.1 + rw [heu, hu] at hucast + rw [hev, hv] at hvcast + linarith + +private theorem partialBentIntegerFourier_eq_level_or + (f : BooleanFunction n) (level : ℤ) + (hlevels : HasPartialBentFourierLevels f level) + (u : FABL.F₂Cube n) (hu : u ≠ 0) : + partialBentIntegerFourier f u = level ∨ + partialBentIntegerFourier f u = level + (2 : ℤ) ^ (n / 2) := by + have hmem : + rawFourierTransform (FABL.booleanRealEmbedding f) u ∈ + Set.range (fun v : {v : FABL.F₂Cube n // v ≠ 0} ↦ + rawFourierTransform (FABL.booleanRealEmbedding f) v.1) := + ⟨⟨u, hu⟩, rfl⟩ + rw [hlevels] at hmem + simp only [Set.mem_insert_iff, Set.mem_singleton_iff] at hmem + have hcast := partialBentIntegerFourier_cast f u + rcases hmem with h | h + · left + exact_mod_cast hcast.trans h + · right + have hpow : (((2 : ℤ) ^ (n / 2) : ℤ) : ℝ) = + (2 : ℝ) ^ (n / 2) := by norm_num + exact_mod_cast hcast.trans h + +/-- The dual of a partial bent function, with the source's punctured-spectrum +convention completed at zero by `f(0)`. -/ +def partialBentDual + (f : BooleanFunction n) (level : ℤ) : BooleanFunction n := + fun u ↦ + if u = 0 then f 0 + else if partialBentIntegerFourier f u = level then 0 else 1 + +@[simp] theorem partialBentDual_zero + (f : BooleanFunction n) (level : ℤ) : + partialBentDual f level 0 = f 0 := by + simp [partialBentDual] + +private theorem bitValueInt_partialBentDual_of_ne_zero + (f : BooleanFunction n) (level : ℤ) + (u : FABL.F₂Cube n) (hu : u ≠ 0) : + bitValueInt (partialBentDual f level u) = + if partialBentIntegerFourier f u = level then 0 else 1 := by + by_cases hvalue : partialBentIntegerFourier f u = level <;> + simp [partialBentDual, hu, hvalue, bitValueInt] + +private theorem partialBentIntegerFourier_decomposition + (f : BooleanFunction n) (level : ℤ) + (hlevels : HasPartialBentFourierLevels f level) + (u : FABL.F₂Cube n) : + partialBentIntegerFourier f u = + level + (2 : ℤ) ^ (n / 2) * + bitValueInt (partialBentDual f level u) + + if u = 0 then + partialBentIntegerFourier f 0 - level - + (2 : ℤ) ^ (n / 2) * bitValueInt (f 0) + else 0 := by + by_cases hu : u = 0 + · subst u + simp [partialBentDual] + · rcases partialBentIntegerFourier_eq_level_or f level hlevels u hu with + hvalue | hvalue + · rw [if_neg hu, + bitValueInt_partialBentDual_of_ne_zero f level u hu, + if_pos hvalue] + omega + · have hne : partialBentIntegerFourier f u ≠ level := by + intro heq + have hpositive : (0 : ℤ) < (2 : ℤ) ^ (n / 2) := by positivity + omega + rw [if_neg hu, + bitValueInt_partialBentDual_of_ne_zero f level u hu, + if_neg hne, hvalue] + omega + +private theorem partialBentDual_transform_relation + (f : BooleanFunction n) (level : ℤ) + (hlevels : HasPartialBentFourierLevels f level) + (x : FABL.F₂Cube n) (hx : x ≠ 0) : + (2 : ℤ) ^ (n / 2) * + partialBentIntegerFourier (partialBentDual f level) x = + (2 : ℤ) ^ n * bitValueInt (f x) - + (partialBentIntegerFourier f 0 - level - + (2 : ℤ) ^ (n / 2) * bitValueInt (f 0)) := by + let q : ℤ := (2 : ℤ) ^ (n / 2) + let correction : ℤ := + partialBentIntegerFourier f 0 - level - q * bitValueInt (f 0) + have hinvolution := + integerWalshTransform_involution + (fun y ↦ bitValueInt (f y)) x + change integerWalshTransform (partialBentIntegerFourier f) x = + (2 : ℤ) ^ n * bitValueInt (f x) at hinvolution + rw [integerWalshTransform] at hinvolution + have hconstant := sum_bitSignInt_dotProduct_eq_zero x hx + have horigin : + ∑ u : FABL.F₂Cube n, + (if u = 0 then correction else 0) * + bitSignInt (FABL.f₂DotProduct u x) = correction := by + rw [Fintype.sum_eq_single 0] + · simp [FABL.f₂DotProduct, bitSignInt] + · intro u hu + simp [hu] + have hdual : + ∑ u : FABL.F₂Cube n, + (q * bitValueInt (partialBentDual f level u)) * + bitSignInt (FABL.f₂DotProduct u x) = + q * partialBentIntegerFourier (partialBentDual f level) x := by + rw [partialBentIntegerFourier, integerWalshTransform, Finset.mul_sum] + apply Finset.sum_congr rfl + intro u _hu + ring + have hdecomposition (u : FABL.F₂Cube n) : + partialBentIntegerFourier f u = + level + q * bitValueInt (partialBentDual f level u) + + if u = 0 then correction else 0 := by + exact partialBentIntegerFourier_decomposition f level hlevels u + simp_rw [hdecomposition] at hinvolution + have hconstantScaled : + ∑ u : FABL.F₂Cube n, + level * bitSignInt (FABL.f₂DotProduct u x) = 0 := by + rw [← Finset.mul_sum, hconstant, mul_zero] + rw [show + (∑ u : FABL.F₂Cube n, + (level + q * bitValueInt (partialBentDual f level u) + + if u = 0 then correction else 0) * + bitSignInt (FABL.f₂DotProduct u x)) = + (∑ u : FABL.F₂Cube n, + level * bitSignInt (FABL.f₂DotProduct u x)) + + (∑ u : FABL.F₂Cube n, + (q * bitValueInt (partialBentDual f level u)) * + bitSignInt (FABL.f₂DotProduct u x)) + + (∑ u : FABL.F₂Cube n, + (if u = 0 then correction else 0) * + bitSignInt (FABL.f₂DotProduct u x)) by + rw [← Finset.sum_add_distrib, ← Finset.sum_add_distrib] + apply Finset.sum_congr rfl + intro u _hu + ring] at hinvolution + rw [hconstantScaled, zero_add, hdual, horigin] at hinvolution + dsimp [q, correction] at hinvolution ⊢ + omega + +/-- The punctured Fourier transform of the partial-bent dual again has two +levels, and its level choice records the values of the original function. -/ +theorem exists_partialBentDual_fourierLevels + (f : BooleanFunction n) (level : ℤ) + (hn : Even n) + (hlevels : HasPartialBentFourierLevels f level) : + ∃ dualLevel : ℤ, + HasPartialBentFourierLevels (partialBentDual f level) dualLevel ∧ + ∀ x ≠ 0, + partialBentIntegerFourier (partialBentDual f level) x = + dualLevel + (2 : ℤ) ^ (n / 2) * bitValueInt (f x) := by + obtain ⟨⟨x₀, hx₀, hfx₀⟩, ⟨x₁, hx₁, hfx₁⟩⟩ := + exists_punctured_zero_and_one_of_partialBentLevels f level hlevels + let g := partialBentDual f level + let dualLevel := partialBentIntegerFourier g x₀ + refine ⟨dualLevel, ?_, ?_⟩ + · rw [HasPartialBentFourierLevels] + ext value + constructor + · rintro ⟨⟨x, hx⟩, rfl⟩ + have hrelationX := + partialBentDual_transform_relation f level hlevels x hx + have hrelationZero := + partialBentDual_transform_relation f level hlevels x₀ hx₀ + have hq : (2 : ℤ) ^ (n / 2) ≠ 0 := by positivity + have hpow : (2 : ℤ) ^ n = + (2 : ℤ) ^ (n / 2) * (2 : ℤ) ^ (n / 2) := by + rcases hn with ⟨m, rfl⟩ + have hhalf : (m + m) / 2 = m := by omega + rw [hhalf, ← pow_add] + rw [hpow] at hrelationX hrelationZero + have hbitZero : bitValueInt (f x₀) = 0 := by + simp [hfx₀, bitValueInt] + rw [hbitZero, mul_zero] at hrelationZero + have hvalue : + partialBentIntegerFourier g x = + dualLevel + (2 : ℤ) ^ (n / 2) * bitValueInt (f x) := by + dsimp [g, dualLevel] + apply mul_left_cancel₀ hq + linear_combination hrelationX - hrelationZero + have hcast := partialBentIntegerFourier_cast g x + rw [hvalue] at hcast + by_cases hfx : f x = 0 + · left + rw [hfx] at hcast + simpa [bitValueInt] using hcast.symm + · right + have hfxOne : f x = 1 := Fin.eq_one_of_ne_zero _ hfx + rw [hfxOne] at hcast + norm_num [bitValueInt] at hcast ⊢ + exact hcast.symm + · intro hvalue + simp only [Set.mem_insert_iff, Set.mem_singleton_iff] at hvalue + rcases hvalue with hvalue | hvalue + · refine ⟨⟨x₀, hx₀⟩, ?_⟩ + have hcast := partialBentIntegerFourier_cast g x₀ + dsimp [dualLevel] + rw [hvalue] + exact hcast.symm + · refine ⟨⟨x₁, hx₁⟩, ?_⟩ + have hrelationOne := + partialBentDual_transform_relation f level hlevels x₁ hx₁ + have hrelationZero := + partialBentDual_transform_relation f level hlevels x₀ hx₀ + have hq : (2 : ℤ) ^ (n / 2) ≠ 0 := by positivity + have hpow : (2 : ℤ) ^ n = + (2 : ℤ) ^ (n / 2) * (2 : ℤ) ^ (n / 2) := by + rcases hn with ⟨m, rfl⟩ + have hhalf : (m + m) / 2 = m := by omega + rw [hhalf, ← pow_add] + rw [hpow] at hrelationOne hrelationZero + have hbitOne : bitValueInt (f x₁) = 1 := by + simp [hfx₁, bitValueInt] + have hbitZero : bitValueInt (f x₀) = 0 := by + simp [hfx₀, bitValueInt] + rw [hbitOne, mul_one] at hrelationOne + rw [hbitZero, mul_zero] at hrelationZero + have hinteger : + partialBentIntegerFourier g x₁ = + dualLevel + (2 : ℤ) ^ (n / 2) := by + dsimp [dualLevel] + apply mul_left_cancel₀ hq + linear_combination hrelationOne - hrelationZero + have hcast := partialBentIntegerFourier_cast g x₁ + rw [hinteger] at hcast + rw [hvalue] + norm_num at hcast ⊢ + simpa [g] using hcast.symm + · intro x hx + have hrelationX := + partialBentDual_transform_relation f level hlevels x hx + have hrelationZero := + partialBentDual_transform_relation f level hlevels x₀ hx₀ + have hq : (2 : ℤ) ^ (n / 2) ≠ 0 := by positivity + have hpow : (2 : ℤ) ^ n = + (2 : ℤ) ^ (n / 2) * (2 : ℤ) ^ (n / 2) := by + rcases hn with ⟨m, rfl⟩ + have hhalf : (m + m) / 2 = m := by omega + rw [hhalf, ← pow_add] + rw [hpow] at hrelationX hrelationZero + have hbitZero : bitValueInt (f x₀) = 0 := by + simp [hfx₀, bitValueInt] + rw [hbitZero, mul_zero] at hrelationZero + dsimp [g, dualLevel] + apply mul_left_cancel₀ hq + linear_combination hrelationX - hrelationZero + +/-- Taking the partial-bent dual twice, with the Fourier levels supplied by +the first duality theorem, returns the original function. -/ +theorem partialBentDual_involution + (f : BooleanFunction n) (level dualLevel : ℤ) + (hdual : ∀ x ≠ 0, + partialBentIntegerFourier (partialBentDual f level) x = + dualLevel + (2 : ℤ) ^ (n / 2) * bitValueInt (f x)) : + partialBentDual (partialBentDual f level) dualLevel = f := by + funext x + by_cases hx : x = 0 + · subst x + simp + · rw [partialBentDual] + simp only [hx, if_false] + rw [hdual x hx] + by_cases hfx : f x = 0 + · simp [hfx, bitValueInt] + · have hfxOne : f x = 1 := Fin.eq_one_of_ne_zero _ hfx + rw [hfxOne] + simp [bitValueInt] + +/-- A partial-bent dual is partial bent, and its dual is the original function. -/ +theorem exists_isPartialBent_partialBentDual_and_involution + (f : BooleanFunction n) (level : ℤ) + (hn : Even n) + (hlevels : HasPartialBentFourierLevels f level) : + ∃ dualLevel : ℤ, + IsPartialBent (partialBentDual f level) ∧ + HasPartialBentFourierLevels (partialBentDual f level) dualLevel ∧ + partialBentDual (partialBentDual f level) dualLevel = f := by + obtain ⟨dualLevel, hdualLevels, htransform⟩ := + exists_partialBentDual_fourierLevels f level hn hlevels + exact ⟨dualLevel, ⟨hn, dualLevel, hdualLevels⟩, hdualLevels, + partialBentDual_involution f level dualLevel htransform⟩ + +private theorem sum_partialBentIntegerFourier + (f : BooleanFunction n) : + ∑ u, partialBentIntegerFourier f u = + (2 : ℤ) ^ n * bitValueInt (f 0) := by + have hinvolution := integerWalshTransform_involution + (fun x ↦ bitValueInt (f x)) (0 : FABL.F₂Cube n) + change integerWalshTransform (partialBentIntegerFourier f) 0 = + (2 : ℤ) ^ n * bitValueInt (f 0) at hinvolution + simpa using hinvolution + +private theorem sum_partialBentIntegerFourier_sq + (f : BooleanFunction n) : + ∑ u, (partialBentIntegerFourier f u) ^ 2 = + (2 : ℤ) ^ n * partialBentIntegerFourier f 0 := by + apply Int.cast_injective (α := ℝ) + norm_num only [Int.cast_sum, Int.cast_pow, Int.cast_ofNat, Int.cast_mul] + simp_rw [partialBentIntegerFourier_cast] + rw [show + (∑ u : FABL.F₂Cube n, + rawFourierTransform (FABL.booleanRealEmbedding f) u ^ 2) = + ∑ u : FABL.F₂Cube n, + rawFourierTransform (FABL.booleanRealEmbedding f) u * + rawFourierTransform (FABL.booleanRealEmbedding f) u by + apply Finset.sum_congr rfl + intro u _hu + ring, + sum_rawFourierTransform_mul] + have hsum : + ∑ x : FABL.F₂Cube n, + FABL.booleanRealEmbedding f x * FABL.booleanRealEmbedding f x = + rawFourierTransform (FABL.booleanRealEmbedding f) 0 := by + calc + ∑ x : FABL.F₂Cube n, + FABL.booleanRealEmbedding f x * FABL.booleanRealEmbedding f x = + ∑ x : FABL.F₂Cube n, FABL.booleanRealEmbedding f x := by + apply Finset.sum_congr rfl + intro x _hx + by_cases hfx : f x = 1 <;> + simp [FABL.booleanRealEmbedding, hfx] + _ = rawFourierTransform (FABL.booleanRealEmbedding f) 0 := by + simp [rawFourierTransform] + rw [hsum] + +/-- Parseval gives the two mutually exclusive partial-bent Fourier types. +The second factor has the corrected sign, and both factors retain the origin +value required by the punctured-spectrum convention. -/ +theorem partialBent_fourier_level_types + (f : BooleanFunction n) (level : ℤ) + (hnEven : Even n) (hn : 0 < n) + (hlevels : HasPartialBentFourierLevels f level) : + Xor + (partialBentIntegerFourier f 0 - bitValueInt (f 0) = + -(level - bitValueInt (f 0)) * + ((2 : ℤ) ^ (n / 2) - 1)) + (partialBentIntegerFourier f 0 - bitValueInt (f 0) = + ((2 : ℤ) ^ (n / 2) + level - bitValueInt (f 0)) * + ((2 : ℤ) ^ (n / 2) + 1)) := by + let q : ℤ := (2 : ℤ) ^ (n / 2) + let total : ℤ := (2 : ℤ) ^ n + let weight : ℤ := partialBentIntegerFourier f 0 + let origin : ℤ := bitValueInt (f 0) + have hqPositive : 0 < q := by + dsimp [q] + positivity + have hhalfPositive : 0 < n / 2 := by + rcases hnEven with ⟨m, hm⟩ + subst n + omega + have hqEven : Even q := by + refine ⟨(2 : ℤ) ^ (n / 2 - 1), ?_⟩ + dsimp [q] + have hindex : n / 2 = n / 2 - 1 + 1 := by omega + calc + (2 : ℤ) ^ (n / 2) = (2 : ℤ) ^ (n / 2 - 1 + 1) := + congrArg (fun k : ℕ ↦ (2 : ℤ) ^ k) hindex + _ = (2 : ℤ) ^ (n / 2 - 1) * 2 := by rw [pow_succ] + _ = (2 : ℤ) ^ (n / 2 - 1) + (2 : ℤ) ^ (n / 2 - 1) := by ring + have hsum := sum_partialBentIntegerFourier f + have hsquares := sum_partialBentIntegerFourier_sq f + change (∑ u, partialBentIntegerFourier f u) = total * origin at hsum + change (∑ u, (partialBentIntegerFourier f u) ^ 2) = total * weight at hsquares + have hquad (u : FABL.F₂Cube n) (hu : u ≠ 0) : + (partialBentIntegerFourier f u - level) * + (partialBentIntegerFourier f u - level - q) = 0 := by + rcases partialBentIntegerFourier_eq_level_or f level hlevels u hu with + hvalue | hvalue + · rw [hvalue] + ring + · change partialBentIntegerFourier f u = level + q at hvalue + rw [hvalue] + ring + have hsumQuad : + ∑ u ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + ((partialBentIntegerFourier f u - level) * + (partialBentIntegerFourier f u - level - q)) = 0 := by + apply Finset.sum_eq_zero + intro u hu + exact hquad u (Finset.mem_erase.mp hu).1 + have hsumErase : + ∑ u ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + partialBentIntegerFourier f u = total * origin - weight := by + have hsplit := Finset.sum_erase_add + (s := (Finset.univ : Finset (FABL.F₂Cube n))) + (f := fun u ↦ partialBentIntegerFourier f u) + (Finset.mem_univ (0 : FABL.F₂Cube n)) + rw [hsum] at hsplit + change + (∑ u ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + partialBentIntegerFourier f u) + weight = total * origin at hsplit + linear_combination hsplit + have hsquaresErase : + ∑ u ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + (partialBentIntegerFourier f u) ^ 2 = + total * weight - weight ^ 2 := by + have hsplit := Finset.sum_erase_add + (s := (Finset.univ : Finset (FABL.F₂Cube n))) + (f := fun u ↦ (partialBentIntegerFourier f u) ^ 2) + (Finset.mem_univ (0 : FABL.F₂Cube n)) + rw [hsquares] at hsplit + change + (∑ u ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + (partialBentIntegerFourier f u) ^ 2) + weight ^ 2 = + total * weight at hsplit + linear_combination hsplit + have hcardErase : + (Finset.univ.erase (0 : FABL.F₂Cube n)).card = (2 ^ n : ℕ) - 1 := by + rw [Finset.card_erase_of_mem (Finset.mem_univ _), Finset.card_univ, + card_f₂Cube] + have htotal : total = q * q := by + rcases hnEven with ⟨m, hm⟩ + subst n + have hhalf : (m + m) / 2 = m := by omega + dsimp [total, q] + rw [hhalf, ← pow_add] + have horiginSq : origin ^ 2 = origin := by + dsimp [origin] + by_cases hvalue : f 0 = 1 <;> + simp [bitValueInt, hvalue] + have hfactor : + (weight - origin + (level - origin) * (q - 1)) * + (weight - origin - (q + level - origin) * (q + 1)) = 0 := by + have hcardCast : + ((Finset.univ.erase (0 : FABL.F₂Cube n)).card : ℤ) = total - 1 := by + rw [hcardErase] + dsimp [total] + norm_num + have hexpand : + (∑ u ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + ((partialBentIntegerFourier f u - level) * + (partialBentIntegerFourier f u - level - q))) = + (∑ u ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + (partialBentIntegerFourier f u) ^ 2) - + (2 * level + q) * + (∑ u ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + partialBentIntegerFourier f u) + + ((Finset.univ.erase (0 : FABL.F₂Cube n)).card : ℤ) * + (level * (level + q)) := by + calc + (∑ u ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + ((partialBentIntegerFourier f u - level) * + (partialBentIntegerFourier f u - level - q))) = + ∑ u ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + ((partialBentIntegerFourier f u) ^ 2 - + (2 * level + q) * partialBentIntegerFourier f u + + level * (level + q)) := by + apply Finset.sum_congr rfl + intro u _hu + ring + _ = + (∑ u ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + (partialBentIntegerFourier f u) ^ 2) - + (2 * level + q) * + (∑ u ∈ (Finset.univ.erase (0 : FABL.F₂Cube n)), + partialBentIntegerFourier f u) + + ((Finset.univ.erase (0 : FABL.F₂Cube n)).card : ℤ) * + (level * (level + q)) := by + rw [Finset.sum_add_distrib, Finset.sum_sub_distrib, + Finset.mul_sum] + simp + rw [hexpand, hsquaresErase, hsumErase, hcardCast] at hsumQuad + rw [htotal] at hsumQuad + nlinarith [horiginSq] + change Xor + (weight - origin = -(level - origin) * (q - 1)) + (weight - origin = (q + level - origin) * (q + 1)) + rcases mul_eq_zero.mp hfactor with hfirst | hsecond + · refine Or.inl ⟨?_, ?_⟩ + · linarith + · intro hsecondEq + change weight - origin = + (q + level - origin) * (q + 1) at hsecondEq + have hrootEq : + -(level - origin) * (q - 1) = + (q + level - origin) * (q + 1) := by + linarith + obtain ⟨r, hr⟩ := hqEven + have hproduct : q * (q + 1 + 2 * (level - origin)) = 0 := by + calc + q * (q + 1 + 2 * (level - origin)) = + (q + level - origin) * (q + 1) - + (-(level - origin) * (q - 1)) := by ring + _ = 0 := by rw [hrootEq]; ring + have hlinear : q + 1 + 2 * (level - origin) = 0 := + (mul_eq_zero.mp hproduct).resolve_left (ne_of_gt hqPositive) + omega + · refine Or.inr ⟨?_, ?_⟩ + · linarith + · intro hfirstEq + change weight - origin = + -(level - origin) * (q - 1) at hfirstEq + have hrootEq : + -(level - origin) * (q - 1) = + (q + level - origin) * (q + 1) := by + linarith + obtain ⟨r, hr⟩ := hqEven + have hproduct : q * (q + 1 + 2 * (level - origin)) = 0 := by + calc + q * (q + 1 + 2 * (level - origin)) = + (q + level - origin) * (q + 1) - + (-(level - origin) * (q - 1)) := by ring + _ = 0 := by rw [hrootEq]; ring + have hlinear : q + 1 + 2 * (level - origin) = 0 := + (mul_eq_zero.mp hproduct).resolve_left (ne_of_gt hqPositive) + omega + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/PartialSpreads.lean b/CryptBoolean/Carlet/Chapter06/PartialSpreads.lean new file mode 100644 index 0000000..25d6293 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/PartialSpreads.lean @@ -0,0 +1,199 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.GeometricCharacterization + +/-! +# Partial-spread bent functions + +Carlet Section 6.4: sums of indicators of pairwise disjoint +half-dimensional subspaces. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- A finite family of half-dimensional subspaces whose distinct members +intersect only at the origin. -/ +def IsHalfDimensionalPartialSpread + (P : Finset (Submodule FABL.𝔽₂ (FABL.F₂Cube n))) : Prop := + (∀ E ∈ P, Module.finrank FABL.𝔽₂ E = n / 2) ∧ + ∀ E ∈ P, ∀ F ∈ P, E ≠ F → E ⊓ F = ⊥ + +/-- The two cardinalities used by Dillon's partial-spread classes. -/ +def HasPartialSpreadBentCardinality + (P : Finset (Submodule FABL.𝔽₂ (FABL.F₂Cube n))) : Prop := + P.card = 2 ^ (n / 2 - 1) ∨ P.card = 2 ^ (n / 2 - 1) + 1 + +/-- The Boolean sum of the indicators of the members of a partial spread. -/ +noncomputable def partialSpreadFunction + (P : Finset (Submodule FABL.𝔽₂ (FABL.F₂Cube n))) : + BooleanFunction n := by + classical + exact ∑ E ∈ P, fun x ↦ if x ∈ E then 1 else 0 + +/-- The coefficient family selecting the members of a partial spread. -/ +noncomputable def partialSpreadCoefficients + (P : Finset (Submodule FABL.𝔽₂ (FABL.F₂Cube n))) : + Submodule FABL.𝔽₂ (FABL.F₂Cube n) → ℤ := by + classical + exact fun E ↦ if E ∈ P then 1 else 0 + +private theorem halfSubspaceCombination_partialSpreadCoefficients + (P : Finset (Submodule FABL.𝔽₂ (FABL.F₂Cube n))) + (hP : IsHalfDimensionalPartialSpread P) + (x : FABL.F₂Cube n) : + halfSubspaceCombination (partialSpreadCoefficients P) x = + ∑ E ∈ P, linearSubspaceIndicatorInt E x := by + classical + unfold halfSubspaceCombination partialSpreadCoefficients + let H := binaryLinearSubspaces (n / 2) n + have hsubset : P ⊆ H := by + intro E hE + exact (mem_binaryLinearSubspaces E).mpr (hP.1 E hE) + calc + (∑ E ∈ H, (if E ∈ P then (1 : ℤ) else 0) * + linearSubspaceIndicatorInt E x) = + ∑ E ∈ H.filter fun E ↦ E ∈ P, + linearSubspaceIndicatorInt E x := by + simp [Finset.sum_filter] + _ = ∑ E ∈ P, linearSubspaceIndicatorInt E x := by + congr 1 + ext E + simp only [Finset.mem_filter] + constructor + · exact fun h ↦ h.2 + · exact fun h ↦ ⟨hsubset h, h⟩ + +private theorem unique_partialSpread_member_of_ne_zero + (P : Finset (Submodule FABL.𝔽₂ (FABL.F₂Cube n))) + (hP : IsHalfDimensionalPartialSpread P) + {x : FABL.F₂Cube n} (hx : x ≠ 0) + {E F : Submodule FABL.𝔽₂ (FABL.F₂Cube n)} + (hE : E ∈ P) (hxE : x ∈ E) (hF : F ∈ P) (hxF : x ∈ F) : + E = F := by + by_contra hne + have hintersection := hP.2 E hE F hF hne + have hxBot : x ∈ (⊥ : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) := by + rw [← hintersection] + exact ⟨hxE, hxF⟩ + exact hx (by simpa using hxBot) + +/-- Away from the origin, the Boolean indicator sum equals its ordinary +integer indicator sum. -/ +theorem bitValueInt_partialSpreadFunction_of_ne_zero + (P : Finset (Submodule FABL.𝔽₂ (FABL.F₂Cube n))) + (hP : IsHalfDimensionalPartialSpread P) + (x : FABL.F₂Cube n) (hx : x ≠ 0) : + bitValueInt (partialSpreadFunction P x) = + ∑ E ∈ P, linearSubspaceIndicatorInt E x := by + classical + by_cases hexists : ∃ E ∈ P, x ∈ E + · obtain ⟨E, hE, hxE⟩ := hexists + have hother (F : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hF : F ∈ P) (hFE : F ≠ E) : x ∉ F := by + intro hxF + exact hFE (unique_partialSpread_member_of_ne_zero + P hP hx hF hxF hE hxE) + have hboolean : partialSpreadFunction P x = 1 := by + unfold partialSpreadFunction + simp_rw [Finset.sum_apply] + rw [Finset.sum_eq_single E] + · simp [hxE] + · intro F hF hFE + simp [hother F hF hFE] + · exact fun h ↦ (h hE).elim + rw [hboolean] + simp only [bitValueInt] + norm_num + rw [Finset.sum_eq_single E] + · simp [linearSubspaceIndicatorInt, hxE] + · intro F hF hFE + simp [linearSubspaceIndicatorInt, hother F hF hFE] + · exact fun h ↦ (h hE).elim + · have hnone (E : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hE : E ∈ P) : x ∉ E := by + exact fun hxE ↦ hexists ⟨E, hE, hxE⟩ + have hboolean : partialSpreadFunction P x = 0 := by + unfold partialSpreadFunction + simp_rw [Finset.sum_apply] + apply Finset.sum_eq_zero + intro E hE + simp [hnone E hE] + have hsum : + (∑ E ∈ P, linearSubspaceIndicatorInt E x) = 0 := by + apply Finset.sum_eq_zero + intro E hE + simp [linearSubspaceIndicatorInt, hnone E hE] + rw [hboolean] + rw [hsum] + simp [bitValueInt] + +/-- At the origin, a partial-spread function records the parity of the +number of selected subspaces. -/ +theorem partialSpreadFunction_zero + (P : Finset (Submodule FABL.𝔽₂ (FABL.F₂Cube n))) : + partialSpreadFunction P 0 = (P.card : FABL.𝔽₂) := by + classical + unfold partialSpreadFunction + simp_rw [Finset.sum_apply] + simp + +/-- A partial spread of either Dillon cardinality gives the exact generalized +partial-spread expression. -/ +theorem hasExactGPSRepresentation_partialSpreadFunction + (P : Finset (Submodule FABL.𝔽₂ (FABL.F₂Cube n))) + (hP : IsHalfDimensionalPartialSpread P) + (hcard : HasPartialSpreadBentCardinality P) + (hhalf : 2 ≤ n / 2) : + HasExactGPSRepresentation (partialSpreadFunction P) + (partialSpreadCoefficients P) := by + intro x + rw [geometricBentExpression, + halfSubspaceCombination_partialSpreadCoefficients P hP x] + by_cases hx : x = 0 + · subst x + have hpowEven : Even (2 ^ (n / 2 - 1)) := + Even.pow_of_ne_zero (by norm_num : Even 2) (by omega) + rw [partialSpreadFunction_zero] + simp only [linearSubspaceIndicatorInt, Submodule.zero_mem, if_pos, + originIndicatorInt] + simp only [Finset.sum_const, nsmul_eq_mul, mul_one] + rcases hcard with hcard | hcard + · rw [hcard] + have hcastZero : ((2 ^ (n / 2 - 1) : ℕ) : FABL.𝔽₂) = 0 := by + exact ZMod.natCast_eq_zero_iff_even.mpr hpowEven + rw [hcastZero] + simp [bitValueInt] + · rw [hcard] + have hcastZero : ((2 ^ (n / 2 - 1) : ℕ) : FABL.𝔽₂) = 0 := by + exact ZMod.natCast_eq_zero_iff_even.mpr hpowEven + rw [Nat.cast_add, hcastZero] + simp [bitValueInt] + · rw [bitValueInt_partialSpreadFunction_of_ne_zero P hP x hx] + simp [originIndicatorInt, hx] + +/-- Dillon's partial-spread construction: selecting either +`2^(n/2-1)` or `2^(n/2-1)+1` pairwise disjoint half-dimensional subspaces +produces a bent function. -/ +theorem isBent_partialSpreadFunction + (P : Finset (Submodule FABL.𝔽₂ (FABL.F₂Cube n))) + (hP : IsHalfDimensionalPartialSpread P) + (hcard : HasPartialSpreadBentCardinality P) + (hnEven : Even n) (hhalf : 2 ≤ n / 2) : + IsBent (partialSpreadFunction P) := by + exact (isBent_and_bitValueInt_bentDual_of_exactGPSRepresentation + (partialSpreadFunction P) (partialSpreadCoefficients P) + hnEven (by omega) + (hasExactGPSRepresentation_partialSpreadFunction P hP hcard hhalf)).1 + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/PartiallyBent.lean b/CryptBoolean/Carlet/Chapter06/PartiallyBent.lean new file mode 100644 index 0000000..d7b1413 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/PartiallyBent.lean @@ -0,0 +1,838 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter04.LinearStructureNormalForm +public import CryptBoolean.Carlet.Chapter04.QuadraticPolar +public import CryptBoolean.Carlet.Chapter06.FourierUncertainty +public import CryptBoolean.Carlet.Chapter06.Plateaued + +/-! +# Partially bent functions + +Carlet Proposition 26: the support sizes of the autocorrelation and Walsh +spectra satisfy an uncertainty bound, with equality exactly for partially +bent functions. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +open FABL + +variable {n m k : ℕ} + +/-- The directions with nonzero autocorrelation. -/ +noncomputable def autocorrelationSupport (f : BooleanFunction n) : + Finset (FABL.F₂Cube n) := + pseudoBooleanSupport (autocorrelation f) + +@[simp] theorem mem_autocorrelationSupport + (f : BooleanFunction n) (b : FABL.F₂Cube n) : + b ∈ autocorrelationSupport f ↔ autocorrelation f b ≠ 0 := by + simp [autocorrelationSupport] + +/-- Carlet's quantity `N_Δf`, the number of nonzero autocorrelation +coefficients. -/ +noncomputable def nonzeroAutocorrelationCount (f : BooleanFunction n) : ℕ := + (autocorrelationSupport f).card + +/-- Wiener--Khintchine identifies the Fourier support of the autocorrelation +with the raw Walsh support. -/ +theorem rawFourierSupport_autocorrelation (f : BooleanFunction n) : + rawFourierSupport (autocorrelation f) = walshSupport f := by + classical + ext u + rw [mem_rawFourierSupport, mem_walshSupport, + rawFourierTransform_autocorrelation] + constructor + · intro hsquare hzero + rw [hzero, Int.cast_zero, zero_pow (by norm_num)] at hsquare + exact hsquare rfl + · intro hwalsh hsquare + have hcast : (walshTransform f u : ℝ) = 0 := sq_eq_zero_iff.mp hsquare + exact hwalsh (by exact_mod_cast hcast) + +private theorem autocorrelation_ne_zero (f : BooleanFunction n) : + autocorrelation f ≠ 0 := by + apply Function.ne_iff.mpr + refine ⟨0, ?_⟩ + rw [Pi.zero_apply, autocorrelation_zero] + positivity + +/-- Carlet Proposition 26, inequality (53). -/ +theorem two_pow_le_nonzeroAutocorrelationCount_mul_card_walshSupport + (f : BooleanFunction n) : + 2 ^ n ≤ nonzeroAutocorrelationCount f * (walshSupport f).card := by + simpa only [nonzeroAutocorrelationCount, autocorrelationSupport, + rawFourierSupport_autocorrelation] using + two_pow_le_card_pseudoBooleanSupport_mul_card_rawFourierSupport + (autocorrelation f) (autocorrelation_ne_zero f) + +/-- A Boolean function is partially bent when every directional derivative +is balanced or constant. -/ +def IsPartiallyBent (f : BooleanFunction n) : Prop := + ∀ b : FABL.F₂Cube n, + IsBalanced (FABL.booleanDerivative f b) ∨ IsLinearStructure f b + +/-- Every quadratic Boolean function is partially bent. -/ +theorem isPartiallyBent_of_functionAlgebraicDegree_le_two + (f : BooleanFunction n) + (hdegree : FABL.functionAlgebraicDegree f ≤ 2) : + IsPartiallyBent f := by + intro a + by_cases ha : a ∈ quadraticRadical f hdegree + · right + rw [← mem_linearKernel, + ← quadraticRadical_eq_linearKernel f hdegree] + exact ha + · left + exact isBalanced_booleanDerivative_of_not_mem_quadraticRadical + f hdegree a ha + +/-- A coordinate-free form of Carlet's complementary-subspace +decomposition. The second summand is affine with its constant absorbed into +the bent summand. -/ +def HasBentAffineComplementDecomposition + (f : BooleanFunction n) (m k : ℕ) : Prop := + ∃ (E E' : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (_hcomplement : IsCompl E E') + (eE : FABL.F₂Cube m ≃ₗ[FABL.𝔽₂] E) + (eE' : FABL.F₂Cube k ≃ₗ[FABL.𝔽₂] E') + (g : BooleanFunction m) (ε : FABL.F₂Cube k), + IsBent g ∧ + ∀ (x : FABL.F₂Cube m) (y : FABL.F₂Cube k), + f (eE x + eE' y) = g x + FABL.f₂DotProduct ε y + +private noncomputable def complementCoordinateEquiv + (E E' : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hcomplement : IsCompl E E') + (eE : FABL.F₂Cube m ≃ₗ[FABL.𝔽₂] E) + (eE' : FABL.F₂Cube k ≃ₗ[FABL.𝔽₂] E') : + (FABL.F₂Cube m × FABL.F₂Cube k) ≃ₗ[FABL.𝔽₂] + FABL.F₂Cube n := + (LinearEquiv.prodCongr eE eE').trans + (E.prodEquivOfIsCompl E' hcomplement) + +@[simp] private theorem complementCoordinateEquiv_apply + (E E' : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hcomplement : IsCompl E E') + (eE : FABL.F₂Cube m ≃ₗ[FABL.𝔽₂] E) + (eE' : FABL.F₂Cube k ≃ₗ[FABL.𝔽₂] E') + (x : FABL.F₂Cube m) (y : FABL.F₂Cube k) : + complementCoordinateEquiv E E' hcomplement eE eE' (x, y) = + eE x + eE' y := + rfl + +private theorem booleanDerivative_complementRepresentation + (f : BooleanFunction n) + (E E' : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (eE : FABL.F₂Cube m ≃ₗ[FABL.𝔽₂] E) + (eE' : FABL.F₂Cube k ≃ₗ[FABL.𝔽₂] E') + (g : BooleanFunction m) (ε : FABL.F₂Cube k) + (hrepresentation : + ∀ (x : FABL.F₂Cube m) (y : FABL.F₂Cube k), + f (eE x + eE' y) = g x + FABL.f₂DotProduct ε y) + (d : FABL.F₂Cube m) (z : FABL.F₂Cube k) + (x : FABL.F₂Cube m) (y : FABL.F₂Cube k) : + FABL.booleanDerivative f (eE d + eE' z) (eE x + eE' y) = + FABL.booleanDerivative g d x + FABL.f₂DotProduct ε z := by + rw [FABL.booleanDerivative, FABL.booleanDerivative, + hrepresentation x y] + have hargument : + (eE x : FABL.F₂Cube n) + (eE' y : FABL.F₂Cube n) + + ((eE d : FABL.F₂Cube n) + (eE' z : FABL.F₂Cube n)) = + (eE (x + d) : FABL.F₂Cube n) + + (eE' (y + z) : FABL.F₂Cube n) := by + simp only [map_add, Submodule.coe_add] + abel + rw [hargument, hrepresentation (x + d) (y + z)] + simp only [FABL.f₂DotProduct, dotProduct_add] + change + (g x + ε ⬝ᵥ y) + (g (x + d) + (ε ⬝ᵥ y + ε ⬝ᵥ z)) = + (g x + g (x + d)) + ε ⬝ᵥ z + calc + (g x + ε ⬝ᵥ y) + (g (x + d) + (ε ⬝ᵥ y + ε ⬝ᵥ z)) = + (g x + g (x + d)) + ((ε ⬝ᵥ y + ε ⬝ᵥ y) + ε ⬝ᵥ z) := by + abel + _ = (g x + g (x + d)) + ε ⬝ᵥ z := by + rw [ZModModule.add_self, zero_add] + +private theorem autocorrelation_complementRepresentation + (f : BooleanFunction n) + (E E' : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (hcomplement : IsCompl E E') + (eE : FABL.F₂Cube m ≃ₗ[FABL.𝔽₂] E) + (eE' : FABL.F₂Cube k ≃ₗ[FABL.𝔽₂] E') + (g : BooleanFunction m) (ε : FABL.F₂Cube k) + (hrepresentation : + ∀ (x : FABL.F₂Cube m) (y : FABL.F₂Cube k), + f (eE x + eE' y) = g x + FABL.f₂DotProduct ε y) + (d : FABL.F₂Cube m) (z : FABL.F₂Cube k) : + autocorrelation f (eE d + eE' z) = + (2 : ℝ) ^ k * FABL.vectorWalshCharacter ε z * + autocorrelation g d := by + classical + let L := complementCoordinateEquiv E E' hcomplement eE eE' + have hsign (x : FABL.F₂Cube m) (y : FABL.F₂Cube k) : + realSignView (FABL.booleanDerivative f (eE d + eE' z)) + (eE x + eE' y) = + realSignView (FABL.booleanDerivative g d) x * + FABL.vectorWalshCharacter ε z := by + change FABL.signValue (FABL.signEncode + (FABL.booleanDerivative f (eE d + eE' z) (eE x + eE' y))) = + FABL.signValue (FABL.signEncode (FABL.booleanDerivative g d x)) * + FABL.vectorWalshCharacter ε z + rw [booleanDerivative_complementRepresentation + f E E' eE eE' g ε hrepresentation d z x y] + rw [FABL.signValue_signEncode_eq_binarySign, + FABL.signValue_signEncode_eq_binarySign, + AddChar.map_add_eq_mul, FABL.vectorWalshCharacter_apply] + rw [autocorrelation] + calc + (∑ p, realSignView (FABL.booleanDerivative f (eE d + eE' z)) p) = + ∑ q : FABL.F₂Cube m × FABL.F₂Cube k, + realSignView (FABL.booleanDerivative f (eE d + eE' z)) (L q) := by + symm + exact Fintype.sum_equiv L.toEquiv + (fun q ↦ realSignView + (FABL.booleanDerivative f (eE d + eE' z)) (L q)) + (fun p ↦ realSignView + (FABL.booleanDerivative f (eE d + eE' z)) p) + (fun _ ↦ rfl) + _ = ∑ x : FABL.F₂Cube m, ∑ y : FABL.F₂Cube k, + realSignView (FABL.booleanDerivative f (eE d + eE' z)) + (eE x + eE' y) := by + rw [Fintype.sum_prod_type] + rfl + _ = ∑ x : FABL.F₂Cube m, ∑ _y : FABL.F₂Cube k, + realSignView (FABL.booleanDerivative g d) x * + FABL.vectorWalshCharacter ε z := by + apply Finset.sum_congr rfl + intro x _hx + apply Finset.sum_congr rfl + intro y _hy + exact hsign x y + _ = ∑ x : FABL.F₂Cube m, + (2 : ℝ) ^ k * + (realSignView (FABL.booleanDerivative g d) x * + FABL.vectorWalshCharacter ε z) := by + apply Finset.sum_congr rfl + intro x _hx + rw [Finset.sum_const, Finset.card_univ, card_f₂Cube, + nsmul_eq_mul] + norm_num + _ = ∑ x : FABL.F₂Cube m, + ((2 : ℝ) ^ k * FABL.vectorWalshCharacter ε z) * + realSignView (FABL.booleanDerivative g d) x := by + apply Finset.sum_congr rfl + intro x _hx + ring + _ = (2 : ℝ) ^ k * FABL.vectorWalshCharacter ε z * + ∑ x, realSignView (FABL.booleanDerivative g d) x := by + rw [Finset.mul_sum] + _ = (2 : ℝ) ^ k * FABL.vectorWalshCharacter ε z * + autocorrelation g d := rfl + +/-- Every bent-plus-affine complementary decomposition is partially bent. -/ +theorem HasBentAffineComplementDecomposition.isPartiallyBent + {f : BooleanFunction n} {m k : ℕ} + (hf : HasBentAffineComplementDecomposition f m k) : + IsPartiallyBent f := by + classical + rcases hf with + ⟨E, E', hcomplement, eE, eE', g, ε, hg, hrepresentation⟩ + let L := complementCoordinateEquiv E E' hcomplement eE eE' + intro b + let q := L.symm b + have hb : b = eE q.1 + eE' q.2 := by + calc + b = L q := (L.apply_symm_apply b).symm + _ = eE q.1 + eE' q.2 := rfl + by_cases hd : q.1 = 0 + · right + refine ⟨FABL.f₂DotProduct ε q.2, fun p ↦ ?_⟩ + let r := L.symm p + have hp : p = eE r.1 + eE' r.2 := by + calc + p = L r := (L.apply_symm_apply p).symm + _ = eE r.1 + eE' r.2 := rfl + rw [hp, hb] + have hderivative := booleanDerivative_complementRepresentation + f E E' eE eE' g ε hrepresentation q.1 q.2 r.1 r.2 + rw [hd] at hderivative + simp only [FABL.booleanDerivative, add_zero] at hderivative + rw [ZModModule.add_self, zero_add] at hderivative + simpa [hd, FABL.booleanDerivative] using hderivative + · left + apply (isBalanced_booleanDerivative_iff_autocorrelation_eq_zero f b).mpr + rw [hb, autocorrelation_complementRepresentation + f E E' hcomplement eE eE' g ε hrepresentation q.1 q.2] + have hbalanced := + (isBent_iff_forall_nonzero_derivative_isBalanced g).mp hg q.1 hd + rw [(isBalanced_booleanDerivative_iff_autocorrelation_eq_zero + g q.1).mp hbalanced, mul_zero] + +/-- In a bent-plus-affine complementary decomposition, the affine summand is +exactly the linear kernel. -/ +theorem HasBentAffineComplementDecomposition.linearKernel_eq_affineSubspace + {f : BooleanFunction n} {m k : ℕ} + (hf : HasBentAffineComplementDecomposition f m k) : + ∃ (E E' : Submodule FABL.𝔽₂ (FABL.F₂Cube n)) + (_hcomplement : IsCompl E E') + (eE : FABL.F₂Cube m ≃ₗ[FABL.𝔽₂] E) + (eE' : FABL.F₂Cube k ≃ₗ[FABL.𝔽₂] E') + (g : BooleanFunction m) (ε : FABL.F₂Cube k), + IsBent g ∧ linearKernel f = E' ∧ + ∀ (x : FABL.F₂Cube m) (y : FABL.F₂Cube k), + f (eE x + eE' y) = g x + FABL.f₂DotProduct ε y := by + classical + rcases hf with + ⟨E, E', hcomplement, eE, eE', g, ε, hg, hrepresentation⟩ + let L := complementCoordinateEquiv E E' hcomplement eE eE' + have hkernel : linearKernel f = E' := by + apply le_antisymm + · intro b hb + let q := L.symm b + have hbCoordinates : b = eE q.1 + eE' q.2 := by + calc + b = L q := (L.apply_symm_apply b).symm + _ = eE q.1 + eE' q.2 := rfl + have hqzero : q.1 = 0 := by + by_contra hq + have hbalanced := + (isBent_iff_forall_nonzero_derivative_isBalanced g).mp hg q.1 hq + have hzeroG := + (isBalanced_booleanDerivative_iff_autocorrelation_eq_zero + g q.1).mp hbalanced + have hfactor := autocorrelation_complementRepresentation + f E E' hcomplement eE eE' g ε hrepresentation q.1 q.2 + rw [hzeroG, mul_zero] at hfactor + have hzeroF : autocorrelation f b = 0 := by + rw [hbCoordinates] + exact hfactor + have hsquare := autocorrelation_sq_of_mem_linearKernel f b hb + rw [hzeroF, zero_pow (by norm_num)] at hsquare + exact (by positivity : (0 : ℝ) ≠ (2 : ℝ) ^ (2 * n)) hsquare + rw [hbCoordinates, hqzero] + simp + · intro b hb + obtain ⟨z, hz⟩ := eE'.surjective ⟨b, hb⟩ + have hzValue := congrArg Subtype.val hz + have hzValue' : (eE' z : FABL.F₂Cube n) = b := by + simpa using hzValue + rw [← hzValue'] + refine ⟨FABL.f₂DotProduct ε z, fun p ↦ ?_⟩ + let q := L.symm p + have hp : p = eE q.1 + eE' q.2 := by + calc + p = L q := (L.apply_symm_apply p).symm + _ = eE q.1 + eE' q.2 := rfl + rw [hp] + have hderivative := booleanDerivative_complementRepresentation + f E E' eE eE' g ε hrepresentation 0 z q.1 q.2 + simp only [map_zero, Submodule.coe_zero, zero_add, + FABL.booleanDerivative, add_zero] at hderivative + rw [ZModModule.add_self, zero_add] at hderivative + exact hderivative + exact ⟨E, E', hcomplement, eE, eE', g, ε, hg, + hkernel, hrepresentation⟩ + +/-- Complementary coordinate dimensions add to the ambient dimension. -/ +theorem HasBentAffineComplementDecomposition.dimensions_add + {f : BooleanFunction n} {m k : ℕ} + (hf : HasBentAffineComplementDecomposition f m k) : + m + k = n := by + rcases hf with + ⟨E, E', hcomplement, eE, eE', g, ε, hg, hrepresentation⟩ + let L := complementCoordinateEquiv E E' hcomplement eE eE' + simpa [L, Module.finrank_prod, + Module.finrank_fintype_fun_eq_card] using L.finrank_eq + +/-- The bent summand has even dimension. -/ +theorem HasBentAffineComplementDecomposition.even_bentDimension + {f : BooleanFunction n} {m k : ℕ} + (hf : HasBentAffineComplementDecomposition f m k) : Even m := by + rcases hf with + ⟨E, E', hcomplement, eE, eE', g, ε, hg, hrepresentation⟩ + exact even_of_isBent g hg + +/-- Every partially bent function decomposes over complementary subspaces as +a bent function plus an affine function. -/ +theorem exists_hasBentAffineComplementDecomposition_of_isPartiallyBent + (f : BooleanFunction n) (hf : IsPartiallyBent f) : + ∃ m k : ℕ, HasBentAffineComplementDecomposition f m k := by + classical + let H := linearKernel f + obtain ⟨E, hHE⟩ := H.exists_isCompl + have hcomplement : IsCompl E H := hHE.symm + let m := Module.finrank FABL.𝔽₂ E + let k := Module.finrank FABL.𝔽₂ H + let eE : FABL.F₂Cube m ≃ₗ[FABL.𝔽₂] E := + LinearEquiv.ofFinrankEq _ _ (by + simp [m, Module.finrank_fintype_fun_eq_card]) + let eH : FABL.F₂Cube k ≃ₗ[FABL.𝔽₂] H := + LinearEquiv.ofFinrankEq _ _ (by + simp [k, Module.finrank_fintype_fun_eq_card]) + let g : BooleanFunction m := fun x ↦ f (eE x) + let q : FABL.F₂Cube k → FABL.𝔽₂ := + fun y ↦ f (eH y) + f 0 + have hq : FABL.IsF₂Linear q := by + intro y z + obtain ⟨δ, hδ⟩ := + (mem_linearKernel f (eH z)).mp (eH z).property + have hderivative := (hδ (eH y)).trans (hδ 0).symm + rw [FABL.booleanDerivative, FABL.booleanDerivative] at hderivative + simp only [zero_add] at hderivative + change f (eH (y + z)) + f 0 = + (f (eH y) + f 0) + (f (eH z) + f 0) + rw [map_add] + calc + f (eH y + eH z) + f 0 = + (f (eH y) + f (eH y)) + (f (eH y + eH z) + f 0) := by + rw [ZModModule.add_self, zero_add] + _ = f (eH y) + (f (eH y) + f (eH y + eH z)) + f 0 := by + abel + _ = f (eH y) + (f 0 + f (eH z)) + f 0 := by + rw [hderivative] + _ = (f (eH y) + f 0) + (f (eH z) + f 0) := by + abel + obtain ⟨ε, hε⟩ := (FABL.isF₂Linear_iff_exists_dotProduct q).mp hq + have hrepresentation + (x : FABL.F₂Cube m) (y : FABL.F₂Cube k) : + f (eE x + eH y) = g x + FABL.f₂DotProduct ε y := by + obtain ⟨δ, hδ⟩ := + (mem_linearKernel f (eH y)).mp (eH y).property + have hderivative := (hδ (eE x)).trans (hδ 0).symm + rw [FABL.booleanDerivative, FABL.booleanDerivative] at hderivative + simp only [zero_add] at hderivative + change f (eE x + eH y) = f (eE x) + FABL.f₂DotProduct ε y + rw [← hε y] + change f (eE x + eH y) = f (eE x) + (f (eH y) + f 0) + calc + f (eE x + eH y) = + (f (eE x) + f (eE x)) + f (eE x + eH y) := by + rw [ZModModule.add_self, zero_add] + _ = f (eE x) + (f (eE x) + f (eE x + eH y)) := by + abel + _ = f (eE x) + (f 0 + f (eH y)) := by + rw [hderivative] + _ = f (eE x) + (f (eH y) + f 0) := by + abel + have hg : IsBent g := by + apply (isBent_iff_forall_nonzero_derivative_isBalanced g).mpr + intro d hd + have hdirectionNe : (eE d : FABL.F₂Cube n) ≠ 0 := by + intro hzero + apply hd + apply eE.injective + exact Subtype.ext (by simpa using hzero) + have hdirectionNotKernel : (eE d : FABL.F₂Cube n) ∉ H := by + intro hkernel + have hintersection : (eE d : FABL.F₂Cube n) ∈ E ⊓ H := + ⟨(eE d).property, hkernel⟩ + have hbot : (eE d : FABL.F₂Cube n) ∈ (⊥ : + Submodule FABL.𝔽₂ (FABL.F₂Cube n)) := by + rw [← hcomplement.inf_eq_bot] + exact hintersection + exact hdirectionNe (by simpa using hbot) + rcases hf (eE d) with hbalanced | hlinear + · apply (isBalanced_booleanDerivative_iff_autocorrelation_eq_zero g d).mpr + have hzero := + (isBalanced_booleanDerivative_iff_autocorrelation_eq_zero + f (eE d)).mp hbalanced + have hfactor := autocorrelation_complementRepresentation + f E H hcomplement eE eH g ε hrepresentation d 0 + simp only [map_zero, Submodule.coe_zero, add_zero] at hfactor + rw [AddChar.map_zero_eq_one, mul_one] at hfactor + rw [hzero] at hfactor + have hpower : (0 : ℝ) < (2 : ℝ) ^ k := by positivity + nlinarith + · exact (hdirectionNotKernel hlinear).elim + exact ⟨m, k, E, H, hcomplement, eE, eH, g, ε, hg, hrepresentation⟩ + +/-- Carlet Proposition 26's structural characterization. -/ +theorem isPartiallyBent_iff_exists_bentAffineComplementDecomposition + (f : BooleanFunction n) : + IsPartiallyBent f ↔ + ∃ m k : ℕ, HasBentAffineComplementDecomposition f m k := by + constructor + · exact exists_hasBentAffineComplementDecomposition_of_isPartiallyBent f + · rintro ⟨m, k, h⟩ + exact h.isPartiallyBent + +private theorem booleanFunction_eq_one_of_hammingWeight_eq_two_pow + (g : BooleanFunction n) (hweight : hammingWeight g = 2 ^ n) : + g = 1 := by + have hsupportCard : (support g).card = Fintype.card (FABL.F₂Cube n) := by + simpa only [hammingWeight_eq_card_support, card_f₂Cube] using hweight + have hsupport : support g = Finset.univ := + Finset.eq_univ_of_card (s := support g) hsupportCard + funext x + have hx : x ∈ support g := by rw [hsupport]; exact Finset.mem_univ x + exact (mem_support g x).mp hx + +/-- A direction is a linear structure exactly when its autocorrelation has +maximal absolute value. -/ +theorem isLinearStructure_iff_abs_autocorrelation_eq_two_pow + (f : BooleanFunction n) (b : FABL.F₂Cube n) : + IsLinearStructure f b ↔ |autocorrelation f b| = (2 : ℝ) ^ n := by + constructor + · intro hlinear + have hsquare := autocorrelation_sq_of_mem_linearKernel f b hlinear + have hsquare' : + autocorrelation f b ^ 2 = ((2 : ℝ) ^ n) ^ 2 := by + calc + autocorrelation f b ^ 2 = (2 : ℝ) ^ (2 * n) := hsquare + _ = ((2 : ℝ) ^ n) ^ 2 := by rw [two_mul, pow_add, pow_two] + rw [← sq_abs] at hsquare' + rcases sq_eq_sq_iff_eq_or_eq_neg.mp hsquare' with heq | heq + · exact heq + · nlinarith [abs_nonneg (autocorrelation f b), + show 0 < (2 : ℝ) ^ n by positivity] + · intro habs + rcases eq_or_eq_neg_of_abs_eq habs with hpositive | hnegative + · have hformula := autocorrelation_eq_two_pow_sub_two_derivative_weight f b + have hweightReal : + (hammingWeight (FABL.booleanDerivative f b) : ℝ) = 0 := by + rw [hpositive] at hformula + nlinarith + have hweight : hammingWeight (FABL.booleanDerivative f b) = 0 := by + exact_mod_cast hweightReal + have hzero : FABL.booleanDerivative f b = 0 := + hammingNorm_eq_zero.mp hweight + exact ⟨0, fun x ↦ congrFun hzero x⟩ + · have hformula := autocorrelation_eq_two_pow_sub_two_derivative_weight f b + have hweightReal : + (hammingWeight (FABL.booleanDerivative f b) : ℝ) = + (2 : ℝ) ^ n := by + rw [hnegative] at hformula + nlinarith + have hweight : + hammingWeight (FABL.booleanDerivative f b) = 2 ^ n := by + exact_mod_cast hweightReal + have hone : FABL.booleanDerivative f b = 1 := + booleanFunction_eq_one_of_hammingWeight_eq_two_pow _ hweight + exact ⟨1, fun x ↦ congrFun hone x⟩ + +/-- Equality in Carlet's support inequality forces every derivative to be +balanced or constant. -/ +theorem isPartiallyBent_of_nonzeroAutocorrelationCount_mul_card_walshSupport_eq + (f : BooleanFunction n) + (hproduct : + nonzeroAutocorrelationCount f * (walshSupport f).card = 2 ^ n) : + IsPartiallyBent f := by + classical + have hproduct' : + (pseudoBooleanSupport (autocorrelation f)).card * + (rawFourierSupport (autocorrelation f)).card = 2 ^ n := by + simpa only [nonzeroAutocorrelationCount, autocorrelationSupport, + rawFourierSupport_autocorrelation] using hproduct + obtain ⟨c, hc, H, a, u, hrepresentation⟩ := + isModulatedAffineFlatIndicator_of_card_support_mul_card_rawFourierSupport_eq + (autocorrelation f) (autocorrelation_ne_zero f) hproduct' + have hzeroFlat : + 0 ∈ FABL.binaryAffineSubspace H a := by + by_contra hnot + have hzero := congrFun hrepresentation 0 + rw [autocorrelation_zero] at hzero + simp [FABL.setIndicator, hnot] at hzero + have hcValue : c = (2 : ℝ) ^ n := by + have hzero := congrFun hrepresentation 0 + rw [autocorrelation_zero] at hzero + simpa [FABL.setIndicator, hzeroFlat] using hzero.symm + intro b + by_cases hzero : autocorrelation f b = 0 + · exact Or.inl + ((isBalanced_booleanDerivative_iff_autocorrelation_eq_zero f b).mpr hzero) + · right + apply (isLinearStructure_iff_abs_autocorrelation_eq_two_pow f b).mpr + have hbFlat : b ∈ FABL.binaryAffineSubspace H a := by + by_contra hnot + have hb := congrFun hrepresentation b + have hindicator : FABL.setIndicator + (FABL.binaryAffineSubspace H a : Set (FABL.F₂Cube n)) b = 0 := by + exact Set.indicator_of_notMem hnot _ + rw [hindicator, mul_zero] at hb + exact hzero hb + rw [congrFun hrepresentation b, hcValue] + simp [FABL.setIndicator, hbFlat, abs_mul] + +private theorem card_autocorrelationSupport_eq_natCard_linearKernel_of_isPartiallyBent + (f : BooleanFunction n) (hf : IsPartiallyBent f) : + (autocorrelationSupport f).card = Nat.card (linearKernel f) := by + classical + let kernelDirections := + Finset.univ.filter (fun b : FABL.F₂Cube n ↦ b ∈ linearKernel f) + have hsupport : autocorrelationSupport f = kernelDirections := by + ext b + simp only [mem_autocorrelationSupport, kernelDirections, + Finset.mem_filter, Finset.mem_univ, true_and] + constructor + · intro hnonzero + rcases hf b with hbalanced | hlinear + · exact (hnonzero + ((isBalanced_booleanDerivative_iff_autocorrelation_eq_zero + f b).mp hbalanced)).elim + · exact hlinear + · intro hlinear hzero + have habs := + (isLinearStructure_iff_abs_autocorrelation_eq_two_pow f b).mp hlinear + rw [hzero, abs_zero] at habs + exact (by positivity : (0 : ℝ) ≠ (2 : ℝ) ^ n) habs + rw [hsupport] + simp [kernelDirections, Fintype.card_subtype, + Nat.card_eq_fintype_card] + +private theorem card_walshSupport_le_natCard_perpendicular_linearKernel + (f : BooleanFunction n) : + (walshSupport f).card ≤ + Nat.card (FABL.perpendicularSubspace (linearKernel f)) := by + classical + have hlower := + two_pow_le_nonzeroAutocorrelationCount_mul_card_walshSupport f + have hwalshPositive : 0 < (walshSupport f).card := by + by_contra hnot + have hzero : (walshSupport f).card = 0 := Nat.eq_zero_of_not_pos hnot + rw [hzero, mul_zero] at hlower + have hpow : 0 < 2 ^ n := by positivity + omega + obtain ⟨u, hu⟩ := Finset.card_pos.mp hwalshPositive + have hshiftMem (v : walshSupport f) : + u + v.1 ∈ FABL.perpendicularSubspace (linearKernel f) := by + rw [FABL.mem_perpendicularSubspace_iff] + intro b hb + by_cases hbzero : b = 0 + · subst b + simp [FABL.f₂DotProduct] + obtain ⟨ε, hε⟩ := (mem_linearKernel f b).mp hb + by_cases hεzero : ε = 0 + · have hderivative : FABL.booleanDerivative f b = 0 := by + funext x + simpa [hεzero] using hε x + have hsubset := + (booleanDerivative_eq_zero_iff_walshSupport_subset_hyperplane + f b hbzero).mp hderivative + have hdotU : FABL.f₂DotProduct u b = 0 := + (mem_walshHyperplane_iff b u).mp (hsubset hu) + have hdotV : FABL.f₂DotProduct v.1 b = 0 := + (mem_walshHyperplane_iff b v.1).mp (hsubset v.2) + rw [FABL.f₂DotProduct, add_dotProduct] + change FABL.f₂DotProduct u b + FABL.f₂DotProduct v.1 b = 0 + rw [hdotU, hdotV, add_zero] + · have hεone : ε = 1 := Fin.eq_one_of_ne_zero ε hεzero + have hderivative : FABL.booleanDerivative f b = 1 := by + funext x + simpa [hεone] using hε x + have hsubset := + (booleanDerivative_eq_one_iff_walshSupport_subset_hyperplane_compl + f b hbzero).mp hderivative + have hdotU : FABL.f₂DotProduct u b = 1 := by + apply Fin.eq_one_of_ne_zero + intro hzero + exact (hsubset hu) ((mem_walshHyperplane_iff b u).mpr hzero) + have hdotV : FABL.f₂DotProduct v.1 b = 1 := by + apply Fin.eq_one_of_ne_zero + intro hzero + exact (hsubset v.2) ((mem_walshHyperplane_iff b v.1).mpr hzero) + rw [FABL.f₂DotProduct, add_dotProduct] + change FABL.f₂DotProduct u b + FABL.f₂DotProduct v.1 b = 0 + rw [hdotU, hdotV, ZModModule.add_self] + let toPerpendicular : walshSupport f → + FABL.perpendicularSubspace (linearKernel f) := + fun v ↦ ⟨u + v.1, hshiftMem v⟩ + have hinjective : Function.Injective toPerpendicular := by + intro v w hvw + apply Subtype.ext + exact add_left_cancel (congrArg Subtype.val hvw) + letI : Fintype (FABL.perpendicularSubspace (linearKernel f)) := + Fintype.ofFinite _ + have hcard : Fintype.card (walshSupport f) ≤ + Fintype.card (FABL.perpendicularSubspace (linearKernel f)) := + Fintype.card_le_of_injective toPerpendicular hinjective + simpa only [Fintype.card_coe, Nat.card_eq_fintype_card] using hcard + +/-- If every derivative is balanced or constant, equality holds in Carlet's +support inequality. -/ +theorem nonzeroAutocorrelationCount_mul_card_walshSupport_eq_of_isPartiallyBent + (f : BooleanFunction n) (hf : IsPartiallyBent f) : + nonzeroAutocorrelationCount f * (walshSupport f).card = 2 ^ n := by + have hcount := + card_autocorrelationSupport_eq_natCard_linearKernel_of_isPartiallyBent f hf + have hwalsh := + card_walshSupport_le_natCard_perpendicular_linearKernel f + have hlower := + two_pow_le_nonzeroAutocorrelationCount_mul_card_walshSupport f + have hupper : + nonzeroAutocorrelationCount f * (walshSupport f).card ≤ 2 ^ n := by + rw [nonzeroAutocorrelationCount, hcount] + calc + Nat.card (linearKernel f) * (walshSupport f).card ≤ + Nat.card (linearKernel f) * + Nat.card (FABL.perpendicularSubspace (linearKernel f)) := + Nat.mul_le_mul_left _ hwalsh + _ = 2 ^ n := by + have hrank : Module.finrank FABL.𝔽₂ (linearKernel f) ≤ n := by + simpa using (linearKernel f).finrank_le + rw [FABL.card_submodule_eq_two_pow_finrank, + FABL.card_submodule_eq_two_pow_finrank, + FABL.finrank_perpendicularSubspace, ← pow_add, + Nat.add_sub_of_le hrank] + omega + +/-- Carlet Proposition 26: equality in (53) is equivalent to partial +bentness. -/ +theorem nonzeroAutocorrelationCount_mul_card_walshSupport_eq_two_pow_iff + (f : BooleanFunction n) : + nonzeroAutocorrelationCount f * (walshSupport f).card = 2 ^ n ↔ + IsPartiallyBent f := by + constructor + · exact + isPartiallyBent_of_nonzeroAutocorrelationCount_mul_card_walshSupport_eq f + · exact + nonzeroAutocorrelationCount_mul_card_walshSupport_eq_of_isPartiallyBent f + +/-- The autocorrelation support has the cardinality of the affine summand. -/ +theorem HasBentAffineComplementDecomposition.nonzeroAutocorrelationCount_eq + {f : BooleanFunction n} {m k : ℕ} + (hf : HasBentAffineComplementDecomposition f m k) : + nonzeroAutocorrelationCount f = 2 ^ k := by + classical + rcases hf.linearKernel_eq_affineSubspace with + ⟨E, E', hcomplement, eE, eE', g, ε, hg, hkernel, hrepresentation⟩ + letI : Fintype E' := Fintype.ofFinite E' + have hcount := + card_autocorrelationSupport_eq_natCard_linearKernel_of_isPartiallyBent + f hf.isPartiallyBent + rw [nonzeroAutocorrelationCount, hcount, hkernel] + calc + Nat.card E' = Fintype.card E' := Nat.card_eq_fintype_card + _ = Fintype.card (FABL.F₂Cube k) := + (Fintype.card_congr eE'.toEquiv).symm + _ = 2 ^ k := card_f₂Cube k + +/-- Every partially bent function has a flat nonzero Walsh spectrum. -/ +theorem hasPlateauedWalshSpectrum_of_isPartiallyBent + (f : BooleanFunction n) (hf : IsPartiallyBent f) : + HasPlateauedWalshSpectrum f := by + classical + have hindicator : + sumOfSquaresIndicator f = + (nonzeroAutocorrelationCount f : ℝ) * ((2 : ℝ) ^ n) ^ 2 := by + rw [sumOfSquaresIndicator] + calc + (∑ b, autocorrelation f b ^ 2) = + ∑ b ∈ autocorrelationSupport f, autocorrelation f b ^ 2 := by + symm + apply Finset.sum_subset (Finset.subset_univ _) + intro b _hb hnot + have hzero : autocorrelation f b = 0 := by + exact not_ne_iff.mp + (by simpa only [mem_autocorrelationSupport] using hnot) + simp [hzero] + _ = ∑ _b ∈ autocorrelationSupport f, ((2 : ℝ) ^ n) ^ 2 := by + apply Finset.sum_congr rfl + intro b hb + have hnonzero : autocorrelation f b ≠ 0 := + (mem_autocorrelationSupport f b).mp hb + have hlinear : IsLinearStructure f b := by + rcases hf b with hbalanced | hlinear + · exact (hnonzero + ((isBalanced_booleanDerivative_iff_autocorrelation_eq_zero + f b).mp hbalanced)).elim + · exact hlinear + have habs := + (isLinearStructure_iff_abs_autocorrelation_eq_two_pow f b).mp hlinear + rw [← sq_abs, habs] + _ = (nonzeroAutocorrelationCount f : ℝ) * + ((2 : ℝ) ^ n) ^ 2 := by + simp [nonzeroAutocorrelationCount] + have hcountNat := + nonzeroAutocorrelationCount_mul_card_walshSupport_eq_of_isPartiallyBent + f hf + have hcountReal : + (nonzeroAutocorrelationCount f : ℝ) * + ((walshSupport f).card : ℝ) = (2 : ℝ) ^ n := by + exact_mod_cast hcountNat + apply (sumOfSquaresIndicator_mul_card_walshSupport_eq_two_pow_three_mul_n_iff_plateaued + f).mp + rw [hindicator] + calc + ((nonzeroAutocorrelationCount f : ℝ) * ((2 : ℝ) ^ n) ^ 2) * + ((walshSupport f).card : ℝ) = + ((nonzeroAutocorrelationCount f : ℝ) * + ((walshSupport f).card : ℝ)) * ((2 : ℝ) ^ n) ^ 2 := by + ring + _ = (2 : ℝ) ^ n * ((2 : ℝ) ^ n) ^ 2 := by + rw [hcountReal] + _ = (2 : ℝ) ^ (3 * n) := by + rw [show 3 * n = n * 3 by omega, pow_mul] + ring + +/-- Every partially bent function is plateaued. -/ +theorem IsPartiallyBent.isPlateaued + {f : BooleanFunction n} (hf : IsPartiallyBent f) : + IsPlateaued f := + (isPlateaued_iff_hasPlateauedWalshSpectrum f).2 + (hasPlateauedWalshSpectrum_of_isPartiallyBent f hf) + +/-- In particular, every quadratic Boolean function is plateaued. -/ +theorem isPlateaued_of_functionAlgebraicDegree_le_two + (f : BooleanFunction n) + (hdegree : FABL.functionAlgebraicDegree f ≤ 2) : + IsPlateaued f := + (isPartiallyBent_of_functionAlgebraicDegree_le_two f hdegree).isPlateaued + +/-- In a decomposition with bent dimension `m` and affine dimension `k`, +every nonzero Walsh coefficient has magnitude `2^(k + m/2)`. -/ +theorem HasBentAffineComplementDecomposition.hasPlateauedWalshAmplitude + {f : BooleanFunction n} {m k : ℕ} + (hf : HasBentAffineComplementDecomposition f m k) : + HasPlateauedWalshAmplitude f (2 ^ (k + m / 2)) := by + have hpartial := hf.isPartiallyBent + have hplateaued : IsPlateaued f := + (isPlateaued_iff_hasPlateauedWalshSpectrum f).mpr + (hasPlateauedWalshSpectrum_of_isPartiallyBent f hpartial) + rcases hplateaued with ⟨amplitude, hamplitude⟩ + have hdimension := hf.dimensions_add + have hcount := hf.nonzeroAutocorrelationCount_eq + have hsupportProduct := + nonzeroAutocorrelationCount_mul_card_walshSupport_eq_of_isPartiallyBent + f hpartial + rw [hcount] at hsupportProduct + have hsupport : (walshSupport f).card = 2 ^ m := by + have heq : 2 ^ k * (walshSupport f).card = 2 ^ k * 2 ^ m := by + calc + 2 ^ k * (walshSupport f).card = 2 ^ n := hsupportProduct + _ = 2 ^ (m + k) := by rw [hdimension] + _ = 2 ^ k * 2 ^ m := by rw [pow_add, mul_comm] + exact Nat.mul_left_cancel (by positivity) heq + have hamplitudeProduct := + card_walshSupport_mul_amplitude_sq_eq_two_pow_two_mul + f amplitude hamplitude + rw [hsupport] at hamplitudeProduct + rcases hf.even_bentDimension with ⟨r, hr⟩ + have hhalf : m / 2 = r := by omega + have htargetProduct : + 2 ^ (2 * n) = 2 ^ m * (2 ^ (k + m / 2)) ^ 2 := by + rw [← pow_mul, ← pow_add] + congr 1 + rw [hhalf] + omega + have hmul : + 2 ^ m * amplitude ^ 2 = 2 ^ m * (2 ^ (k + m / 2)) ^ 2 := + hamplitudeProduct.trans htargetProduct + have hsquare : amplitude ^ 2 = (2 ^ (k + m / 2)) ^ 2 := + Nat.mul_left_cancel (by positivity) hmul + have heq : amplitude = 2 ^ (k + m / 2) := + Nat.pow_left_injective (by norm_num) hsquare + simpa [heq] using hamplitude + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/PermutationReindex.lean b/CryptBoolean/Carlet/Chapter06/PermutationReindex.lean new file mode 100644 index 0000000..5c63e12 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/PermutationReindex.lean @@ -0,0 +1,127 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.Bentness + +/-! +# Bent functions from arbitrary permutations + +Carlet Proposition 21 for reindexing the binary cube by an arbitrary +permutation. +-/ + +open scoped BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- Simultaneous precomposition by a permutation preserves Hamming distance. -/ +theorem hammingDistance_comp_perm + (f g : BooleanFunction n) (σ : Equiv.Perm (FABL.F₂Cube n)) : + hammingDistance (f ∘ σ) (g ∘ σ) = hammingDistance f g := by + classical + unfold hammingDistance hammingDist + rw [Finset.card_filter, Finset.card_filter] + change + (∑ x : FABL.F₂Cube n, if f (σ x) ≠ g (σ x) then 1 else 0) = + ∑ x : FABL.F₂Cube n, if f x ≠ g x then 1 else 0 + exact Equiv.sum_comp σ (fun x ↦ if f x ≠ g x then 1 else 0) + +/-- Reindexing by `σ⁻¹` converts distance from a linear function into +distance from its pullback along the arbitrary permutation `σ`. -/ +theorem hammingDistance_comp_perm_symm_linearFunction + (f : BooleanFunction n) (σ : Equiv.Perm (FABL.F₂Cube n)) + (a : FABL.F₂Cube n) : + hammingDistance (f ∘ σ.symm) (FABL.affineFunction 0 a) = + hammingDistance f (fun x ↦ FABL.f₂DotProduct a (σ x)) := by + let g : BooleanFunction n := fun x ↦ FABL.f₂DotProduct a (σ x) + have hlinear : g ∘ σ.symm = FABL.affineFunction 0 a := by + funext x + simp [g, FABL.affineFunction] + change hammingDistance (f ∘ σ.symm) (FABL.affineFunction 0 a) = + hammingDistance f g + rw [← hlinear] + exact hammingDistance_comp_perm f g σ.symm + +/-- The Walsh coefficient after an arbitrary permutation is the signed +distance from the corresponding pulled-back linear function. -/ +theorem walshTransform_comp_perm_symm_eq_two_pow_sub_two_hammingDistance + (f : BooleanFunction n) (σ : Equiv.Perm (FABL.F₂Cube n)) + (a : FABL.F₂Cube n) : + walshTransform (f ∘ σ.symm) a = + (2 ^ n : ℤ) - 2 * + (hammingDistance f + (fun x ↦ FABL.f₂DotProduct a (σ x)) : ℤ) := by + apply Int.cast_injective (α := ℝ) + push_cast + have hdistance := + hammingDistance_cast_linearFunction_eq (f ∘ σ.symm) a + rw [hammingDistance_comp_perm_symm_linearFunction f σ a] at hdistance + linarith + +/-- Carlet Proposition 21, first assertion: if the distance from `f` to every +permutation-pulled-back linear function differs from `2^(n-1)` by exactly +`2^(n/2-1)`, then reindexing `f` by the inverse permutation is bent. -/ +theorem isBent_comp_perm_symm_of_hammingDistance + (f : BooleanFunction n) (σ : Equiv.Perm (FABL.F₂Cube n)) + (hnEven : Even n) (hnTwo : 2 ≤ n) + (hdistance : ∀ a : FABL.F₂Cube n, + |(hammingDistance f + (fun x ↦ FABL.f₂DotProduct a (σ x)) : ℝ) - + (2 : ℝ) ^ (n - 1)| = + (2 : ℝ) ^ (n / 2 - 1)) : + IsBent (f ∘ σ.symm) := by + have hnEq : n = (n - 1) + 1 := by omega + have hnPower : (2 : ℝ) ^ n / 2 = (2 : ℝ) ^ (n - 1) := by + apply (div_eq_iff (by norm_num : (2 : ℝ) ≠ 0)).2 + calc + (2 : ℝ) ^ n = (2 : ℝ) ^ ((n - 1) + 1) := + congrArg (fun k : ℕ ↦ (2 : ℝ) ^ k) hnEq + _ = (2 : ℝ) ^ (n - 1) * 2 := pow_succ _ _ + have hhalfEq : n / 2 = (n / 2 - 1) + 1 := by omega + have hhalfPower : + (2 : ℝ) ^ (n / 2) / 2 = (2 : ℝ) ^ (n / 2 - 1) := by + apply (div_eq_iff (by norm_num : (2 : ℝ) ≠ 0)).2 + calc + (2 : ℝ) ^ (n / 2) = (2 : ℝ) ^ ((n / 2 - 1) + 1) := + congrArg (fun k : ℕ ↦ (2 : ℝ) ^ k) hhalfEq + _ = (2 : ℝ) ^ (n / 2 - 1) * 2 := pow_succ _ _ + apply (hasFlatWalshSpectrum_iff_isBent (f ∘ σ.symm)).1 + intro a + rw [sqrt_two_pow_eq_pow_half hnEven] + have hdistanceAt := hdistance a + rw [← hnPower, ← hhalfPower] at hdistanceAt + have hwalshInt := + walshTransform_comp_perm_symm_eq_two_pow_sub_two_hammingDistance f σ a + have hwalsh := congrArg (fun z : ℤ ↦ (z : ℝ)) hwalshInt + push_cast at hwalsh + rw [hwalsh] + calc + |(2 : ℝ) ^ n - + 2 * hammingDistance f + (fun x ↦ FABL.f₂DotProduct a (σ x))| = + 2 * + |(hammingDistance f + (fun x ↦ FABL.f₂DotProduct a (σ x)) : ℝ) - + (2 : ℝ) ^ n / 2| := by + rw [show + (2 : ℝ) ^ n - + 2 * hammingDistance f + (fun x ↦ FABL.f₂DotProduct a (σ x)) = + (-2 : ℝ) * + ((hammingDistance f + (fun x ↦ FABL.f₂DotProduct a (σ x)) : ℝ) - + (2 : ℝ) ^ n / 2) by ring, + abs_mul] + norm_num + _ = 2 * ((2 : ℝ) ^ (n / 2) / 2) := by rw [hdistanceAt] + _ = (2 : ℝ) ^ (n / 2) := by ring + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/Plateaued.lean b/CryptBoolean/Carlet/Chapter06/Plateaued.lean new file mode 100644 index 0000000..9b98371 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/Plateaued.lean @@ -0,0 +1,228 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter04.IndicatorSpectralBounds +public import CryptBoolean.Carlet.Chapter06.Bentness +import Mathlib.Data.Nat.Factors + +/-! +# Plateaued Boolean functions + +Carlet Section 6.8: integral Walsh amplitudes and the full-support bent characterization. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- A Boolean function has Walsh amplitude `amplitude` when every raw Walsh +coefficient is zero or has that positive integral magnitude. -/ +def HasPlateauedWalshAmplitude + (f : BooleanFunction n) (amplitude : ℕ) : Prop := + 0 < amplitude ∧ ∀ a, walshTransform f a = 0 ∨ + (walshTransform f a).natAbs = amplitude + +/-- A Boolean function is plateaued when it has some positive integral Walsh amplitude. -/ +def IsPlateaued (f : BooleanFunction n) : Prop := + ∃ amplitude : ℕ, HasPlateauedWalshAmplitude f amplitude + +/-- Carlet's integral-amplitude definition agrees with the existing real +flat-on-support predicate. -/ +theorem isPlateaued_iff_hasPlateauedWalshSpectrum + (f : BooleanFunction n) : + IsPlateaued f ↔ HasPlateauedWalshSpectrum f := by + constructor + · rintro ⟨amplitude, hamplitude, hspec⟩ + refine ⟨(amplitude : ℝ), by exact_mod_cast hamplitude, ?_⟩ + intro a + rcases hspec a with hzero | hmagnitude + · left + simp [hzero] + · right + have hcast := congrArg (fun k : ℕ ↦ (k : ℝ)) hmagnitude + simpa only [Nat.cast_natAbs, Int.cast_abs] using hcast + · rintro ⟨c, hc, hspec⟩ + obtain ⟨u, hu⟩ := exists_walshTransform_ne_zero f + have huMagnitude : |(walshTransform f u : ℝ)| = c := by + rcases hspec u with hzero | hmagnitude + · exact (hu (by exact_mod_cast (abs_eq_zero.mp hzero))).elim + · exact hmagnitude + refine ⟨(walshTransform f u).natAbs, ?_, ?_⟩ + · exact Int.natAbs_pos.mpr hu + · intro a + rcases hspec a with hzero | hmagnitude + · left + exact_mod_cast abs_eq_zero.mp hzero + · right + apply Nat.cast_injective (R := ℝ) + simpa only [Nat.cast_natAbs, Int.cast_abs, huMagnitude] using hmagnitude + +/-- A bent function is exactly a plateaued function with full Walsh support. -/ +theorem isBent_iff_isPlateaued_and_forall_walshTransform_ne_zero + (f : BooleanFunction n) : + IsBent f ↔ IsPlateaued f ∧ ∀ a, walshTransform f a ≠ 0 := by + constructor + · intro hf + refine ⟨⟨2 ^ (n / 2), by positivity, fun a ↦ Or.inr ?_⟩, ?_⟩ + · exact natAbs_walshTransform_eq_two_pow_half_of_isBent f hf a + · intro a hzero + have hmagnitude := + natAbs_walshTransform_eq_two_pow_half_of_isBent f hf a + rw [hzero, Int.natAbs_zero] at hmagnitude + have : 0 < 2 ^ (n / 2) := by positivity + omega + · rintro ⟨⟨amplitude, hamplitude, hspec⟩, hnonzero⟩ + have hmagnitude (a : FABL.F₂Cube n) : + (walshTransform f a).natAbs = amplitude := by + rcases hspec a with hzero | hmagnitude + · exact (hnonzero a hzero).elim + · exact hmagnitude + have hsum : + (∑ a : FABL.F₂Cube n, (walshTransform f a : ℝ) ^ 2) = + (2 : ℝ) ^ n * (amplitude : ℝ) ^ 2 := by + calc + (∑ a : FABL.F₂Cube n, (walshTransform f a : ℝ) ^ 2) = + ∑ _a : FABL.F₂Cube n, (amplitude : ℝ) ^ 2 := by + apply Finset.sum_congr rfl + intro a _ha + have hcast := congrArg (fun k : ℕ ↦ (k : ℝ)) (hmagnitude a) + have habs : |(walshTransform f a : ℝ)| = (amplitude : ℝ) := by + simpa only [Nat.cast_natAbs, Int.cast_abs] using hcast + rw [← sq_abs, habs] + _ = (2 : ℝ) ^ n * (amplitude : ℝ) ^ 2 := by + rw [Finset.sum_const, Finset.card_univ, card_f₂Cube, nsmul_eq_mul] + norm_num + have hparseval := sum_walshTransform_sq_eq_two_pow_sq f + rw [hsum] at hparseval + have hamplitudeSquare : (amplitude : ℝ) ^ 2 = (2 : ℝ) ^ n := by + apply mul_left_cancel₀ (by positivity : (2 : ℝ) ^ n ≠ 0) + calc + (2 : ℝ) ^ n * (amplitude : ℝ) ^ 2 = ((2 : ℝ) ^ n) ^ 2 := + hparseval + _ = (2 : ℝ) ^ n * (2 : ℝ) ^ n := by ring + apply (hasFlatWalshSpectrum_iff_isBent f).1 + intro a + have hcast := congrArg (fun k : ℕ ↦ (k : ℝ)) (hmagnitude a) + have habs : |(walshTransform f a : ℝ)| = (amplitude : ℝ) := by + simpa only [Nat.cast_natAbs, Int.cast_abs] using hcast + rw [habs, ← Real.sqrt_sq + (by positivity : (0 : ℝ) ≤ (amplitude : ℝ)), hamplitudeSquare] + +/-- Parseval determines the product of Walsh-support size and squared plateaued amplitude. -/ +theorem card_walshSupport_mul_amplitude_sq_eq_two_pow_two_mul + (f : BooleanFunction n) (amplitude : ℕ) + (hf : HasPlateauedWalshAmplitude f amplitude) : + (walshSupport f).card * amplitude ^ 2 = 2 ^ (2 * n) := by + have hsumSupport : + (∑ a : FABL.F₂Cube n, (walshTransform f a : ℝ) ^ 2) = + ∑ a ∈ walshSupport f, (walshTransform f a : ℝ) ^ 2 := by + symm + apply Finset.sum_subset (Finset.subset_univ _) + intro a _ha hnot + have hzero : walshTransform f a = 0 := by + simpa only [mem_walshSupport, not_ne_iff] using hnot + simp [hzero] + have hsumAmplitude : + (∑ a ∈ walshSupport f, (walshTransform f a : ℝ) ^ 2) = + ((walshSupport f).card : ℝ) * (amplitude : ℝ) ^ 2 := by + calc + (∑ a ∈ walshSupport f, (walshTransform f a : ℝ) ^ 2) = + ∑ _a ∈ walshSupport f, (amplitude : ℝ) ^ 2 := by + apply Finset.sum_congr rfl + intro a ha + have hne : walshTransform f a ≠ 0 := (mem_walshSupport f a).mp ha + have hmagnitude : (walshTransform f a).natAbs = amplitude := by + rcases hf.2 a with hzero | hmagnitude + · exact (hne hzero).elim + · exact hmagnitude + have hcast := congrArg (fun k : ℕ ↦ (k : ℝ)) hmagnitude + have habs : |(walshTransform f a : ℝ)| = (amplitude : ℝ) := by + simpa only [Nat.cast_natAbs, Int.cast_abs] using hcast + rw [← sq_abs, habs] + _ = ((walshSupport f).card : ℝ) * (amplitude : ℝ) ^ 2 := by + simp + have hreal : + ((walshSupport f).card : ℝ) * (amplitude : ℝ) ^ 2 = + ((2 : ℝ) ^ n) ^ 2 := by + rw [← hsumAmplitude, ← hsumSupport] + exact sum_walshTransform_sq_eq_two_pow_sq f + have hnat : + (walshSupport f).card * amplitude ^ 2 = (2 ^ n) ^ 2 := by + exact_mod_cast hreal + calc + (walshSupport f).card * amplitude ^ 2 = (2 ^ n) ^ 2 := hnat + _ = 2 ^ (2 * n) := by rw [show 2 * n = n * 2 by omega, pow_mul] + +/-- The amplitude of a plateaued Boolean function is a power of two, and its +exponent is at least half the dimension. -/ +theorem exists_plateauedAmplitudeExponent + (f : BooleanFunction n) (amplitude : ℕ) + (hf : HasPlateauedWalshAmplitude f amplitude) : + ∃ r : ℕ, amplitude = 2 ^ r ∧ n ≤ 2 * r := by + have hcard := + card_walshSupport_mul_amplitude_sq_eq_two_pow_two_mul f amplitude hf + rcases Nat.eq_two_pow_or_exists_odd_prime_and_dvd amplitude with + ⟨r, hr⟩ | ⟨p, hp, hpAmplitude, hpOdd⟩ + · refine ⟨r, hr, ?_⟩ + have hcardBound : (walshSupport f).card ≤ 2 ^ n := by + calc + (walshSupport f).card ≤ + (Finset.univ : Finset (FABL.F₂Cube n)).card := + Finset.card_le_card (Finset.subset_univ _) + _ = 2 ^ n := by simp + have heq : + (walshSupport f).card * 2 ^ (2 * r) = 2 ^ (2 * n) := by + calc + (walshSupport f).card * 2 ^ (2 * r) = + (walshSupport f).card * (2 ^ r) ^ 2 := by + rw [show 2 * r = r * 2 by omega, pow_mul] + _ = (walshSupport f).card * amplitude ^ 2 := by rw [hr] + _ = 2 ^ (2 * n) := hcard + have hproduct : + 2 ^ (2 * n) ≤ 2 ^ n * 2 ^ (2 * r) := by + rw [← heq] + exact Nat.mul_le_mul_right (2 ^ (2 * r)) hcardBound + have hpow : 2 ^ (2 * n) ≤ 2 ^ (n + 2 * r) := by + simpa only [pow_add] using hproduct + have hexponent : 2 * n ≤ n + 2 * r := + (Nat.pow_le_pow_iff_right (by omega : 1 < 2)).mp hpow + omega + · have hpAmplitudeSq : p ∣ amplitude ^ 2 := + dvd_trans hpAmplitude (dvd_pow_self amplitude (by omega)) + have hpPower : p ∣ 2 ^ (2 * n) := by + rw [← hcard] + exact dvd_mul_of_dvd_right hpAmplitudeSq _ + have hpTwo : p ∣ 2 := hp.dvd_of_dvd_pow hpPower + have hpEq : p = 2 := + (Nat.prime_dvd_prime_iff_eq hp Nat.prime_two).mp hpTwo + rcases hpOdd with ⟨k, hk⟩ + omega + +/-- Every Walsh coefficient of a plateaued Boolean function is divisible by +`2^⌈n/2⌉`; this is `2^(n/2)` in even dimension and `2^((n+1)/2)` in odd dimension. -/ +theorem two_pow_add_one_div_two_dvd_walshTransform_of_hasPlateauedWalshAmplitude + (f : BooleanFunction n) (amplitude : ℕ) + (hf : HasPlateauedWalshAmplitude f amplitude) + (a : FABL.F₂Cube n) : + ((2 ^ ((n + 1) / 2) : ℕ) : ℤ) ∣ walshTransform f a := by + obtain ⟨r, hr, hdimension⟩ := + exists_plateauedAmplitudeExponent f amplitude hf + have hexponent : (n + 1) / 2 ≤ r := by omega + have hpower : 2 ^ ((n + 1) / 2) ∣ 2 ^ r := + (Nat.pow_dvd_pow_iff_le_right (by omega : 1 < 2)).mpr hexponent + rcases hf.2 a with hzero | hmagnitude + · rw [hzero] + exact dvd_zero _ + · apply Int.natCast_dvd.mpr + rw [hmagnitude, hr] + exact hpower + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/PlateauedOrphan.lean b/CryptBoolean/Carlet/Chapter06/PlateauedOrphan.lean new file mode 100644 index 0000000..ee8282b --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/PlateauedOrphan.lean @@ -0,0 +1,311 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter03.ReedMullerMinimumWeight +public import CryptBoolean.Carlet.Chapter04.KthNonhomomorphicity +public import CryptBoolean.Carlet.Chapter04.ReedMullerCosetDistance +public import CryptBoolean.Carlet.Chapter06.DualIsometry +public import CryptBoolean.Carlet.Chapter06.Plateaued + +/-! +# Plateaued cosets and orphans + +The support order on first-order Reed--Muller cosets and Langevin's maximality +theorem for non-affine plateaued functions. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- A first-order coset leader is a representative whose weight realizes its +nonlinearity. -/ +def IsFirstOrderCosetLeader (f : BooleanFunction n) : Prop := + hammingWeight f = nonlinearity f + +/-- The support order on first-order Reed--Muller cosets. -/ +def FirstOrderCosetBelow (f g : BooleanFunction n) : Prop := + ∃ f₁ g₁ : BooleanFunction n, + f₁ + f ∈ reedMuller 1 n ∧ + g₁ + g ∈ reedMuller 1 n ∧ + IsFirstOrderCosetLeader f₁ ∧ + IsFirstOrderCosetLeader g₁ ∧ + support f₁ ⊆ support g₁ + +/-- A first-order Reed--Muller coset is an orphan when it is maximal in the +coset-leader support order. -/ +def IsFirstOrderOrphan (f : BooleanFunction n) : Prop := + ∀ g : BooleanFunction n, + FirstOrderCosetBelow f g → f + g ∈ reedMuller 1 n + +/-- Adding an affine function preserves plateauedness. -/ +theorem IsPlateaued.add_affineFunction + {f : BooleanFunction n} (hf : IsPlateaued f) + (b : FABL.𝔽₂) (a : FABL.F₂Cube n) : + IsPlateaued (f + FABL.affineFunction b a) := by + rcases hf with ⟨amplitude, hpositive, hspectrum⟩ + refine ⟨amplitude, hpositive, fun u ↦ ?_⟩ + rcases hspectrum (u + a) with hzero | hmagnitude + · left + rw [walshTransform_add_affineFunction] + simp [hzero] + · right + simpa only [walshTransform_add_affineFunction_natAbs] using hmagnitude + +private theorem walshTransform_zero_cast_eq_maxWalshMagnitude_of_leader + (f : BooleanFunction n) (hf : IsFirstOrderCosetLeader f) : + (walshTransform f 0 : ℝ) = (maxWalshMagnitude f : ℝ) := by + have hrelation := congrArg (fun k : ℕ ↦ (k : ℝ)) + (two_mul_nonlinearity_add_maxWalshMagnitude f) + have hzero := congrArg (fun z : ℤ ↦ (z : ℝ)) + (walshTransform_zero_eq_two_pow_sub_two_weight f) + push_cast at hrelation hzero + rw [hf] at hzero + linarith + +private theorem amplitude_eq_maxWalshMagnitude_of_leader + (f : BooleanFunction n) (amplitude : ℕ) + (hf : HasPlateauedWalshAmplitude f amplitude) + (hleader : IsFirstOrderCosetLeader f) : + amplitude = maxWalshMagnitude f := by + have hzeroMax := + walshTransform_zero_cast_eq_maxWalshMagnitude_of_leader f hleader + obtain ⟨u, hu⟩ := exists_walshTransform_ne_zero f + have hmaxPositive : 0 < (maxWalshMagnitude f : ℝ) := by + have habsPositive : 0 < |(walshTransform f u : ℝ)| := + abs_pos.mpr (by exact_mod_cast hu) + exact habsPositive.trans_le (abs_walshTransform_le_maxWalshMagnitude f u) + have hzeroNe : walshTransform f 0 ≠ 0 := by + intro hzero + rw [hzero, Int.cast_zero] at hzeroMax + linarith + have hmagnitude : (walshTransform f 0).natAbs = amplitude := by + rcases hf.2 0 with hzero | hmagnitude + · exact (hzeroNe hzero).elim + · exact hmagnitude + apply Nat.cast_injective (R := ℝ) + have hcast := congrArg (fun k : ℕ ↦ (k : ℝ)) hmagnitude + have hmaxAmplitude : + (maxWalshMagnitude f : ℝ) = (amplitude : ℝ) := by + simpa only [Nat.cast_natAbs, Int.cast_abs, abs_of_pos + (hzeroMax.trans_gt hmaxPositive), hzeroMax, + abs_of_nonneg (by positivity : 0 ≤ (maxWalshMagnitude f : ℝ))] using hcast + exact hmaxAmplitude.symm + +/-- A non-affine plateaued coset leader cannot have its support properly +contained in the support of another first-order coset leader. -/ +theorem eq_of_plateaued_cosetLeaders_of_support_subset + (f g : BooleanFunction n) + (hf : IsPlateaued f) + (hnonlinearity : 0 < nonlinearity f) + (hleaderF : IsFirstOrderCosetLeader f) + (hleaderG : IsFirstOrderCosetLeader g) + (hsubset : support f ⊆ support g) : + g = f := by + classical + by_contra hne + rcases hf with ⟨amplitude, hfAmplitude⟩ + have hamplitudeMax : amplitude = maxWalshMagnitude f := + amplitude_eq_maxWalshMagnitude_of_leader f amplitude hfAmplitude hleaderF + have hrelationF := two_mul_nonlinearity_add_maxWalshMagnitude f + have hamplitudeLt : amplitude < 2 ^ n := by + rw [hamplitudeMax] + omega + let k := hammingWeight (f + g) + have hk : 0 < k := by + apply Nat.pos_of_ne_zero + intro hkzero + have hfgzero : f + g = 0 := hammingNorm_eq_zero.mp hkzero + apply hne + funext x + have hx := congrFun hfgzero x + simp only [Pi.add_apply, Pi.zero_apply] at hx + by_cases hfx : f x = 0 + · simp only [hfx, zero_add] at hx ⊢ + exact hx + · have hfxOne : f x = 1 := Fin.eq_one_of_ne_zero _ hfx + by_cases hgx : g x = 0 + · simp [hfxOne, hgx] at hx + · exact (Fin.eq_one_of_ne_zero _ hgx).trans hfxOne.symm + have hinter : support f ∩ support g = support f := + Finset.inter_eq_left.mpr hsubset + have hweight := hammingWeight_add_add_two_mul_card_inter f g + rw [hinter, ← hammingWeight_eq_card_support] at hweight + have hzeroF := + walshTransform_zero_cast_eq_maxWalshMagnitude_of_leader f hleaderF + have hzeroG := + walshTransform_zero_cast_eq_maxWalshMagnitude_of_leader g hleaderG + have hmaxG : + (maxWalshMagnitude g : ℝ) = + (amplitude : ℝ) - 2 * (k : ℝ) := by + have hzF := congrArg (fun z : ℤ ↦ (z : ℝ)) + (walshTransform_zero_eq_two_pow_sub_two_weight f) + have hzG := congrArg (fun z : ℤ ↦ (z : ℝ)) + (walshTransform_zero_eq_two_pow_sub_two_weight g) + have hw := congrArg (fun q : ℕ ↦ (q : ℝ)) hweight + push_cast at hzF hzG hw + rw [← hamplitudeMax] at hzeroF + dsimp [k] at hw ⊢ + linarith + have hraw (h : BooleanFunction n) (u : FABL.F₂Cube n) : + rawFourierTransform (realSignView h) u = + (walshTransform h u : ℝ) := by + rw [rawFourierTransform_eq_two_pow_mul_vectorFourierCoeff, + walshTransform_eq_two_pow_mul_vectorFourierCoeff] + have hinner : + (∑ x, realSignView f x * realSignView g x) = + (2 : ℝ) ^ n - 2 * (k : ℝ) := by + calc + (∑ x, realSignView f x * realSignView g x) = + ∑ x, realSignView (f + g) x := by + apply Finset.sum_congr rfl + intro x _hx + exact (realSignView_add f g x).symm + _ = (walshTransform (f + g) 0 : ℝ) := by + rw [walshTransform_cast_eq_sum_realSignView_mul_character] + simp + _ = (2 : ℝ) ^ n - 2 * (k : ℝ) := by + have hz := congrArg (fun z : ℤ ↦ (z : ℝ)) + (walshTransform_zero_eq_two_pow_sub_two_weight (f + g)) + push_cast at hz + exact hz + have hplancherel := + sum_rawFourierTransform_mul (realSignView f) (realSignView g) + simp_rw [hraw] at hplancherel + rw [hinner] at hplancherel + have hsumBound : + (∑ u, (walshTransform f u : ℝ) * (walshTransform g u : ℝ)) ≤ + ((walshSupport f).card : ℝ) * (amplitude : ℝ) * + (maxWalshMagnitude g : ℝ) := by + calc + (∑ u, (walshTransform f u : ℝ) * (walshTransform g u : ℝ)) = + ∑ u ∈ walshSupport f, + (walshTransform f u : ℝ) * (walshTransform g u : ℝ) := by + symm + apply Finset.sum_subset (Finset.subset_univ _) + intro u _hu hnot + have hzero : walshTransform f u = 0 := by + simpa only [mem_walshSupport, not_ne_iff] using hnot + simp [hzero] + _ ≤ ∑ _u ∈ walshSupport f, + (amplitude : ℝ) * (maxWalshMagnitude g : ℝ) := by + apply Finset.sum_le_sum + intro u hu + have hneF : walshTransform f u ≠ 0 := + (mem_walshSupport f u).mp hu + have hmagnitudeF : + |(walshTransform f u : ℝ)| = (amplitude : ℝ) := by + rcases hfAmplitude.2 u with hzero | hmagnitude + · exact (hneF hzero).elim + · have hcast := congrArg (fun q : ℕ ↦ (q : ℝ)) hmagnitude + simpa only [Nat.cast_natAbs, Int.cast_abs] using hcast + calc + (walshTransform f u : ℝ) * (walshTransform g u : ℝ) ≤ + |(walshTransform f u : ℝ) * (walshTransform g u : ℝ)| := + le_abs_self _ + _ = |(walshTransform f u : ℝ)| * + |(walshTransform g u : ℝ)| := abs_mul _ _ + _ ≤ (amplitude : ℝ) * (maxWalshMagnitude g : ℝ) := by + rw [hmagnitudeF] + exact mul_le_mul_of_nonneg_left + (abs_walshTransform_le_maxWalshMagnitude g u) + (by positivity) + _ = ((walshSupport f).card : ℝ) * (amplitude : ℝ) * + (maxWalshMagnitude g : ℝ) := by simp [mul_assoc] + have hcard := + card_walshSupport_mul_amplitude_sq_eq_two_pow_two_mul + f amplitude hfAmplitude + have hcardReal := congrArg (fun q : ℕ ↦ (q : ℝ)) hcard + push_cast at hcardReal + rw [hplancherel, hmaxG] at hsumBound + have hamplitudePositive : 0 < (amplitude : ℝ) := by + exact_mod_cast hfAmplitude.1 + have hpowPositive : 0 < (2 : ℝ) ^ n := by positivity + have hpowSquare : (2 : ℝ) ^ (2 * n) = ((2 : ℝ) ^ n) ^ 2 := by + rw [mul_comm 2 n, pow_mul] + rw [hpowSquare] at hcardReal + have hkReal : 0 < (k : ℝ) := by exact_mod_cast hk + have hsupportAmplitudeLe : + ((walshSupport f).card : ℝ) * (amplitude : ℝ) ≤ + (2 : ℝ) ^ n := by + nlinarith [hsumBound, hcardReal, hkReal] + have hmul := mul_le_mul_of_nonneg_right hsupportAmplitudeLe + (le_of_lt hamplitudePositive) + have hpowLeAmplitude : (2 : ℝ) ^ n ≤ (amplitude : ℝ) := by + nlinarith [hmul, hcardReal] + exact (not_lt_of_ge hpowLeAmplitude) (by exact_mod_cast hamplitudeLt) + +/-- Langevin's corrected orphan theorem: every non-affine plateaued function +represents a maximal first-order Reed--Muller coset. -/ +theorem isFirstOrderOrphan_of_isPlateaued + (f : BooleanFunction n) (hf : IsPlateaued f) + (hnonaffine : f ∉ reedMuller 1 n) : + IsFirstOrderOrphan f := by + have hnonlinearity : 0 < nonlinearity f := by + apply Nat.pos_of_ne_zero + intro hzero + rcases (isAffineBooleanFunction_iff_nonlinearity_eq_zero f).2 hzero with + ⟨b, a, hfa⟩ + apply hnonaffine + rw [hfa] + exact affineFunction_mem_reedMuller_one b a + intro g hbelow + rcases hbelow with + ⟨f₁, g₁, hf₁Coset, hg₁Coset, hf₁Leader, hg₁Leader, hsupport⟩ + obtain ⟨b, a, haffine⟩ := + FABL.exists_affineFunction_of_functionAlgebraicDegree_le_one + (f₁ + f) hf₁Coset + have hf₁Eq : f₁ = f + FABL.affineFunction b a := by + funext x + have hx := congrFun haffine x + simp only [Pi.add_apply] at hx ⊢ + rw [← hx] + by_cases hf₁x : f₁ x = 0 + · by_cases hfx : f x = 0 + · simp [hf₁x, hfx] + · have hfxOne : f x = 1 := Fin.eq_one_of_ne_zero _ hfx + simp [hf₁x, hfxOne] + · have hf₁xOne : f₁ x = 1 := Fin.eq_one_of_ne_zero _ hf₁x + by_cases hfx : f x = 0 + · simp [hf₁xOne, hfx] + · have hfxOne : f x = 1 := Fin.eq_one_of_ne_zero _ hfx + simp [hf₁xOne, hfxOne] + have hf₁Plateaued : IsPlateaued f₁ := by + rw [hf₁Eq] + exact hf.add_affineFunction b a + have hf₁Nonlinearity : 0 < nonlinearity f₁ := by + rw [hf₁Eq, nonlinearity_add_affineFunction] + exact hnonlinearity + have hleadersEqual : g₁ = f₁ := + eq_of_plateaued_cosetLeaders_of_support_subset + f₁ g₁ hf₁Plateaued hf₁Nonlinearity hf₁Leader hg₁Leader hsupport + have hsum := (reedMuller 1 n).add_mem hf₁Coset hg₁Coset + have hfunctions : (f₁ + f) + (g₁ + g) = f + g := by + rw [hleadersEqual] + funext x + simp only [Pi.add_apply] + by_cases hf₁x : f₁ x = 0 + · simp [hf₁x] + · have hf₁xOne : f₁ x = 1 := Fin.eq_one_of_ne_zero _ hf₁x + by_cases hfx : f x = 0 + · by_cases hgx : g x = 0 + · simp [hf₁xOne, hfx, hgx] + · have hgxOne : g x = 1 := Fin.eq_one_of_ne_zero _ hgx + simp [hf₁xOne, hfx, hgxOne] + · have hfxOne : f x = 1 := Fin.eq_one_of_ne_zero _ hfx + by_cases hgx : g x = 0 + · simp [hf₁xOne, hfxOne, hgx] + · have hgxOne : g x = 1 := Fin.eq_one_of_ne_zero _ hgx + simp [hf₁xOne, hfxOne, hgxOne] + rwa [hfunctions] at hsum + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/PlateauedSecondOrder.lean b/CryptBoolean/Carlet/Chapter06/PlateauedSecondOrder.lean new file mode 100644 index 0000000..c652e54 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/PlateauedSecondOrder.lean @@ -0,0 +1,131 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.Plateaued +public import CryptBoolean.Carlet.Chapter06.SecondOrderCharacterization + +/-! +# Second-order characterization of plateaued functions + +Carlet Proposition 28 and Relation (55). +-/ + +open scoped BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- A positive integer is the Walsh amplitude exactly when the raw Walsh +transform satisfies its corresponding cubic equation. -/ +theorem hasPlateauedWalshAmplitude_iff_forall_walshTransform_cube_eq + (f : BooleanFunction n) (amplitude : ℕ) : + HasPlateauedWalshAmplitude f amplitude ↔ + 0 < amplitude ∧ ∀ u : FABL.F₂Cube n, + (walshTransform f u : ℝ) ^ 3 = + (amplitude : ℝ) ^ 2 * (walshTransform f u : ℝ) := by + constructor + · rintro ⟨hamplitude, hspec⟩ + refine ⟨hamplitude, fun u ↦ ?_⟩ + rcases hspec u with hzero | hmagnitude + · simp [hzero] + · have habs : |(walshTransform f u : ℝ)| = (amplitude : ℝ) := by + have hcast := congrArg (fun k : ℕ ↦ (k : ℝ)) hmagnitude + simpa only [Nat.cast_natAbs, Int.cast_abs] using hcast + have hsquare : (walshTransform f u : ℝ) ^ 2 = (amplitude : ℝ) ^ 2 := by + rw [← sq_abs, habs] + calc + (walshTransform f u : ℝ) ^ 3 = + (walshTransform f u : ℝ) ^ 2 * (walshTransform f u : ℝ) := by ring + _ = (amplitude : ℝ) ^ 2 * (walshTransform f u : ℝ) := by rw [hsquare] + · rintro ⟨hamplitude, hcubic⟩ + refine ⟨hamplitude, fun u ↦ ?_⟩ + by_cases hzero : walshTransform f u = 0 + · exact Or.inl hzero + · right + have hrealZero : (walshTransform f u : ℝ) ≠ 0 := by exact_mod_cast hzero + have hsquare : (walshTransform f u : ℝ) ^ 2 = (amplitude : ℝ) ^ 2 := by + apply mul_left_cancel₀ hrealZero + calc + (walshTransform f u : ℝ) * (walshTransform f u : ℝ) ^ 2 = + (walshTransform f u : ℝ) ^ 3 := by ring + _ = (amplitude : ℝ) ^ 2 * (walshTransform f u : ℝ) := hcubic u + _ = (walshTransform f u : ℝ) * (amplitude : ℝ) ^ 2 := by ring + have habs : |(walshTransform f u : ℝ)| = (amplitude : ℝ) := by + have hnonneg : 0 ≤ (amplitude : ℝ) := by positivity + rw [← sq_abs] at hsquare + nlinarith [abs_nonneg (walshTransform f u : ℝ)] + apply Nat.cast_injective (R := ℝ) + simpa only [Nat.cast_natAbs, Int.cast_abs] using habs + +/-- Carlet Proposition 28, Relation (55): a Boolean function is plateaued +exactly when all fixed-point double sums of second-derivative signs are the +same positive square. -/ +theorem isPlateaued_iff_exists_forall_secondDerivativeDoubleSum_eq_sq + (f : BooleanFunction n) : + IsPlateaued f ↔ + ∃ amplitude : ℕ, 0 < amplitude ∧ + ∀ x : FABL.F₂Cube n, + secondDerivativeDoubleSum f x = (amplitude : ℝ) ^ 2 := by + constructor + · rintro ⟨amplitude, hf⟩ + have hcubic := + (hasPlateauedWalshAmplitude_iff_forall_walshTransform_cube_eq + f amplitude).1 hf + refine ⟨amplitude, hcubic.1, fun x ↦ ?_⟩ + have hconvolution : + rawTripleConvolution (realSignView f) = + fun y ↦ (amplitude : ℝ) ^ 2 * realSignView f y := by + apply eq_of_rawFourierTransform_eq + funext u + rw [rawFourierTransform_rawTripleConvolution, + rawFourierTransform_const_mul_realSignView] + have hwalsh : rawFourierTransform (realSignView f) u = + (walshTransform f u : ℝ) := by + simpa [rawFourierTransform] using + (walshTransform_cast_eq_sum_realSignView_mul_character f u).symm + rw [hwalsh] + exact hcubic.2 u + rw [secondDerivativeDoubleSum_eq_mul_rawTripleConvolution, hconvolution] + calc + realSignView f x * ((amplitude : ℝ) ^ 2 * realSignView f x) = + (amplitude : ℝ) ^ 2 * + (realSignView f x * realSignView f x) := by ring + _ = (amplitude : ℝ) ^ 2 := by rw [realSignView_mul_self, mul_one] + · rintro ⟨amplitude, hamplitude, hsecond⟩ + refine ⟨amplitude, + (hasPlateauedWalshAmplitude_iff_forall_walshTransform_cube_eq + f amplitude).2 ⟨hamplitude, ?_⟩⟩ + have hconvolution : + rawTripleConvolution (realSignView f) = + fun x ↦ (amplitude : ℝ) ^ 2 * realSignView f x := by + funext x + have h := hsecond x + rw [secondDerivativeDoubleSum_eq_mul_rawTripleConvolution] at h + calc + rawTripleConvolution (realSignView f) x = + 1 * rawTripleConvolution (realSignView f) x := by ring + _ = (realSignView f x * realSignView f x) * + rawTripleConvolution (realSignView f) x := by + rw [realSignView_mul_self] + _ = realSignView f x * + (realSignView f x * rawTripleConvolution (realSignView f) x) := by ring + _ = realSignView f x * (amplitude : ℝ) ^ 2 := by rw [h] + _ = (amplitude : ℝ) ^ 2 * realSignView f x := by ring + intro u + have hu := congrArg (fun φ ↦ rawFourierTransform φ u) hconvolution + rw [rawFourierTransform_rawTripleConvolution, + rawFourierTransform_const_mul_realSignView] at hu + have hwalsh : rawFourierTransform (realSignView f) u = + (walshTransform f u : ℝ) := by + simpa [rawFourierTransform] using + (walshTransform_cast_eq_sum_realSignView_mul_character f u).symm + simpa only [hwalsh] using hu + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/PlateauedSupport.lean b/CryptBoolean/Carlet/Chapter06/PlateauedSupport.lean new file mode 100644 index 0000000..7081375 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/PlateauedSupport.lean @@ -0,0 +1,232 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.Plateaued + +/-! +# Walsh-support bound for plateaued functions + +Carlet Section 6.8: the support-size nonlinearity bound and its equality case. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The maximum Walsh magnitude is the amplitude supplied by a plateaued spectrum. -/ +theorem maxWalshMagnitude_eq_of_hasPlateauedWalshAmplitude + (f : BooleanFunction n) (amplitude : ℕ) + (hf : HasPlateauedWalshAmplitude f amplitude) : + maxWalshMagnitude f = amplitude := by + apply le_antisymm + · unfold maxWalshMagnitude + apply Finset.sup'_le + intro a _ha + rcases hf.2 a with hzero | hmagnitude + · simp [hzero] + · exact hmagnitude.le + · obtain ⟨a, ha⟩ := exists_walshTransform_ne_zero f + have hmagnitude : (walshTransform f a).natAbs = amplitude := by + rcases hf.2 a with hzero | hmagnitude + · exact (ha hzero).elim + · exact hmagnitude + rw [← hmagnitude] + unfold maxWalshMagnitude + exact Finset.le_sup' (fun u ↦ (walshTransform f u).natAbs) + (Finset.mem_univ a) + +/-- Parseval restricted to the nonzero Walsh support. -/ +theorem sum_walshTransform_sq_walshSupport + (f : BooleanFunction n) : + (∑ a ∈ walshSupport f, (walshTransform f a : ℝ) ^ 2) = + ((2 : ℝ) ^ n) ^ 2 := by + rw [← sum_walshTransform_sq_eq_two_pow_sq f] + apply Finset.sum_subset (Finset.subset_univ _) + intro a _ha hnot + have hzero : walshTransform f a = 0 := by + simpa only [mem_walshSupport, not_ne_iff] using hnot + simp [hzero] + +/-- Walsh support size times squared maximum magnitude dominates the Parseval mass. -/ +theorem two_pow_sq_le_card_walshSupport_mul_maxWalshMagnitude_sq + (f : BooleanFunction n) : + ((2 : ℝ) ^ n) ^ 2 ≤ + ((walshSupport f).card : ℝ) * (maxWalshMagnitude f : ℝ) ^ 2 := by + rw [← sum_walshTransform_sq_walshSupport f] + calc + (∑ a ∈ walshSupport f, (walshTransform f a : ℝ) ^ 2) ≤ + ∑ _a ∈ walshSupport f, (maxWalshMagnitude f : ℝ) ^ 2 := by + apply Finset.sum_le_sum + intro a _ha + have habs := abs_walshTransform_le_maxWalshMagnitude f a + simpa only [sq_abs] using + (sq_le_sq₀ (abs_nonneg (walshTransform f a : ℝ)) + (Nat.cast_nonneg (maxWalshMagnitude f))).mpr habs + _ = ((walshSupport f).card : ℝ) * + (maxWalshMagnitude f : ℝ) ^ 2 := by simp + +/-- Equality in the Walsh-support product bound characterizes plateaued functions. -/ +theorem two_pow_sq_eq_card_walshSupport_mul_maxWalshMagnitude_sq_iff_plateaued + (f : BooleanFunction n) : + ((2 : ℝ) ^ n) ^ 2 = + ((walshSupport f).card : ℝ) * (maxWalshMagnitude f : ℝ) ^ 2 ↔ + IsPlateaued f := by + constructor + · intro heq + have hgap : + (∑ a ∈ walshSupport f, + ((maxWalshMagnitude f : ℝ) ^ 2 - + (walshTransform f a : ℝ) ^ 2)) = 0 := by + rw [Finset.sum_sub_distrib, Finset.sum_const, nsmul_eq_mul, + sum_walshTransform_sq_walshSupport, heq] + ring + have hnonneg (a : FABL.F₂Cube n) : + 0 ≤ (maxWalshMagnitude f : ℝ) ^ 2 - + (walshTransform f a : ℝ) ^ 2 := by + have habs := abs_walshTransform_le_maxWalshMagnitude f a + have hsquare : (walshTransform f a : ℝ) ^ 2 ≤ + (maxWalshMagnitude f : ℝ) ^ 2 := by + simpa only [sq_abs] using + (sq_le_sq₀ (abs_nonneg (walshTransform f a : ℝ)) + (Nat.cast_nonneg (maxWalshMagnitude f))).mpr habs + linarith + have hmaxPositive : 0 < (maxWalshMagnitude f : ℝ) := by + obtain ⟨u, hu⟩ := exists_walshTransform_ne_zero f + have huPositive : 0 < |(walshTransform f u : ℝ)| := + abs_pos.mpr (by exact_mod_cast hu) + exact huPositive.trans_le (abs_walshTransform_le_maxWalshMagnitude f u) + apply (isPlateaued_iff_hasPlateauedWalshSpectrum f).mpr + refine ⟨(maxWalshMagnitude f : ℝ), hmaxPositive, ?_⟩ + intro a + by_cases ha : a ∈ walshSupport f + · right + have hzero := (Finset.sum_eq_zero_iff_of_nonneg + (fun u _hu ↦ hnonneg u)).mp hgap a ha + have hsquare : (walshTransform f a : ℝ) ^ 2 = + (maxWalshMagnitude f : ℝ) ^ 2 := by linarith + exact (sq_eq_sq₀ (abs_nonneg (walshTransform f a : ℝ)) + (Nat.cast_nonneg (maxWalshMagnitude f))).mp (by + simpa only [sq_abs] using hsquare) + · left + have hzero : walshTransform f a = 0 := by + simpa only [mem_walshSupport, not_ne_iff] using ha + simp [hzero] + · intro hf + obtain ⟨amplitude, hfAmplitude⟩ := hf + have hcard := + card_walshSupport_mul_amplitude_sq_eq_two_pow_two_mul + f amplitude hfAmplitude + have hmax := + maxWalshMagnitude_eq_of_hasPlateauedWalshAmplitude + f amplitude hfAmplitude + rw [hmax] + have hcast := congrArg (fun k : ℕ ↦ (k : ℝ)) hcard + norm_num only [Nat.cast_mul, Nat.cast_pow, Nat.cast_ofNat] at hcast + calc + ((2 : ℝ) ^ n) ^ 2 = (2 : ℝ) ^ (2 * n) := by + rw [show 2 * n = n * 2 by omega, pow_mul] + _ = ((walshSupport f).card : ℝ) * (amplitude : ℝ) ^ 2 := hcast.symm + +/-- Carlet's support-size upper bound on nonlinearity. -/ +theorem nonlinearity_cast_le_walshSupport_bound + (f : BooleanFunction n) : + (nonlinearity f : ℝ) ≤ + (2 : ℝ) ^ n / 2 * + (1 - (Real.sqrt ((walshSupport f).card : ℝ))⁻¹) := by + obtain ⟨u, hu⟩ := exists_walshTransform_ne_zero f + have hcardPositive : (0 : ℝ) < ((walshSupport f).card : ℝ) := by + exact_mod_cast Finset.card_pos.mpr + ⟨u, (mem_walshSupport f u).mpr hu⟩ + have hsqrtPositive : 0 < Real.sqrt ((walshSupport f).card : ℝ) := + Real.sqrt_pos.2 hcardPositive + have hproduct := + two_pow_sq_le_card_walshSupport_mul_maxWalshMagnitude_sq f + have hpeak : + (2 : ℝ) ^ n / Real.sqrt ((walshSupport f).card : ℝ) ≤ + (maxWalshMagnitude f : ℝ) := by + rw [div_le_iff₀ hsqrtPositive] + have hsquare : + ((2 : ℝ) ^ n) ^ 2 ≤ + ((maxWalshMagnitude f : ℝ) * + Real.sqrt ((walshSupport f).card : ℝ)) ^ 2 := by + rw [mul_pow, Real.sq_sqrt hcardPositive.le] + simpa [mul_comm] using hproduct + exact (sq_le_sq₀ (by positivity : 0 ≤ (2 : ℝ) ^ n) + (mul_nonneg (Nat.cast_nonneg _) (Real.sqrt_nonneg _))).mp hsquare + rw [nonlinearity_cast_eq_relation_35] + have hsqrtNe : Real.sqrt ((walshSupport f).card : ℝ) ≠ 0 := + hsqrtPositive.ne' + calc + (2 : ℝ) ^ n / 2 - (maxWalshMagnitude f : ℝ) / 2 ≤ + (2 : ℝ) ^ n / 2 - + ((2 : ℝ) ^ n / Real.sqrt ((walshSupport f).card : ℝ)) / 2 := by + linarith + _ = (2 : ℝ) ^ n / 2 * + (1 - (Real.sqrt ((walshSupport f).card : ℝ))⁻¹) := by + rw [inv_eq_one_div] + field_simp + +/-- Equality in the Walsh-support nonlinearity bound holds exactly for plateaued functions. -/ +theorem nonlinearity_cast_eq_walshSupport_bound_iff_plateaued + (f : BooleanFunction n) : + (nonlinearity f : ℝ) = + (2 : ℝ) ^ n / 2 * + (1 - (Real.sqrt ((walshSupport f).card : ℝ))⁻¹) ↔ + IsPlateaued f := by + obtain ⟨u, hu⟩ := exists_walshTransform_ne_zero f + have hcardPositive : (0 : ℝ) < ((walshSupport f).card : ℝ) := by + exact_mod_cast Finset.card_pos.mpr + ⟨u, (mem_walshSupport f u).mpr hu⟩ + have hsqrtPositive : 0 < Real.sqrt ((walshSupport f).card : ℝ) := + Real.sqrt_pos.2 hcardPositive + have hsqrtNe : Real.sqrt ((walshSupport f).card : ℝ) ≠ 0 := + hsqrtPositive.ne' + constructor + · intro hnonlinearity + rw [nonlinearity_cast_eq_relation_35] at hnonlinearity + have hpeak : + (maxWalshMagnitude f : ℝ) = + (2 : ℝ) ^ n / Real.sqrt ((walshSupport f).card : ℝ) := by + rw [inv_eq_one_div] at hnonlinearity + field_simp [hsqrtNe] at hnonlinearity + apply (eq_div_iff hsqrtNe).mpr + ring_nf at hnonlinearity ⊢ + linarith + apply + (two_pow_sq_eq_card_walshSupport_mul_maxWalshMagnitude_sq_iff_plateaued + f).mp + rw [hpeak] + field_simp [hsqrtNe] + rw [Real.sq_sqrt hcardPositive.le] + · intro hf + have hproduct := + (two_pow_sq_eq_card_walshSupport_mul_maxWalshMagnitude_sq_iff_plateaued + f).mpr hf + have hsquare : + ((maxWalshMagnitude f : ℝ) * + Real.sqrt ((walshSupport f).card : ℝ)) ^ 2 = + ((2 : ℝ) ^ n) ^ 2 := by + rw [mul_pow, Real.sq_sqrt hcardPositive.le] + simpa [mul_comm] using hproduct.symm + have hmul : + (maxWalshMagnitude f : ℝ) * + Real.sqrt ((walshSupport f).card : ℝ) = (2 : ℝ) ^ n := + (sq_eq_sq₀ + (mul_nonneg (Nat.cast_nonneg _) (Real.sqrt_nonneg _)) + (by positivity : 0 ≤ (2 : ℝ) ^ n)).mp hsquare + have hpeak : + (maxWalshMagnitude f : ℝ) = + (2 : ℝ) ^ n / Real.sqrt ((walshSupport f).card : ℝ) := + (eq_div_iff hsqrtNe).mpr hmul + rw [nonlinearity_cast_eq_relation_35, hpeak, inv_eq_one_div] + field_simp [hsqrtNe] + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/QuadraticBent.lean b/CryptBoolean/Carlet/Chapter06/QuadraticBent.lean new file mode 100644 index 0000000..0cc4e87 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/QuadraticBent.lean @@ -0,0 +1,80 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter05.Quadratic +public import CryptBoolean.Carlet.Chapter06.Bentness + +/-! +# Carlet Chapter 6 quadratic bent functions + +The radical and linear-kernel characterizations of quadratic bent functions. +-/ + +open scoped BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- A quadratic Boolean function is bent exactly when the radical of its polar +form is trivial. -/ +theorem isBent_iff_quadraticRadical_eq_bot + (f : BooleanFunction n) + (hdegree : FABL.functionAlgebraicDegree f ≤ 2) : + IsBent f ↔ quadraticRadical f hdegree = ⊥ := by + constructor + · intro hf + ext a + constructor + · intro ha + have haZero : a = 0 := by + by_contra haNe + have hbalanced := + (isBent_iff_forall_nonzero_derivative_isBalanced f).mp hf a haNe + have hzero := + (isBalanced_iff_walshTransform_zero_eq_zero + (FABL.booleanDerivative f a)).mp hbalanced + rw [booleanDerivative_eq_const_of_mem_quadraticRadical + f hdegree a ha] at hzero + have hconstant : + (fun _ : FABL.F₂Cube n ↦ f a + f 0) = + FABL.affineFunction (f a + f 0) 0 := by + funext x + simp [FABL.affineFunction, FABL.f₂DotProduct] + rw [hconstant, walshTransform_affineFunction] at hzero + simp only [if_pos] at hzero + have hsign : bitSignInt (f a + f 0) ≠ 0 := by + rw [bitSignInt_eq_if_one] + split <;> norm_num + have hpow : (2 ^ n : ℤ) ≠ 0 := pow_ne_zero n (by norm_num) + exact (mul_ne_zero hsign hpow) hzero + simp [haZero] + · intro ha + have haZero : a = 0 := by simpa using ha + subst a + exact Submodule.zero_mem _ + · intro hradical + apply (isBent_iff_forall_nonzero_derivative_isBalanced f).mpr + intro a ha + apply isBalanced_booleanDerivative_of_not_mem_quadraticRadical + f hdegree a + intro hmem + rw [hradical] at hmem + exact ha (by simpa using hmem) + +/-- A quadratic Boolean function is bent exactly when its linear kernel is +trivial. -/ +theorem isBent_iff_linearKernel_eq_bot_of_degree_le_two + (f : BooleanFunction n) + (hdegree : FABL.functionAlgebraicDegree f ≤ 2) : + IsBent f ↔ linearKernel f = ⊥ := by + simpa only [quadraticRadical_eq_linearKernel f hdegree] using + (isBent_iff_quadraticRadical_eq_bot f hdegree) + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/Rothaus.lean b/CryptBoolean/Carlet/Chapter06/Rothaus.lean new file mode 100644 index 0000000..fec2c62 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/Rothaus.lean @@ -0,0 +1,235 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.NestedBent +public import CryptBoolean.Carlet.Chapter06.ThreeFunctionBent + +/-! +# The Dillon--Rothaus construction + +Carlet Section 6.4.2: the two-variable secondary construction from four bent +functions. +-/ + +open Finset +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The Dillon--Rothaus function, with the two new coordinates forming the +first block. -/ +def rothausConstruction + (g h k : BooleanFunction n) : BooleanFunction (2 + n) := + fun z ↦ + let p := (Fin.appendEquiv 2 n).symm z + let u := p.1 + let x := p.2 + g x * h x + g x * k x + h x * k x + + (g x + h x) * u 0 + (g x + k x) * u 1 + u 0 * u 1 + +@[simp] theorem rothausConstruction_append + (g h k : BooleanFunction n) + (u : FABL.F₂Cube 2) (x : FABL.F₂Cube n) : + rothausConstruction g h k (Fin.append u x) = + g x * h x + g x * k x + h x * k x + + (g x + h x) * u 0 + (g x + k x) * u 1 + u 0 * u 1 := by + simp [rothausConstruction] + +private def rothausTwoBitQuadratic + (c a b : FABL.𝔽₂) : BooleanFunction 2 := + fun u ↦ c + a * u 0 + b * u 1 + u 0 * u 1 + +private theorem sum_bitSignInt_rothausTwoBitQuadratic + (c a b p q : FABL.𝔽₂) : + (∑ x₁ : FABL.𝔽₂, ∑ x₂ : FABL.𝔽₂, + bitSignInt + (c + a * x₁ + b * x₂ + x₁ * x₂ + p * x₁ + q * x₂)) = + 2 * bitSignInt (c + (a + p) * (b + q)) := by + fin_cases c <;> fin_cases a <;> fin_cases b <;> + fin_cases p <;> fin_cases q <;> decide + +private theorem walshTransform_rothausTwoBitQuadratic + (c a b : FABL.𝔽₂) (s : FABL.F₂Cube 2) : + walshTransform (rothausTwoBitQuadratic c a b) s = + 2 * bitSignInt (c + (a + s 0) * (b + s 1)) := by + rw [walshTransform] + calc + ∑ u : FABL.F₂Cube 2, + walshTerm (rothausTwoBitQuadratic c a b) s u = + ∑ p : FABL.𝔽₂ × FABL.𝔽₂, + walshTerm (rothausTwoBitQuadratic c a b) s ![p.1, p.2] := by + exact Fintype.sum_equiv (finTwoArrowEquiv FABL.𝔽₂) + (fun u ↦ walshTerm (rothausTwoBitQuadratic c a b) s u) + (fun p ↦ walshTerm + (rothausTwoBitQuadratic c a b) s ![p.1, p.2]) + (fun u ↦ by + have hu : + ![((finTwoArrowEquiv FABL.𝔽₂) u).1, + ((finTwoArrowEquiv FABL.𝔽₂) u).2] = u := by + simpa only [finTwoArrowEquiv_symm_apply] using + (finTwoArrowEquiv FABL.𝔽₂).symm_apply_apply u + rw [hu]) + _ = ∑ x₁ : FABL.𝔽₂, ∑ x₂ : FABL.𝔽₂, + bitSignInt + (c + a * x₁ + b * x₂ + x₁ * x₂ + + s 0 * x₁ + s 1 * x₂) := by + rw [Fintype.sum_prod_type] + apply Finset.sum_congr rfl + intro x₁ _hx₁ + apply Finset.sum_congr rfl + intro x₂ _hx₂ + simp [walshTerm, rothausTwoBitQuadratic, + FABL.f₂DotProduct, dotProduct, Fin.sum_univ_two] + congr 1 + abel + _ = 2 * bitSignInt (c + (a + s 0) * (b + s 1)) := + sum_bitSignInt_rothausTwoBitQuadratic c a b (s 0) (s 1) + +private theorem isBent_rothausTwoBitQuadratic + (c a b : FABL.𝔽₂) : + IsBent (rothausTwoBitQuadratic c a b) := by + apply (isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half _).mpr + intro s + rw [walshTransform_rothausTwoBitQuadratic, Int.natAbs_mul] + have hsign : + (bitSignInt (c + (a + s 0) * (b + s 1))).natAbs = 1 := by + rw [bitSignInt_eq_if_one] + split <;> simp + rw [hsign] + norm_num + +private theorem bentDual_rothausTwoBitQuadratic + (c a b : FABL.𝔽₂) (s : FABL.F₂Cube 2) : + bentDual (rothausTwoBitQuadratic c a b) s = + c + (a + s 0) * (b + s 1) := by + rw [bentDual, walshTransform_rothausTwoBitQuadratic] + by_cases hvalue : c + (a + s 0) * (b + s 1) = 1 + · rw [hvalue] + norm_num [bitSignInt_eq_if_one] + · have hzero : c + (a + s 0) * (b + s 1) = 0 := by + by_contra hne + exact hvalue (Fin.eq_one_of_ne_zero _ hne) + rw [hzero] + norm_num [bitSignInt_eq_if_one] + +private theorem firstBlockSlice_rothausConstruction + (g h k : BooleanFunction n) (x : FABL.F₂Cube n) : + firstBlockSlice (rothausConstruction g h k) x = + rothausTwoBitQuadratic + (g x * h x + g x * k x + h x * k x) + (g x + h x) (g x + k x) := by + funext u + simp [firstBlockSlice, rothausTwoBitQuadratic] + +private theorem dualSliceFunction_rothausConstruction + (g h k : BooleanFunction n) (s : FABL.F₂Cube 2) : + dualSliceFunction (rothausConstruction g h k) s = + fun x ↦ + g x * h x + g x * k x + h x * k x + + (g x + h x + s 0) * (g x + k x + s 1) := by + funext x + rw [dualSliceFunction, firstBlockSlice_rothausConstruction, + bentDual_rothausTwoBitQuadratic] + +private theorem rothausDual_zero_zero + (g h k : FABL.𝔽₂) : + g * h + g * k + h * k + (g + h) * (g + k) = g := by + fin_cases g <;> fin_cases h <;> fin_cases k <;> decide + +private theorem rothausDual_one_zero + (g h k : FABL.𝔽₂) : + g * h + g * k + h * k + (g + h + 1) * (g + k) = k := by + fin_cases g <;> fin_cases h <;> fin_cases k <;> decide + +private theorem rothausDual_zero_one + (g h k : FABL.𝔽₂) : + g * h + g * k + h * k + (g + h) * (g + k + 1) = h := by + fin_cases g <;> fin_cases h <;> fin_cases k <;> decide + +private theorem rothausDual_one_one + (g h k : FABL.𝔽₂) : + g * h + g * k + h * k + (g + h + 1) * (g + k + 1) = + g + h + k + 1 := by + fin_cases g <;> fin_cases h <;> fin_cases k <;> decide + +private theorem isBent_dualSliceFunction_rothausConstruction + (g h k : BooleanFunction n) + (hg : IsBent g) (hh : IsBent h) (hk : IsBent k) + (hsum : IsBent (threeFunctionSum g h k)) + (s : FABL.F₂Cube 2) : + IsBent (dualSliceFunction (rothausConstruction g h k) s) := by + rw [dualSliceFunction_rothausConstruction] + by_cases hs₀ : s 0 = 0 + · by_cases hs₁ : s 1 = 0 + · have heq : + (fun x ↦ + g x * h x + g x * k x + h x * k x + + (g x + h x + s 0) * (g x + k x + s 1)) = g := by + funext x + rw [hs₀, hs₁] + simpa using rothausDual_zero_zero (g x) (h x) (k x) + rw [heq] + exact hg + · have hs₁One : s 1 = 1 := Fin.eq_one_of_ne_zero _ hs₁ + have heq : + (fun x ↦ + g x * h x + g x * k x + h x * k x + + (g x + h x + s 0) * (g x + k x + s 1)) = h := by + funext x + rw [hs₀, hs₁One] + simpa using rothausDual_zero_one (g x) (h x) (k x) + rw [heq] + exact hh + · have hs₀One : s 0 = 1 := Fin.eq_one_of_ne_zero _ hs₀ + by_cases hs₁ : s 1 = 0 + · have heq : + (fun x ↦ + g x * h x + g x * k x + h x * k x + + (g x + h x + s 0) * (g x + k x + s 1)) = k := by + funext x + rw [hs₀One, hs₁] + simpa using rothausDual_one_zero (g x) (h x) (k x) + rw [heq] + exact hk + · have hs₁One : s 1 = 1 := Fin.eq_one_of_ne_zero _ hs₁ + have heq : + (fun x ↦ + g x * h x + g x * k x + h x * k x + + (g x + h x + s 0) * (g x + k x + s 1)) = + threeFunctionSum g h k + FABL.affineFunction 1 0 := by + funext x + rw [hs₀One, hs₁One] + simp only [threeFunctionSum, Pi.add_apply, FABL.affineFunction, + FABL.f₂DotProduct, zero_dotProduct, add_zero] + exact rothausDual_one_one (g x) (h x) (k x) + rw [heq] + exact (isBent_add_affineFunction_iff + (threeFunctionSum g h k) 1 0).mpr hsum + +/-- The Dillon--Rothaus secondary construction is bent when `g`, `h`, `k`, +and `g + h + k` are bent. -/ +theorem isBent_rothausConstruction + (g h k : BooleanFunction n) + (hnEven : Even n) (_hnTwo : 2 ≤ n) + (hg : IsBent g) (hh : IsBent h) (hk : IsBent k) + (hsum : IsBent (threeFunctionSum g h k)) : + IsBent (rothausConstruction g h k) := by + have hslices : + ∀ x, IsBent (firstBlockSlice (rothausConstruction g h k) x) := by + intro x + rw [firstBlockSlice_rothausConstruction] + exact isBent_rothausTwoBitQuadratic _ _ _ + apply (isBent_iff_forall_isBent_dualSliceFunction + (rothausConstruction g h k) (by norm_num) hnEven hslices).mpr + exact isBent_dualSliceFunction_rothausConstruction + g h k hg hh hk hsum + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/SecondOrderCharacterization.lean b/CryptBoolean/Carlet/Chapter06/SecondOrderCharacterization.lean new file mode 100644 index 0000000..9ad9241 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/SecondOrderCharacterization.lean @@ -0,0 +1,252 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter04.AutocorrelationBounds +public import CryptBoolean.Carlet.Chapter04.AutocorrelationIdentities +public import CryptBoolean.Carlet.Chapter06.Bentness + +/-! +# Carlet Chapter 6 second-order characterization + +Carlet Proposition 24 and relation (52), in derivative, convolution, and Walsh forms. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The double sum of the signs of all second derivatives at a fixed point. -/ +noncomputable def secondDerivativeDoubleSum + (f : BooleanFunction n) (x : FABL.F₂Cube n) : ℝ := + ∑ a, ∑ e, realSignView (secondBooleanDerivative f a e) x + +/-- The unnormalized threefold additive convolution of a real cube function. -/ +noncomputable def rawTripleConvolution + (φ : FABL.F₂Cube n → ℝ) : FABL.F₂Cube n → ℝ := + rawConvolution φ (rawConvolution φ φ) + +/-- The fixed-point second-derivative sum is the sign view times its threefold +raw convolution. -/ +theorem secondDerivativeDoubleSum_eq_mul_rawTripleConvolution + (f : BooleanFunction n) (x : FABL.F₂Cube n) : + secondDerivativeDoubleSum f x = + realSignView f x * rawTripleConvolution (realSignView f) x := by + classical + calc + secondDerivativeDoubleSum f x = + ∑ a, ∑ e, realSignView f x * realSignView f a * + realSignView f e * realSignView f (x + a + e) := by + rw [secondDerivativeDoubleSum] + simp_rw [secondBooleanDerivative, realSignView_booleanDerivative] + rw [← Equiv.sum_comp (Equiv.addRight x)] + apply Finset.sum_congr rfl + intro a _ha + rw [← Equiv.sum_comp (Equiv.addRight x)] + apply Finset.sum_congr rfl + intro e _he + have hx : x + x = 0 := ZModModule.add_self x + rw [show (Equiv.addRight x) a = a + x by rfl, + show (Equiv.addRight x) e = e + x by rfl] + rw [show x + (a + x) = a by + calc + x + (a + x) = (x + x) + a := by ac_rfl + _ = a := by rw [hx, zero_add]] + rw [show x + (e + x) = e by + calc + x + (e + x) = (x + x) + e := by ac_rfl + _ = e := by rw [hx, zero_add]] + rw [show a + (e + x) = x + a + e by abel] + ring + _ = realSignView f x * rawTripleConvolution (realSignView f) x := by + unfold rawTripleConvolution rawConvolution + rw [Finset.mul_sum] + apply Finset.sum_congr rfl + intro a _ha + rw [Finset.mul_sum, Finset.mul_sum] + apply Finset.sum_congr rfl + intro e _he + ring + +/-- The raw Fourier transform sends threefold raw convolution to a cube. -/ +theorem rawFourierTransform_rawTripleConvolution + (φ : FABL.F₂Cube n → ℝ) (u : FABL.F₂Cube n) : + rawFourierTransform (rawTripleConvolution φ) u = + rawFourierTransform φ u ^ 3 := by + rw [rawTripleConvolution, rawFourierTransform_rawConvolution, + rawFourierTransform_rawConvolution] + ring + +theorem rawFourierTransform_const_mul_realSignView + (f : BooleanFunction n) (c : ℝ) (u : FABL.F₂Cube n) : + rawFourierTransform + (fun x ↦ c * realSignView f x) u = + c * (walshTransform f u : ℝ) := by + rw [rawFourierTransform] + calc + (∑ x, c * realSignView f x * + FABL.vectorWalshCharacter u x) = + c * ∑ x, realSignView f x * + FABL.vectorWalshCharacter u x := by + rw [Finset.mul_sum] + apply Finset.sum_congr rfl + intro x _hx + ring + _ = c * (walshTransform f u : ℝ) := by + rw [walshTransform_cast_eq_sum_realSignView_mul_character] + +theorem eq_of_rawFourierTransform_eq + (φ ψ : FABL.F₂Cube n → ℝ) + (h : rawFourierTransform φ = rawFourierTransform ψ) : + φ = ψ := by + funext x + have hx := congrArg (fun θ ↦ rawFourierTransform θ x) h + rw [rawFourierTransform_involution, rawFourierTransform_involution] at hx + exact mul_left_cancel₀ (by positivity : (2 : ℝ) ^ n ≠ 0) hx + +private theorem walshTransform_cube_eq_of_isBent + (f : BooleanFunction n) (hf : IsBent f) (u : FABL.F₂Cube n) : + (walshTransform f u : ℝ) ^ 3 = + (2 : ℝ) ^ n * (walshTransform f u : ℝ) := by + have hflat := (hasFlatWalshSpectrum_iff_isBent f).2 hf u + have hsquare := congrArg (fun r : ℝ ↦ r ^ 2) hflat + rw [sq_abs, Real.sq_sqrt (by positivity)] at hsquare + calc + (walshTransform f u : ℝ) ^ 3 = + (walshTransform f u : ℝ) ^ 2 * (walshTransform f u : ℝ) := by ring + _ = (2 : ℝ) ^ n * (walshTransform f u : ℝ) := by rw [hsquare] + +private theorem rawTripleConvolution_realSignView_eq_of_isBent + (f : BooleanFunction n) (hf : IsBent f) : + rawTripleConvolution (realSignView f) = + fun x ↦ (2 : ℝ) ^ n * realSignView f x := by + apply eq_of_rawFourierTransform_eq + funext u + rw [rawFourierTransform_rawTripleConvolution, + rawFourierTransform_const_mul_realSignView] + have hwalsh : rawFourierTransform (realSignView f) u = + (walshTransform f u : ℝ) := by + simpa [rawFourierTransform] using + (walshTransform_cast_eq_sum_realSignView_mul_character f u).symm + rw [hwalsh] + exact walshTransform_cube_eq_of_isBent f hf u + +/-- Carlet Proposition 24: bentness is equivalent to the fixed-point double +sum of second-derivative signs being exactly `2^n` at every point. -/ +theorem isBent_iff_forall_secondDerivativeDoubleSum_eq_two_pow + (f : BooleanFunction n) : + IsBent f ↔ + ∀ x : FABL.F₂Cube n, + secondDerivativeDoubleSum f x = (2 : ℝ) ^ n := by + constructor + · intro hf x + rw [secondDerivativeDoubleSum_eq_mul_rawTripleConvolution, + rawTripleConvolution_realSignView_eq_of_isBent f hf] + calc + realSignView f x * ((2 : ℝ) ^ n * realSignView f x) = + (2 : ℝ) ^ n * (realSignView f x * realSignView f x) := by ring + _ = (2 : ℝ) ^ n := by rw [realSignView_mul_self, mul_one] + · intro h + apply (isBent_iff_forall_nonzero_derivative_isBalanced f).2 + apply (sumOfSquaresIndicator_eq_two_pow_iff f).1 + rw [sumOfSquaresIndicator_eq_sum_secondBooleanDerivative] + calc + (∑ a, ∑ e, ∑ x, + realSignView (secondBooleanDerivative f a e) x) = + ∑ a, ∑ x, ∑ e, + realSignView (secondBooleanDerivative f a e) x := by + apply Finset.sum_congr rfl + intro a _ha + exact Finset.sum_comm + _ = ∑ x, ∑ a, ∑ e, + realSignView (secondBooleanDerivative f a e) x := + Finset.sum_comm + _ = ∑ x, secondDerivativeDoubleSum f x := by + rfl + _ = ∑ _x : FABL.F₂Cube n, (2 : ℝ) ^ n := by + apply Finset.sum_congr rfl + intro x _hx + exact h x + _ = (2 : ℝ) ^ (2 * n) := by + rw [Finset.sum_const, Finset.card_univ, card_f₂Cube, + nsmul_eq_mul] + norm_num + rw [← pow_add] + congr 1 + omega + +/-- At a fixed point, the second-derivative sum condition is equivalent to +the corresponding value of the threefold raw convolution. -/ +theorem secondDerivativeDoubleSum_eq_two_pow_iff_rawTripleConvolution_eq + (f : BooleanFunction n) (x : FABL.F₂Cube n) : + secondDerivativeDoubleSum f x = (2 : ℝ) ^ n ↔ + rawTripleConvolution (realSignView f) x = + (2 : ℝ) ^ n * realSignView f x := by + rw [secondDerivativeDoubleSum_eq_mul_rawTripleConvolution] + constructor + · intro h + calc + rawTripleConvolution (realSignView f) x = + 1 * rawTripleConvolution (realSignView f) x := by ring + _ = (realSignView f x * realSignView f x) * + rawTripleConvolution (realSignView f) x := by + rw [realSignView_mul_self] + _ = realSignView f x * + (realSignView f x * rawTripleConvolution (realSignView f) x) := by ring + _ = realSignView f x * (2 : ℝ) ^ n := by rw [h] + _ = (2 : ℝ) ^ n * realSignView f x := by ring + · intro h + calc + realSignView f x * rawTripleConvolution (realSignView f) x = + realSignView f x * ((2 : ℝ) ^ n * realSignView f x) := by rw [h] + _ = (2 : ℝ) ^ n * (realSignView f x * realSignView f x) := by ring + _ = (2 : ℝ) ^ n := by rw [realSignView_mul_self, mul_one] + +/-- Bentness is equivalent to the threefold raw convolution eigenvalue +identity for the sign view. -/ +theorem isBent_iff_rawTripleConvolution_realSignView_eq + (f : BooleanFunction n) : + IsBent f ↔ + rawTripleConvolution (realSignView f) = + fun x ↦ (2 : ℝ) ^ n * realSignView f x := by + constructor + · exact rawTripleConvolution_realSignView_eq_of_isBent f + · intro h + apply (isBent_iff_forall_secondDerivativeDoubleSum_eq_two_pow f).2 + intro x + apply + (secondDerivativeDoubleSum_eq_two_pow_iff_rawTripleConvolution_eq f x).2 + exact congrFun h x + +/-- The frequency-domain form of Proposition 24: bentness is equivalent to +the cubic raw Walsh identity at every frequency. -/ +theorem isBent_iff_forall_walshTransform_cube_eq + (f : BooleanFunction n) : + IsBent f ↔ + ∀ u : FABL.F₂Cube n, + walshTransform f u ^ 3 = + (2 ^ n : ℤ) * walshTransform f u := by + constructor + · intro hf u + exact_mod_cast walshTransform_cube_eq_of_isBent f hf u + · intro h + apply (isBent_iff_rawTripleConvolution_realSignView_eq f).2 + apply eq_of_rawFourierTransform_eq + funext u + rw [rawFourierTransform_rawTripleConvolution, + rawFourierTransform_const_mul_realSignView] + have hwalsh : rawFourierTransform (realSignView f) u = + (walshTransform f u : ℝ) := by + simpa [rawFourierTransform] using + (walshTransform_cast_eq_sum_realSignView_mul_character f u).symm + rw [hwalsh] + exact_mod_cast h u + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/SupportCode.lean b/CryptBoolean/Carlet/Chapter06/SupportCode.lean new file mode 100644 index 0000000..f3a9522 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/SupportCode.lean @@ -0,0 +1,495 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter04.SupportDualDistance +public import CryptBoolean.Carlet.Chapter06.Dual + +/-! +# The linear code carried by the support of a Boolean function + +Carlet Proposition 16: the support-column code characterizes bent functions. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The codeword obtained by evaluating the linear form `x ↦ v · x` on the +support of `f`. -/ +def supportCodeMap (f : BooleanFunction n) : + FABL.F₂Cube n →ₗ[FABL.𝔽₂] (↥(support f) → FABL.𝔽₂) where + toFun v x := FABL.f₂DotProduct v x.1 + map_add' v w := by + funext x + exact add_dotProduct v w x.1 + map_smul' c v := by + funext x + exact smul_dotProduct c v x.1 + +/-- The support-column linear code generated by the coordinate rows of the +support matrix. -/ +def supportCode (f : BooleanFunction n) : + Submodule FABL.𝔽₂ (↥(support f) → FABL.𝔽₂) := + LinearMap.range (supportCodeMap f) + +/-- The Hamming weight of the support-code word indexed by `v`. -/ +def supportCodewordWeight (f : BooleanFunction n) (v : FABL.F₂Cube n) : ℕ := + hammingNorm (supportCodeMap f v) + +/-- The support-code word indexed by zero has weight zero. -/ +@[simp] theorem supportCodewordWeight_zero (f : BooleanFunction n) : + supportCodewordWeight f 0 = 0 := by + simp [supportCodewordWeight] + +/-- A support-code word counts support points on which its defining linear +form is one. -/ +theorem supportCodewordWeight_eq_card_filter + (f : BooleanFunction n) (v : FABL.F₂Cube n) : + supportCodewordWeight f v = + ((support f).filter fun x ↦ FABL.f₂DotProduct v x = 1).card := by + classical + rw [supportCodewordWeight, hammingNorm, Finset.univ_eq_attach] + apply Finset.card_bij (fun x _hx ↦ x.1) + · intro x hx + rw [Finset.mem_filter] at hx ⊢ + exact ⟨x.2, Fin.eq_one_of_ne_zero _ hx.2⟩ + · intro x _hx y _hy hxy + exact Subtype.ext hxy + · intro x hx + refine ⟨⟨x, (Finset.mem_filter.mp hx).1⟩, ?_, rfl⟩ + rw [Finset.mem_filter] + refine ⟨Finset.mem_attach _ _, ?_⟩ + change FABL.f₂DotProduct v x ≠ 0 + rw [(Finset.mem_filter.mp hx).2] + exact one_ne_zero + +/-- The character sum over the support is its cardinality minus twice the +support-code word weight. -/ +theorem codeCharacterSum_support_eq_card_sub_two_weight + (f : BooleanFunction n) (v : FABL.F₂Cube n) : + codeCharacterSum (support f) v = + ((support f).card : ℝ) - 2 * supportCodewordWeight f v := by + classical + rw [codeCharacterSum, supportCodewordWeight_eq_card_filter] + calc + ∑ x ∈ support f, FABL.vectorWalshCharacter v x = + ∑ x ∈ support f, + (1 - 2 * (if FABL.f₂DotProduct v x = 1 then (1 : ℝ) else 0)) := by + apply Finset.sum_congr rfl + intro x _hx + by_cases hdot : FABL.f₂DotProduct v x = 1 + · simp [FABL.vectorWalshCharacter_apply, hdot] + norm_num + · have hzero : FABL.f₂DotProduct v x = 0 := by + by_contra hne + exact hdot (Fin.eq_one_of_ne_zero _ hne) + simp [FABL.vectorWalshCharacter_apply, hzero] + _ = (support f).card - + 2 * (((support f).filter fun x ↦ + FABL.f₂DotProduct v x = 1).card : ℝ) := by + rw [Finset.sum_sub_distrib] + simp only [Finset.sum_const, nsmul_eq_mul] + rw [← Finset.mul_sum] + simp + +/-- For a nonzero frequency, four times the support-code word weight is the +difference between the corresponding and zero-frequency Walsh coefficients, +shifted by the cube cardinality. -/ +theorem four_mul_supportCodewordWeight_eq + (f : BooleanFunction n) (v : FABL.F₂Cube n) (hv : v ≠ 0) : + (4 : ℤ) * supportCodewordWeight f v = + 2 ^ n + walshTransform f v - walshTransform f 0 := by + have hsupport := codeCharacterSum_support_eq_card_sub_two_weight f v + have hwalsh := + walshTransform_cast_eq_neg_two_mul_codeCharacterSum_support f v hv + have hzero := walshTransform_zero_eq_two_pow_sub_two_weight f + rw [hsupport] at hwalsh + rw [hammingWeight_eq_card_support] at hzero + have hzeroReal := congrArg (fun z : ℤ ↦ (z : ℝ)) hzero + norm_num only [Int.cast_sub, Int.cast_pow, Int.cast_ofNat, Int.cast_mul, + Int.cast_natCast] at hzeroReal + have hreal : + (4 : ℝ) * supportCodewordWeight f v = + (2 : ℝ) ^ n + walshTransform f v - walshTransform f 0 := by + linarith + exact_mod_cast hreal + +/-- The exact two-nonzero-weight condition for the support-column code. -/ +def SupportCodeHasExactlyTwoNonzeroWeights (f : BooleanFunction n) : Prop := + let first := 2 ^ (n - 2) + let second := hammingWeight f - first + (∀ c : supportCode f, c ≠ 0 → + hammingNorm c.1 = first ∨ hammingNorm c.1 = second) ∧ + (∃ c : supportCode f, c ≠ 0 ∧ hammingNorm c.1 = first) ∧ + (∃ c : supportCode f, c ≠ 0 ∧ hammingNorm c.1 = second) + +private theorem finrank_supportCode_eq_n_iff_injective + (f : BooleanFunction n) : + Module.finrank FABL.𝔽₂ (supportCode f) = n ↔ + Function.Injective (supportCodeMap f) := by + constructor + · intro hrank + rw [← LinearMap.ker_eq_bot] + apply Submodule.finrank_eq_zero.mp + have hrankNull := LinearMap.finrank_range_add_finrank_ker (supportCodeMap f) + change Module.finrank FABL.𝔽₂ (supportCode f) + + Module.finrank FABL.𝔽₂ (LinearMap.ker (supportCodeMap f)) = _ at hrankNull + rw [hrank] at hrankNull + simpa using hrankNull + · intro hinjective + change Module.finrank FABL.𝔽₂ (LinearMap.range (supportCodeMap f)) = n + rw [LinearMap.finrank_range_of_inj hinjective] + simp + +private theorem nonlinearity_le_hammingWeight (f : BooleanFunction n) : + nonlinearity f ≤ hammingWeight f := by + unfold nonlinearity + have hle := Finset.inf'_le + (fun p : FABL.𝔽₂ × FABL.F₂Cube n ↦ + hammingDistance f (FABL.affineFunction p.1 p.2)) + (Finset.mem_univ (0, 0)) + have hzero : + FABL.affineFunction (0 : FABL.𝔽₂) (0 : FABL.F₂Cube n) = 0 := by + funext x + simp [FABL.affineFunction, FABL.f₂DotProduct] + rw [hzero] at hle + simpa [hammingDistance_eq_hammingWeight_add] using hle + +private theorem two_pow_sub_two_lt_hammingWeight_of_isBent + (f : BooleanFunction n) (hf : IsBent f) (hnEven : Even n) (hn : 4 ≤ n) : + 2 ^ (n - 2) < hammingWeight f := by + have hnonlinearity := + nonlinearity_eq_two_pow_sub_two_pow_half_of_isBent f hf (by omega) + have hle := nonlinearity_le_hammingWeight f + have hexponents : n / 2 - 1 < n - 2 := by + rcases hnEven with ⟨k, rfl⟩ + omega + have hpowers : 2 ^ (n / 2 - 1) < 2 ^ (n - 2) := + Nat.pow_lt_pow_right (by omega) hexponents + have hsplit : 2 ^ (n - 1) = 2 * 2 ^ (n - 2) := by + rw [show n - 1 = (n - 2) + 1 by omega, pow_succ] + exact Nat.mul_comm _ _ + have hfirst : 2 ≤ 2 ^ (n - 2) := by + have hexponent : 1 ≤ n - 2 := by omega + simpa using + (Nat.pow_le_pow_right (n := 2) (by omega : 0 < 2) hexponent) + omega + +private theorem exists_nonzero_eq_one_of_isBent + (f : BooleanFunction n) (hf : IsBent f) (hnEven : Even n) (hn : 4 ≤ n) : + ∃ v : FABL.F₂Cube n, v ≠ 0 ∧ f v = 1 := by + have hcard : 1 < (support f).card := by + rw [← hammingWeight_eq_card_support] + have hfirst := + two_pow_sub_two_lt_hammingWeight_of_isBent f hf hnEven hn + have hfirstTwo : 2 ≤ 2 ^ (n - 2) := by + have hexponent : 1 ≤ n - 2 := by omega + simpa using + (Nat.pow_le_pow_right (n := 2) (by omega : 0 < 2) hexponent) + omega + obtain ⟨v, hv, hvzero⟩ := Finset.exists_mem_ne hcard (0 : FABL.F₂Cube n) + exact ⟨v, hvzero, (mem_support f v).mp hv⟩ + +private theorem exists_nonzero_eq_zero_of_isBent + (f : BooleanFunction n) (hf : IsBent f) (hnEven : Even n) (hn : 4 ≤ n) : + ∃ v : FABL.F₂Cube n, v ≠ 0 ∧ f v = 0 := by + have hfComplement : IsBent (f + 1) := by + have hone : + FABL.affineFunction (1 : FABL.𝔽₂) (0 : FABL.F₂Cube n) = 1 := by + funext x + simp [FABL.affineFunction, FABL.f₂DotProduct] + rw [← hone] + exact (isBent_add_affineFunction_iff f 1 0).mpr hf + obtain ⟨v, hvzero, hvone⟩ := + exists_nonzero_eq_one_of_isBent (f + 1) hfComplement hnEven hn + refine ⟨v, hvzero, ?_⟩ + simp only [Pi.add_apply, Pi.one_apply] at hvone + apply add_right_cancel (b := (1 : FABL.𝔽₂)) + simpa using hvone + +private theorem supportCodewordWeight_eq_first_or_second_of_isBent + (f : BooleanFunction n) (hf : IsBent f) (hn : 4 ≤ n) + (v : FABL.F₂Cube n) (hv : v ≠ 0) : + supportCodewordWeight f v = 2 ^ (n - 2) ∨ + supportCodewordWeight f v = hammingWeight f - 2 ^ (n - 2) := by + have hfour := four_mul_supportCodewordWeight_eq f v hv + have habs : (walshTransform f v).natAbs = (walshTransform f 0).natAbs := by + rw [natAbs_walshTransform_eq_two_pow_half_of_isBent f hf v, + natAbs_walshTransform_eq_two_pow_half_of_isBent f hf 0] + have hsplit : (2 : ℤ) ^ n = 4 * (2 ^ (n - 2) : ℤ) := by + rw [show n = (n - 2) + 2 by omega, pow_add] + norm_num + ring + rcases Int.natAbs_eq_natAbs_iff.mp habs with heq | hneg + · left + rw [heq] at hfour + exact_mod_cast (by omega : + (supportCodewordWeight f v : ℤ) = 2 ^ (n - 2)) + · right + have hzero := walshTransform_zero_eq_two_pow_sub_two_weight f + rw [hneg, hzero] at hfour + have hnat : + 4 * supportCodewordWeight f v + 2 ^ n = 4 * hammingWeight f := by + exact_mod_cast (by omega : + (4 : ℤ) * supportCodewordWeight f v + 2 ^ n = + 4 * hammingWeight f) + have hsplitNat : 2 ^ n = 4 * 2 ^ (n - 2) := by + exact_mod_cast hsplit + omega + +private theorem exists_nonzero_walshTransform_eq_zeroFrequency_of_isBent + (f : BooleanFunction n) (hf : IsBent f) (hnEven : Even n) (hn : 4 ≤ n) : + ∃ v : FABL.F₂Cube n, v ≠ 0 ∧ + walshTransform f v = walshTransform f 0 := by + let d := bentDual f + obtain ⟨vOne, hvOne, hdOne⟩ := + exists_nonzero_eq_one_of_isBent d (isBent_bentDual f hf) hnEven hn + obtain ⟨vZero, hvZero, hdZero⟩ := + exists_nonzero_eq_zero_of_isBent d (isBent_bentDual f hf) hnEven hn + change bentDual f vOne = 1 at hdOne + change bentDual f vZero = 0 at hdZero + by_cases hd0 : d 0 = 1 + · change bentDual f 0 = 1 at hd0 + refine ⟨vOne, hvOne, ?_⟩ + rw [walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf vOne, + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf 0, + hdOne, hd0] + · have hd0Zero : bentDual f 0 = 0 := by + by_contra hzero + exact hd0 (show d 0 = 1 from Fin.eq_one_of_ne_zero _ hzero) + refine ⟨vZero, hvZero, ?_⟩ + rw [walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf vZero, + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf 0, + hdZero, hd0Zero] + +private theorem exists_nonzero_walshTransform_eq_neg_zeroFrequency_of_isBent + (f : BooleanFunction n) (hf : IsBent f) (hnEven : Even n) (hn : 4 ≤ n) : + ∃ v : FABL.F₂Cube n, v ≠ 0 ∧ + walshTransform f v = -walshTransform f 0 := by + let d := bentDual f + obtain ⟨vOne, hvOne, hdOne⟩ := + exists_nonzero_eq_one_of_isBent d (isBent_bentDual f hf) hnEven hn + obtain ⟨vZero, hvZero, hdZero⟩ := + exists_nonzero_eq_zero_of_isBent d (isBent_bentDual f hf) hnEven hn + change bentDual f vOne = 1 at hdOne + change bentDual f vZero = 0 at hdZero + by_cases hd0 : d 0 = 1 + · change bentDual f 0 = 1 at hd0 + refine ⟨vZero, hvZero, ?_⟩ + rw [walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf vZero, + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf 0, + hdZero, hd0] + simp [bitSignInt] + · have hd0Zero : bentDual f 0 = 0 := by + by_contra hzero + exact hd0 (show d 0 = 1 from Fin.eq_one_of_ne_zero _ hzero) + refine ⟨vOne, hvOne, ?_⟩ + rw [walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf vOne, + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f hf 0, + hdOne, hd0Zero] + simp [bitSignInt] + +private theorem supportCodewordWeight_eq_first_of_walshTransform_eq + (f : BooleanFunction n) (hn : 4 ≤ n) + (v : FABL.F₂Cube n) (hv : v ≠ 0) + (hwalsh : walshTransform f v = walshTransform f 0) : + supportCodewordWeight f v = 2 ^ (n - 2) := by + have hfour := four_mul_supportCodewordWeight_eq f v hv + rw [hwalsh] at hfour + have hsplit : (2 : ℤ) ^ n = 4 * (2 ^ (n - 2) : ℤ) := by + rw [show n = (n - 2) + 2 by omega, pow_add] + norm_num + ring + exact_mod_cast (by omega : + (supportCodewordWeight f v : ℤ) = 2 ^ (n - 2)) + +private theorem supportCodewordWeight_eq_second_of_walshTransform_eq_neg + (f : BooleanFunction n) (hn : 4 ≤ n) + (v : FABL.F₂Cube n) (hv : v ≠ 0) + (hwalsh : walshTransform f v = -walshTransform f 0) + (hfirst : 2 ^ (n - 2) ≤ hammingWeight f) : + supportCodewordWeight f v = hammingWeight f - 2 ^ (n - 2) := by + have hfour := four_mul_supportCodewordWeight_eq f v hv + have hzero := walshTransform_zero_eq_two_pow_sub_two_weight f + rw [hwalsh, hzero] at hfour + have hnat : + 4 * supportCodewordWeight f v + 2 ^ n = 4 * hammingWeight f := by + exact_mod_cast (by omega : + (4 : ℤ) * supportCodewordWeight f v + 2 ^ n = + 4 * hammingWeight f) + have hsplit : 2 ^ n = 4 * 2 ^ (n - 2) := by + rw [show n = (n - 2) + 2 by omega, pow_add] + norm_num + ring + omega + +/-- Carlet Proposition 16, with the necessary correction `n ≥ 4`: a +Boolean function in positive even dimension is bent exactly when its +support-column code has dimension `n` and exactly the two stated nonzero +weights. -/ +theorem isBent_iff_supportCode_finrank_and_two_nonzero_weights + (f : BooleanFunction n) (hnEven : Even n) (hn : 4 ≤ n) : + IsBent f ↔ + Module.finrank FABL.𝔽₂ (supportCode f) = n ∧ + SupportCodeHasExactlyTwoNonzeroWeights f := by + constructor + · intro hf + have hfirstlt := + two_pow_sub_two_lt_hammingWeight_of_isBent f hf hnEven hn + have hinjective : Function.Injective (supportCodeMap f) := by + rw [← LinearMap.ker_eq_bot] + apply le_antisymm + · intro v hv + change v = 0 + have hmap : supportCodeMap f v = 0 := hv + by_contra hvzero + have hweightZero : supportCodewordWeight f v = 0 := by + rw [supportCodewordWeight, hmap, hammingNorm_zero] + rcases supportCodewordWeight_eq_first_or_second_of_isBent + f hf hn v hvzero with hfirst | hsecond + · rw [hweightZero] at hfirst + exact (Nat.ne_of_gt (Nat.two_pow_pos (n - 2))) hfirst.symm + · rw [hweightZero] at hsecond + omega + · exact bot_le + refine ⟨(finrank_supportCode_eq_n_iff_injective f).mpr hinjective, ?_⟩ + refine ⟨?_, ?_, ?_⟩ + · rintro ⟨c, hc⟩ hcne + obtain ⟨v, rfl⟩ := hc + have hv : v ≠ 0 := by + intro hvzero + subst v + apply hcne + apply Subtype.ext + simp + simpa [supportCodewordWeight] using + supportCodewordWeight_eq_first_or_second_of_isBent f hf hn v hv + · obtain ⟨v, hv, hwalsh⟩ := + exists_nonzero_walshTransform_eq_zeroFrequency_of_isBent + f hf hnEven hn + let c : supportCode f := ⟨supportCodeMap f v, ⟨v, rfl⟩⟩ + refine ⟨c, ?_, ?_⟩ + · intro hc + have hvalue : supportCodeMap f v = 0 := by + simpa [c] using congrArg Subtype.val hc + exact hv (hinjective (by simpa using hvalue)) + · exact supportCodewordWeight_eq_first_of_walshTransform_eq + f hn v hv hwalsh + · obtain ⟨v, hv, hwalsh⟩ := + exists_nonzero_walshTransform_eq_neg_zeroFrequency_of_isBent + f hf hnEven hn + let c : supportCode f := ⟨supportCodeMap f v, ⟨v, rfl⟩⟩ + refine ⟨c, ?_, ?_⟩ + · intro hc + have hvalue : supportCodeMap f v = 0 := by + simpa [c] using congrArg Subtype.val hc + exact hv (hinjective (by simpa using hvalue)) + · exact supportCodewordWeight_eq_second_of_walshTransform_eq_neg + f hn v hv hwalsh hfirstlt.le + · rintro ⟨hdimension, hweights⟩ + have hinjective : Function.Injective (supportCodeMap f) := + (finrank_supportCode_eq_n_iff_injective f).mp hdimension + obtain ⟨cSecond, hcSecond, hweightSecond⟩ := hweights.2.2 + have hsecondPositive : 0 < hammingWeight f - 2 ^ (n - 2) := by + rw [← hweightSecond] + exact hammingNorm_pos_iff.mpr (by + intro hzero + apply hcSecond + exact Subtype.ext hzero) + have hfirst : 2 ^ (n - 2) < hammingWeight f := + Nat.sub_pos_iff_lt.mp hsecondPositive + have hwalshSign (v : FABL.F₂Cube n) : + walshTransform f v = walshTransform f 0 ∨ + walshTransform f v = -walshTransform f 0 := by + by_cases hv : v = 0 + · exact Or.inl (by rw [hv]) + · let c : supportCode f := ⟨supportCodeMap f v, ⟨v, rfl⟩⟩ + have hc : c ≠ 0 := by + intro hzero + have hvalue : supportCodeMap f v = 0 := by + simpa [c] using congrArg Subtype.val hzero + exact hv (hinjective (by simpa using hvalue)) + have hword := hweights.1 c hc + change supportCodewordWeight f v = 2 ^ (n - 2) ∨ + supportCodewordWeight f v = hammingWeight f - 2 ^ (n - 2) at hword + have hfour := four_mul_supportCodewordWeight_eq f v hv + have hsplit : (2 : ℤ) ^ n = 4 * (2 ^ (n - 2) : ℤ) := by + rw [show n = (n - 2) + 2 by omega, pow_add] + norm_num + ring + rcases hword with hword | hword + · left + have hwordInt : + (supportCodewordWeight f v : ℤ) = (2 ^ (n - 2) : ℤ) := by + exact_mod_cast hword + rw [hwordInt] at hfour + omega + · right + have hwordInt : + (supportCodewordWeight f v : ℤ) = + (hammingWeight f : ℤ) - (2 ^ (n - 2) : ℤ) := by + calc + (supportCodewordWeight f v : ℤ) = + (hammingWeight f - 2 ^ (n - 2) : ℕ) := by + exact_mod_cast hword + _ = (hammingWeight f : ℤ) - (2 ^ (n - 2) : ℤ) := by + rw [Nat.cast_sub hfirst.le] + norm_num only [Nat.cast_pow, Nat.cast_ofNat] + rw [hwordInt] at hfour + have hzero := walshTransform_zero_eq_two_pow_sub_two_weight f + omega + have hparseval := sum_walshTransform_sq_eq_two_pow_sq f + have hconstantSum : + (∑ v : FABL.F₂Cube n, (walshTransform f v : ℝ) ^ 2) = + (2 : ℝ) ^ n * (walshTransform f 0 : ℝ) ^ 2 := by + calc + (∑ v : FABL.F₂Cube n, (walshTransform f v : ℝ) ^ 2) = + ∑ _v : FABL.F₂Cube n, (walshTransform f 0 : ℝ) ^ 2 := by + apply Finset.sum_congr rfl + intro v _hv + rcases hwalshSign v with heq | hneg + · rw [heq] + · rw [hneg] + norm_num only [Int.cast_neg] + ring + _ = (2 : ℝ) ^ n * (walshTransform f 0 : ℝ) ^ 2 := by + rw [Finset.sum_const, Finset.card_univ, card_f₂Cube, nsmul_eq_mul] + norm_num + have hsquare : + (walshTransform f 0 : ℝ) ^ 2 = (2 : ℝ) ^ n := by + rw [hconstantSum] at hparseval + apply mul_left_cancel₀ (by positivity : (2 : ℝ) ^ n ≠ 0) + calc + (2 : ℝ) ^ n * (walshTransform f 0 : ℝ) ^ 2 = + ((2 : ℝ) ^ n) ^ 2 := hparseval + _ = (2 : ℝ) ^ n * (2 : ℝ) ^ n := by ring + have habsZero : + |(walshTransform f 0 : ℝ)| = (2 : ℝ) ^ (n / 2) := by + apply (sq_eq_sq₀ (abs_nonneg _) (by positivity)).mp + rw [sq_abs, hsquare] + rcases hnEven with ⟨k, rfl⟩ + have hhalf : (k + k) / 2 = k := by omega + rw [hhalf, pow_add] + ring + apply (isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half f).mpr + intro v + have habs : + |(walshTransform f v : ℝ)| = (2 : ℝ) ^ (n / 2) := by + rcases hwalshSign v with heq | hneg + · rw [heq, habsZero] + · rw [hneg] + norm_num only [Int.cast_neg] + rw [abs_neg, habsZero] + apply Nat.cast_injective (R := ℝ) + simpa only [Nat.cast_natAbs, Int.cast_abs, Nat.cast_pow, + Nat.cast_ofNat] using habs + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/ThreeFunctionBent.lean b/CryptBoolean/Carlet/Chapter06/ThreeFunctionBent.lean new file mode 100644 index 0000000..a12a43f --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/ThreeFunctionBent.lean @@ -0,0 +1,184 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.Dual +public import CryptBoolean.Carlet.Chapter06.ThreeFunctionIdentity +public import CryptBoolean.Carlet.Chapter06.WalshCongruence + +/-! +# Bentness from three Boolean functions + +Carlet Corollary 4 for the first two elementary symmetric functions of three +bent Boolean functions. +-/ + +open scoped BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +private theorem bitSignInt_threeFunctionIdentity + (f₁ f₂ f₃ : BooleanFunction n) (a : FABL.F₂Cube n) : + bitSignInt (f₁ a) + bitSignInt (f₂ a) + bitSignInt (f₃ a) = + bitSignInt (threeFunctionSum f₁ f₂ f₃ a) + + 2 * bitSignInt (threeFunctionPairwiseProductSum f₁ f₂ f₃ a) := by + have h := congrFun (bitValueInt_threeFunctionIdentity f₁ f₂ f₃) a + simp only [threeFunctionSum, threeFunctionPairwiseProductSum, + Pi.add_apply, Pi.mul_apply] at h ⊢ + simp_rw [bitSignInt_eq_one_sub_two_mul_bitValueInt] + linarith + +private theorem walshTransform_threeFunctionPairwiseProductSum_eq + (f₁ f₂ f₃ : BooleanFunction n) + (hf₁ : IsBent f₁) (hf₂ : IsBent f₂) (hf₃ : IsBent f₃) + (hsum : IsBent (threeFunctionSum f₁ f₂ f₃)) + (hdual : bentDual (threeFunctionSum f₁ f₂ f₃) = + bentDual f₁ + bentDual f₂ + bentDual f₃) + (a : FABL.F₂Cube n) : + walshTransform (threeFunctionPairwiseProductSum f₁ f₂ f₃) a = + (2 ^ (n / 2) : ℤ) * + bitSignInt + (threeFunctionPairwiseProductSum + (bentDual f₁) (bentDual f₂) (bentDual f₃) a) := by + have hwalsh := walshTransform_threeFunctionIdentity f₁ f₂ f₃ a + rw [walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f₁ hf₁ a, + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f₂ hf₂ a, + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual f₃ hf₃ a, + walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual + (threeFunctionSum f₁ f₂ f₃) hsum a] at hwalsh + have hsign := bitSignInt_threeFunctionIdentity + (bentDual f₁) (bentDual f₂) (bentDual f₃) a + rw [threeFunctionSum, ← hdual] at hsign + have hscaled : + (2 ^ (n / 2) : ℤ) * bitSignInt (bentDual f₁ a) + + (2 ^ (n / 2) : ℤ) * bitSignInt (bentDual f₂ a) + + (2 ^ (n / 2) : ℤ) * bitSignInt (bentDual f₃ a) = + (2 ^ (n / 2) : ℤ) * + bitSignInt (bentDual (threeFunctionSum f₁ f₂ f₃) a) + + 2 * ((2 ^ (n / 2) : ℤ) * + bitSignInt + (threeFunctionPairwiseProductSum + (bentDual f₁) (bentDual f₂) (bentDual f₃) a)) := by + calc + _ = (2 ^ (n / 2) : ℤ) * + (bitSignInt (bentDual f₁ a) + bitSignInt (bentDual f₂ a) + + bitSignInt (bentDual f₃ a)) := by ring + _ = (2 ^ (n / 2) : ℤ) * + (bitSignInt (bentDual (threeFunctionSum f₁ f₂ f₃) a) + + 2 * bitSignInt + (threeFunctionPairwiseProductSum + (bentDual f₁) (bentDual f₂) (bentDual f₃) a)) := by + rw [hsign] + _ = _ := by ring + have htwice : + 2 * walshTransform (threeFunctionPairwiseProductSum f₁ f₂ f₃) a = + 2 * ((2 ^ (n / 2) : ℤ) * + bitSignInt + (threeFunctionPairwiseProductSum + (bentDual f₁) (bentDual f₂) (bentDual f₃) a)) := + add_left_cancel (hwalsh.symm.trans hscaled) + exact mul_left_cancel₀ (by norm_num : (2 : ℤ) ≠ 0) htwice + +/-- Carlet Corollary 4, first assertion: when the dual of the bent sum is the +sum of the three duals, the second elementary symmetric function is bent and +its dual is the second elementary symmetric function of the three duals. -/ +theorem isBent_threeFunctionPairwiseProductSum_and_bentDual_eq + (f₁ f₂ f₃ : BooleanFunction n) + (_hnEven : Even n) (_hnTwo : 2 ≤ n) + (hf₁ : IsBent f₁) (hf₂ : IsBent f₂) (hf₃ : IsBent f₃) + (hsum : IsBent (threeFunctionSum f₁ f₂ f₃)) + (hdual : bentDual (threeFunctionSum f₁ f₂ f₃) = + bentDual f₁ + bentDual f₂ + bentDual f₃) : + IsBent (threeFunctionPairwiseProductSum f₁ f₂ f₃) ∧ + bentDual (threeFunctionPairwiseProductSum f₁ f₂ f₃) = + threeFunctionPairwiseProductSum + (bentDual f₁) (bentDual f₂) (bentDual f₃) := by + have hwalsh (a : FABL.F₂Cube n) := + walshTransform_threeFunctionPairwiseProductSum_eq + f₁ f₂ f₃ hf₁ hf₂ hf₃ hsum hdual a + have hbent : IsBent (threeFunctionPairwiseProductSum f₁ f₂ f₃) := by + apply + (isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half + (threeFunctionPairwiseProductSum f₁ f₂ f₃)).2 + intro a + rw [hwalsh a, Int.natAbs_mul] + rw [bitSignInt_eq_if_one] + split <;> simp + refine ⟨hbent, ?_⟩ + funext a + rw [bentDual, hwalsh a] + by_cases hvalue : + threeFunctionPairwiseProductSum + (bentDual f₁) (bentDual f₂) (bentDual f₃) a = 1 + · have hnegative : ¬ (0 : ℤ) ≤ + (2 ^ (n / 2) : ℤ) * + bitSignInt + (threeFunctionPairwiseProductSum + (bentDual f₁) (bentDual f₂) (bentDual f₃) a) := by + simp [hvalue, bitSignInt_eq_if_one] + rw [if_neg hnegative, hvalue] + · have hzero : + threeFunctionPairwiseProductSum + (bentDual f₁) (bentDual f₂) (bentDual f₃) a = 0 := by + by_contra hne + exact hvalue (Fin.eq_one_of_ne_zero _ hne) + have hnonnegative : (0 : ℤ) ≤ + (2 ^ (n / 2) : ℤ) * + bitSignInt + (threeFunctionPairwiseProductSum + (bentDual f₁) (bentDual f₂) (bentDual f₃) a) := by + simp [hzero, bitSignInt_eq_if_one] + rw [if_pos hnonnegative, hzero] + +/-- Carlet Corollary 4, second assertion: in even dimension at least two, if +every Walsh coefficient of the second elementary symmetric function is +divisible by `2^(n/2)`, then the first elementary symmetric function is bent. -/ +theorem isBent_threeFunctionSum_of_two_pow_half_dvd_walshTransform + (f₁ f₂ f₃ : BooleanFunction n) + (hnEven : Even n) (hnTwo : 2 ≤ n) + (hf₁ : IsBent f₁) (hf₂ : IsBent f₂) (hf₃ : IsBent f₃) + (hdiv : ∀ a : FABL.F₂Cube n, + (2 ^ (n / 2) : ℤ) ∣ + walshTransform (threeFunctionPairwiseProductSum f₁ f₂ f₃) a) : + IsBent (threeFunctionSum f₁ f₂ f₃) := by + apply + (isBent_iff_forall_walshTransform_modeq + (threeFunctionSum f₁ f₂ f₃) hnEven hnTwo).2 + intro a + have hf₁Modeq := + ((isBent_iff_forall_walshTransform_modeq f₁ hnEven hnTwo).1 hf₁) a + have hf₂Modeq := + ((isBent_iff_forall_walshTransform_modeq f₂ hnEven hnTwo).1 hf₂) a + have hf₃Modeq := + ((isBent_iff_forall_walshTransform_modeq f₃ hnEven hnTwo).1 hf₃) a + have hpairwiseModeq : + Int.ModEq (2 ^ (n / 2 + 1)) + (2 * walshTransform + (threeFunctionPairwiseProductSum f₁ f₂ f₃) a) 0 := by + rw [Int.modEq_zero_iff_dvd] + obtain ⟨z, hz⟩ := hdiv a + rw [hz, pow_succ] + refine ⟨z, ?_⟩ + ring + have hsumModeq := (hf₁Modeq.add hf₂Modeq).add hf₃Modeq + have hwalsh := walshTransform_threeFunctionIdentity f₁ f₂ f₃ a + rw [hwalsh] at hsumModeq + have hcleared := hsumModeq.sub hpairwiseModeq + simp only [add_sub_cancel_right, sub_zero] at hcleared + have hperiod : + Int.ModEq (2 ^ (n / 2 + 1)) + ((2 ^ (n / 2) : ℤ) + 2 ^ (n / 2) + 2 ^ (n / 2)) + (2 ^ (n / 2)) := by + rw [Int.modEq_iff_dvd, pow_succ] + refine ⟨-1, ?_⟩ + ring + exact hcleared.trans hperiod + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/ThreeFunctionIdentity.lean b/CryptBoolean/Carlet/Chapter06/ThreeFunctionIdentity.lean new file mode 100644 index 0000000..b64153e --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/ThreeFunctionIdentity.lean @@ -0,0 +1,152 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter05.CoveringSequences +public import FABL.Chapter06.F₂Polynomials.BentDegree + +/-! +# Carlet Chapter 6 three-function identity + +Carlet Proposition 22 and relation (50) for three Boolean functions. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +/-- The first elementary symmetric function of three Boolean functions. -/ +def threeFunctionSum + (f₁ f₂ f₃ : BooleanFunction n) : BooleanFunction n := + f₁ + f₂ + f₃ + +/-- The second elementary symmetric function of three Boolean functions. -/ +def threeFunctionPairwiseProductSum + (f₁ f₂ f₃ : BooleanFunction n) : BooleanFunction n := + f₁ * f₂ + f₁ * f₃ + f₂ * f₃ + +private theorem bitValueInt_threeBitIdentity (b₁ b₂ b₃ : FABL.𝔽₂) : + bitValueInt b₁ + bitValueInt b₂ + bitValueInt b₃ = + bitValueInt (b₁ + b₂ + b₃) + + 2 * bitValueInt (b₁ * b₂ + b₁ * b₃ + b₂ * b₃) := by + fin_cases b₁ <;> fin_cases b₂ <;> fin_cases b₃ <;> + decide + +/-- Carlet Proposition 22: the ordinary integer sum of three bits is their +first elementary symmetric function plus twice their second. -/ +theorem bitValueInt_threeFunctionIdentity + (f₁ f₂ f₃ : BooleanFunction n) : + (fun x ↦ bitValueInt (f₁ x) + bitValueInt (f₂ x) + bitValueInt (f₃ x)) = + fun x ↦ bitValueInt (threeFunctionSum f₁ f₂ f₃ x) + + 2 * bitValueInt (threeFunctionPairwiseProductSum f₁ f₂ f₃ x) := by + funext x + simpa [threeFunctionSum, threeFunctionPairwiseProductSum] using + bitValueInt_threeBitIdentity (f₁ x) (f₂ x) (f₃ x) + +private theorem booleanRealEmbedding_threeFunctionIdentity + (f₁ f₂ f₃ : BooleanFunction n) : + FABL.booleanRealEmbedding f₁ + FABL.booleanRealEmbedding f₂ + + FABL.booleanRealEmbedding f₃ = + FABL.booleanRealEmbedding (threeFunctionSum f₁ f₂ f₃) + + fun x ↦ 2 * + FABL.booleanRealEmbedding + (threeFunctionPairwiseProductSum f₁ f₂ f₃) x := by + funext x + have h := congrFun (bitValueInt_threeFunctionIdentity f₁ f₂ f₃) x + have hcast := congrArg (fun z : ℤ ↦ (z : ℝ)) h + simp only [Int.cast_add, Int.cast_mul, Int.cast_ofNat] at hcast + have hembedding (f : BooleanFunction n) : + (bitValueInt (f x) : ℝ) = FABL.booleanRealEmbedding f x := by + by_cases hf : f x = 1 <;> + simp [bitValueInt, FABL.booleanRealEmbedding, hf] + rw [hembedding f₁, hembedding f₂, hembedding f₃, + hembedding (threeFunctionSum f₁ f₂ f₃), + hembedding (threeFunctionPairwiseProductSum f₁ f₂ f₃)] at hcast + simpa only [Pi.add_apply] using hcast + +/-- Applying the raw pseudo-Boolean Fourier transform to Proposition 22 +preserves the three-function identity. -/ +theorem rawFourierTransform_threeFunctionIdentity + (f₁ f₂ f₃ : BooleanFunction n) (a : FABL.F₂Cube n) : + rawFourierTransform (FABL.booleanRealEmbedding f₁) a + + rawFourierTransform (FABL.booleanRealEmbedding f₂) a + + rawFourierTransform (FABL.booleanRealEmbedding f₃) a = + rawFourierTransform + (FABL.booleanRealEmbedding (threeFunctionSum f₁ f₂ f₃)) a + + 2 * rawFourierTransform + (FABL.booleanRealEmbedding + (threeFunctionPairwiseProductSum f₁ f₂ f₃)) a := by + have hcoeff := congrArg + (fun φ : FABL.F₂Cube n → ℝ ↦ FABL.vectorFourierCoeff φ a) + (booleanRealEmbedding_threeFunctionIdentity f₁ f₂ f₃) + simp only [FABL.vectorFourierCoeff_add, + FABL.vectorFourierCoeff_const_mul] at hcoeff + simp_rw [rawFourierTransform_eq_two_pow_mul_vectorFourierCoeff] + calc + (2 ^ n : ℝ) * FABL.vectorFourierCoeff (FABL.booleanRealEmbedding f₁) a + + (2 ^ n : ℝ) * FABL.vectorFourierCoeff (FABL.booleanRealEmbedding f₂) a + + (2 ^ n : ℝ) * FABL.vectorFourierCoeff (FABL.booleanRealEmbedding f₃) a = + (2 ^ n : ℝ) * + (FABL.vectorFourierCoeff (FABL.booleanRealEmbedding f₁) a + + FABL.vectorFourierCoeff (FABL.booleanRealEmbedding f₂) a + + FABL.vectorFourierCoeff (FABL.booleanRealEmbedding f₃) a) := by ring + _ = (2 ^ n : ℝ) * + (FABL.vectorFourierCoeff + (FABL.booleanRealEmbedding (threeFunctionSum f₁ f₂ f₃)) a + + 2 * FABL.vectorFourierCoeff + (FABL.booleanRealEmbedding + (threeFunctionPairwiseProductSum f₁ f₂ f₃)) a) := by + rw [hcoeff] + _ = (2 ^ n : ℝ) * FABL.vectorFourierCoeff + (FABL.booleanRealEmbedding (threeFunctionSum f₁ f₂ f₃)) a + + 2 * ((2 ^ n : ℝ) * FABL.vectorFourierCoeff + (FABL.booleanRealEmbedding + (threeFunctionPairwiseProductSum f₁ f₂ f₃)) a) := by ring + +theorem walshTransform_cast_eq_rawFourierTransform_sub_two_mul + (f : BooleanFunction n) (a : FABL.F₂Cube n) : + (walshTransform f a : ℝ) = + rawFourierTransform (fun _ ↦ 1) a - + 2 * rawFourierTransform (FABL.booleanRealEmbedding f) a := by + calc + (walshTransform f a : ℝ) = rawFourierTransform (realSignView f) a := by + simpa [rawFourierTransform] using + walshTransform_cast_eq_sum_realSignView_mul_character f a + _ = rawFourierTransform + (fun x ↦ 1 - 2 * FABL.booleanRealEmbedding f x) a := by + rw [show realSignView f = + (fun x ↦ 1 - 2 * FABL.booleanRealEmbedding f x) from + FABL.realSignEncodedFunction_eq_one_sub_two_booleanRealEmbedding f] + _ = rawFourierTransform (fun _ ↦ 1) a - + 2 * rawFourierTransform (FABL.booleanRealEmbedding f) a := by + rw [rawFourierTransform, rawFourierTransform, rawFourierTransform, + Finset.mul_sum, ← Finset.sum_sub_distrib] + apply Finset.sum_congr rfl + intro x _hx + ring + +/-- Carlet relation (50): the raw Walsh transforms of three Boolean functions +satisfy the same first-and-second symmetric-function identity. -/ +theorem walshTransform_threeFunctionIdentity + (f₁ f₂ f₃ : BooleanFunction n) (a : FABL.F₂Cube n) : + walshTransform f₁ a + walshTransform f₂ a + walshTransform f₃ a = + walshTransform (threeFunctionSum f₁ f₂ f₃) a + + 2 * walshTransform (threeFunctionPairwiseProductSum f₁ f₂ f₃) a := by + apply Int.cast_injective (α := ℝ) + push_cast + rw [walshTransform_cast_eq_rawFourierTransform_sub_two_mul, + walshTransform_cast_eq_rawFourierTransform_sub_two_mul, + walshTransform_cast_eq_rawFourierTransform_sub_two_mul, + walshTransform_cast_eq_rawFourierTransform_sub_two_mul, + walshTransform_cast_eq_rawFourierTransform_sub_two_mul] + have hfourier := rawFourierTransform_threeFunctionIdentity f₁ f₂ f₃ a + linarith + +end CryptBoolean diff --git a/CryptBoolean/Carlet/Chapter06/WalshCongruence.lean b/CryptBoolean/Carlet/Chapter06/WalshCongruence.lean new file mode 100644 index 0000000..4355d36 --- /dev/null +++ b/CryptBoolean/Carlet/Chapter06/WalshCongruence.lean @@ -0,0 +1,133 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +module + +public import CryptBoolean.Carlet.Chapter06.Bentness + +/-! +# Carlet Chapter 6 Walsh congruence + +Carlet Lemma 2: a congruence characterization of bent Boolean functions. +-/ + +open scoped BigOperators BooleanCube + +@[expose] public section + +namespace CryptBoolean + +variable {n : ℕ} + +private theorem exists_odd_factor_of_walsh_modeq + (k : ℕ) (w : ℤ) + (h : Int.ModEq (2 ^ (k + 1)) w (2 ^ k)) : + ∃ z : ℤ, w = (2 : ℤ) ^ k * z ∧ Int.ModEq 2 z 1 := by + let p : ℤ := (2 : ℤ) ^ k + have h' : Int.ModEq (p * 2) w p := by + simpa [p, pow_succ] using h + obtain ⟨t, ht⟩ := Int.modEq_iff_add_fac.mp h' + refine ⟨1 - 2 * t, ?_, ?_⟩ + · have hw : w = p - (p * 2) * t := eq_sub_of_add_eq ht.symm + rw [hw] + ring + · rw [Int.modEq_iff_dvd] + refine ⟨t, ?_⟩ + ring + +/-- Carlet Lemma 2: in even dimension at least two, bentness is equivalent +to every raw Walsh coefficient being congruent to `2^(n/2)` modulo +`2^(n/2+1)`. -/ +theorem isBent_iff_forall_walshTransform_modeq + (f : BooleanFunction n) (hn : Even n) (_hnTwo : 2 ≤ n) : + IsBent f ↔ + ∀ a : FABL.F₂Cube n, + Int.ModEq (2 ^ (n / 2 + 1)) + (walshTransform f a) (2 ^ (n / 2)) := by + constructor + · intro hf a + have hmagnitude := + natAbs_walshTransform_eq_two_pow_half_of_isBent f hf a + rcases Int.natAbs_eq_iff.mp hmagnitude with hpositive | hnegative + · rw [hpositive] + norm_num + · rw [hnegative, Int.modEq_iff_dvd] + rw [pow_succ] + refine ⟨1, ?_⟩ + simp only [sub_neg_eq_add, mul_one, Nat.cast_pow, Nat.cast_ofNat] + ring + · intro hmodeq + have hexists (a : FABL.F₂Cube n) : + ∃ z : ℤ, walshTransform f a = (2 : ℤ) ^ (n / 2) * z ∧ + Int.ModEq 2 z 1 := + exists_odd_factor_of_walsh_modeq (n / 2) (walshTransform f a) (hmodeq a) + choose z hz hodd using hexists + have hz_ne (a : FABL.F₂Cube n) : z a ≠ 0 := by + intro ha + have haOdd := hodd a + rw [ha] at haOdd + norm_num [Int.modEq_iff_dvd] at haOdd + have hz_sq_lower (a : FABL.F₂Cube n) : + (1 : ℝ) ≤ (z a : ℝ) ^ 2 := by + have hpositive : (0 : ℤ) < z a ^ 2 := sq_pos_of_ne_zero (hz_ne a) + have hone : (1 : ℤ) ≤ z a ^ 2 := by omega + exact_mod_cast hone + have hsplit : n = n / 2 + n / 2 := by + rcases hn with ⟨k, hk⟩ + omega + have hhalfSquare : ((2 : ℝ) ^ (n / 2)) ^ 2 = (2 : ℝ) ^ n := by + rw [pow_two, ← pow_add, ← hsplit] + have hparseval := sum_walshTransform_sq_eq_two_pow_sq f + simp_rw [hz] at hparseval + simp only [Int.cast_mul, Int.cast_pow, Int.cast_ofNat] at hparseval + have hsumFactor : + (∑ a : FABL.F₂Cube n, + ((2 : ℝ) ^ (n / 2) * (z a : ℝ)) ^ 2) = + ((2 : ℝ) ^ (n / 2)) ^ 2 * + ∑ a : FABL.F₂Cube n, (z a : ℝ) ^ 2 := by + rw [Finset.mul_sum] + apply Finset.sum_congr rfl + intro a _ha + ring + have hsumz : + ∑ a : FABL.F₂Cube n, (z a : ℝ) ^ 2 = (2 : ℝ) ^ n := by + apply mul_left_cancel₀ + (by positivity : ((2 : ℝ) ^ (n / 2)) ^ 2 ≠ 0) + calc + ((2 : ℝ) ^ (n / 2)) ^ 2 * + ∑ a : FABL.F₂Cube n, (z a : ℝ) ^ 2 = + ∑ a : FABL.F₂Cube n, + ((2 : ℝ) ^ (n / 2) * (z a : ℝ)) ^ 2 := hsumFactor.symm + _ = ((2 : ℝ) ^ n) ^ 2 := hparseval + _ = ((2 : ℝ) ^ (n / 2)) ^ 2 * (2 : ℝ) ^ n := by + rw [hhalfSquare] + ring + have hsumOne : + (∑ _a : FABL.F₂Cube n, (1 : ℝ)) = (2 : ℝ) ^ n := by + rw [Finset.sum_const, Finset.card_univ, card_f₂Cube, + nsmul_eq_mul] + norm_num + apply (hasFlatWalshSpectrum_iff_isBent f).1 + intro a + have hz_sq_upper : (z a : ℝ) ^ 2 ≤ 1 := by + by_contra hnot + have hstrict : (1 : ℝ) < (z a : ℝ) ^ 2 := lt_of_not_ge hnot + have hsumStrict : + (∑ _u : FABL.F₂Cube n, (1 : ℝ)) < + ∑ u : FABL.F₂Cube n, (z u : ℝ) ^ 2 := + Finset.sum_lt_sum (fun u _hu ↦ hz_sq_lower u) + ⟨a, Finset.mem_univ a, hstrict⟩ + rw [hsumOne, hsumz] at hsumStrict + exact (lt_irrefl ((2 : ℝ) ^ n)) hsumStrict + have hz_sq : (z a : ℝ) ^ 2 = 1 := + le_antisymm hz_sq_upper (hz_sq_lower a) + have hz_abs := congrArg Real.sqrt hz_sq + rw [Real.sqrt_sq_eq_abs, Real.sqrt_one] at hz_abs + have hwalsh := congrArg (fun w : ℤ ↦ (w : ℝ)) (hz a) + simp only [Int.cast_mul, Int.cast_pow, Int.cast_ofNat] at hwalsh + rw [hwalsh, abs_mul, abs_of_pos (by positivity), hz_abs, mul_one, + sqrt_two_pow_eq_pow_half hn] + +end CryptBoolean diff --git a/README.md b/README.md index 7ab9425..fe773c1 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ statements, Lean declarations, references, and proof-dependency graph. ## Mathematical scope -The current library covers Carlet Chapters 2--5: +The current library covers Carlet Chapters 2--6: - **Representations and transforms:** support and weight, algebraic and numerical normal forms, Walsh and pseudo-Boolean Fourier transforms, inversion, Parseval and Poisson formulas, @@ -31,15 +31,20 @@ The current library covers Carlet Chapters 2--5: - **Function classes:** affine and quadratic spectra, quadratic trace representations, affine-flat indicators, restriction nonlinearity, normality, covering sequences, and trace-character reductions for finite-field character-sum bounds. +- **Bent functions:** spectral and derivative characterizations, duality, algebraic-degree bounds, + primary and secondary constructions, hyperplane decompositions, counting bounds, numerical and + geometric characterizations, partially-bent and plateaued superclasses, normal extensions, and + the explicit finite-field Kerdock construction and its code parameters. -The Blueprint presents these as reader Chapters 1--4 because Carlet's introductory Chapter 1 is +The Blueprint presents these as reader Chapters 1--5 because Carlet's introductory Chapter 1 is outside the formalization scope; citations and internal identifiers retain Carlet's numbering. -Carlet Chapters 2--4 have no remaining open statements. Chapter 2 includes the exact univariate -binary-degree formula, Proposition 3 on trace-monomial degree, and the trace-pairing coordinate -theorem. Chapter 5 retains three analytic open statements: the Weil character-sum bound, its -nonlinearity corollary, and the reciprocal character-sum bound. Every linked Lean declaration is -proved and kernel-checked. +Carlet Chapters 2--4 and 6 have no remaining open statements. Chapter 2 includes the exact +univariate binary-degree formula, Proposition 3 on trace-monomial degree, and the trace-pairing +coordinate theorem. Chapter 6 includes the McEliece--Ax divisibility theorem used for the bent-dual +degree relation. Chapter 5 retains three analytic open statements: the Weil character-sum bound, +its nonlinearity corollary, and the reciprocal character-sum bound. Every linked Lean declaration +is proved and kernel-checked. Carlet's Walsh transform is an unnormalized integer sum, whereas FABL uses normalized Fourier coefficients. CryptBoolean provides explicit scaling theorems between these conventions. Its @@ -47,14 +52,14 @@ canonical scalar Boolean functions have type `FABL.F₂Cube n → FABL.𝔽₂`. ## Using CryptBoolean -Release `v0.4.1` uses Lean and Mathlib `v4.32.0` and pins FABL `v0.5.6`. Add the package to a +Release `v0.5.0` uses Lean and Mathlib `v4.32.0` and pins FABL `v0.5.6`. Add the package to a downstream `lakefile.toml`: ```toml [[require]] name = "CryptBooleanFunction" git = "https://github.com/Polarnova/CryptBoolean.git" -rev = "v0.4.1" +rev = "v0.5.0" ``` On Linux x86-64 and macOS arm64, obtain the verified release archive with: diff --git a/blueprint-verso/CryptBooleanBlueprint/Blueprint.lean b/blueprint-verso/CryptBooleanBlueprint/Blueprint.lean index 07b9f52..54d2c9f 100644 --- a/blueprint-verso/CryptBooleanBlueprint/Blueprint.lean +++ b/blueprint-verso/CryptBooleanBlueprint/Blueprint.lean @@ -12,6 +12,7 @@ import CryptBooleanBlueprint.Carlet.Chapter02 import CryptBooleanBlueprint.Carlet.Chapter03 import CryptBooleanBlueprint.Carlet.Chapter04 import CryptBooleanBlueprint.Carlet.Chapter05.Classes +import CryptBooleanBlueprint.Carlet.Chapter06 import CryptBooleanBlueprint.References open Verso.Genre @@ -32,12 +33,12 @@ Reed--Muller coding, and cryptographic criteria for scalar Boolean functions. Ca transform and the normalized Fourier coefficient are related throughout by the identity $`W_f(a)=2^n\widetilde{f_\chi}(a)`. -The four chapters develop, in order, representations and the Fourier--Walsh relation, -Reed--Muller coding, scalar cryptographic criteria, and classes with constrained weights, Walsh -spectra, and nonlinearities. +The five chapters develop, in order, representations and the Fourier--Walsh relation, +Reed--Muller coding, scalar cryptographic criteria, classes with constrained weights, Walsh +spectra, and nonlinearities, and bent functions. -The exposition begins with Carlet's Chapter 2. Thus Chapters 1--4 below correspond respectively -to Carlet Chapters 2--5; source references retain Carlet's numbering. +The exposition begins with Carlet's Chapter 2. Thus Chapters 1--5 below correspond respectively +to Carlet Chapters 2--6; source references retain Carlet's numbering. Each entry states the mathematics with explicit domains, hypotheses, quantifiers, and conclusions. The graph below records the mathematical dependencies among these results. @@ -58,6 +59,10 @@ Chapter 3: Boolean functions and cryptography Chapter 4: Classes with Provable Spectra and Weights ::: +:::group "carlet-chapter-6" +Chapter 5: Bent functions +::: + {include 0 CryptBooleanBlueprint.Carlet.Chapter02} {include 0 CryptBooleanBlueprint.Carlet.Chapter03} @@ -66,6 +71,8 @@ Chapter 4: Classes with Provable Spectra and Weights {include 0 CryptBooleanBlueprint.Carlet.Chapter05.Classes} +{include 0 CryptBooleanBlueprint.Carlet.Chapter06} + {references} {blueprint_graph (direction := LR)} diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/Derivatives.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/Derivatives.lean index 595f118..4572142 100644 --- a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/Derivatives.lean +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/Derivatives.lean @@ -6,7 +6,7 @@ Authors: Asher Yan with Codex import Verso import VersoManual import VersoBlueprint -import CryptBoolean.Carlet.Chapter02.Derivatives +import CryptBoolean.Carlet.Chapter02.RestrictionSquareIdentity open Verso.Genre open Verso.Genre.Manual @@ -54,3 +54,13 @@ $$` \sum_{b\in V_n}\Delta_f(b)=W_f(0)^2. ` ::: + +:::proposition "carlet-2-prop-9-restriction-square" (parent := "carlet-chapter-2") (lean := "CryptBoolean.affineSubspaceRestrictionImbalance, CryptBoolean.sum_autocorrelation_submodule_eq_sum_affineSubspaceRestrictionImbalance_sq, CryptBoolean.sum_walshTransform_sq_perpendicular_eq_card_mul_sum_restrictionImbalance_sq") (uses := "carlet-2-cor-1-poisson-summation, carlet-2-rel-25-wiener-khinchin, carlet-2-def-2-derivative") (tags := "carlet, chapter-2, proposition-9, relation-28, page-28, fidelity-exact") +*Proposition 9 (Carlet, Relation (28), p. 28).* Let $`E,E'` be complementary +subspaces of $`V_n`. For every Boolean function $`f:V_n\to\mathbb F_2`, +$$` +\sum_{u\in E^\perp}W_f(u)^2 +=|E^\perp|\sum_{a\in E'} + \left(\sum_{x\in a+E}(-1)^{f(x)}\right)^2. +` +::: diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/NumericalNormalForm.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/NumericalNormalForm.lean index 109e59c..f3f0713 100644 --- a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/NumericalNormalForm.lean +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/NumericalNormalForm.lean @@ -6,7 +6,7 @@ Authors: Asher Yan with Codex import Verso import VersoManual import VersoBlueprint -import CryptBoolean.Carlet.Chapter02.NumericalNormalForm +import CryptBoolean.Carlet.Chapter02.FourierNNF open Verso.Genre open Verso.Genre.Manual @@ -33,6 +33,18 @@ $$` ` ::: +:::theorem "carlet-2-rel-30-nnf-fourier" (parent := "carlet-chapter-2") (lean := "CryptBoolean.rawFourierTransform_numericalMonomial, CryptBoolean.rawFourierTransform_numericalEval") (uses := "carlet-2-nnf-existence-uniqueness, carlet-2-pseudoboolean-fourier, carlet-2-prop-7-subspace-indicator") (tags := "carlet, chapter-2, relation-30, page-32, fidelity-exact") +*Relation (30) (Carlet, p. 32).* If +$`\varphi(x)=\sum_{S\subseteq[n]}\lambda_S\prod_{i\in S}x_i`, then for every +$`u\in V_n`, +$$` +\widehat\varphi(u) +=(-1)^{w_H(u)} + \sum_{\operatorname{supp}(u)\subseteq S} + 2^{n-|S|}\lambda_S. +` +::: + :::proposition "carlet-2-prop-4-nnf-mobius" (parent := "carlet-chapter-2") (lean := "FABL.sum_Icc_neg_one_pow_card_sub, FABL.numericalMobiusCoeff, FABL.numericalEval_numericalMobiusCoeff_f₂CubeOfFinset, FABL.numericalMobiusCoeff_eq_numericalCoeff, FABL.numericalCoeff_eq_mobius_sum") (uses := "carlet-2-nnf-existence-uniqueness") (tags := "carlet, chapter-2, proposition-4, relation-8, page-19, fidelity-exact") *Proposition 4 (Carlet, Relation (8), p. 19).* If $`\varphi(x)=\sum_{S\subseteq[n]}\lambda_Sx^S`, then for every diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/SpectralSupport.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/SpectralSupport.lean index 044be30..f865105 100644 --- a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/SpectralSupport.lean +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/SpectralSupport.lean @@ -7,6 +7,7 @@ import Verso import VersoManual import VersoBlueprint import CryptBoolean.Carlet.Chapter02.SpectralSupport +import CryptBoolean.Carlet.Chapter02.WalshDivisibility open Verso.Genre open Verso.Genre.Manual @@ -46,3 +47,11 @@ N_{\widehat\varphi}\le\sum_{i=0}^{D}\binom ni. The lower bound assumes $`f\ne0`, since the zero function has empty Fourier support. The condition $`\varphi\ne0` likewise makes the displayed numerical degree a maximum over a nonempty set; with the zero-degree convention, the resulting upper bound also holds for $`\varphi=0`. + +:::proposition "carlet-2-prop-11-walsh-divisibility" (parent := "carlet-chapter-2") (lean := "CryptBoolean.vectorFourierCoeff_booleanRealEmbedding_eq, CryptBoolean.functionAlgebraicDegree_le_of_two_pow_dvd_walshTransform") (uses := "carlet-2-def-algebraic-degree, carlet-2-def-walsh-transform") (tags := "carlet, chapter-2, proposition-11, page-34, fidelity-exact") +*Proposition 11 (Carlet, p. 34).* Let $`n\ge2` and $`1\le k\le n`. If +$`2^k` divides $`W_f(a)` for every $`a\in V_n`, then +$$` +\deg_{\mathrm{alg}}(f)\le n-k+1. +` +::: diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/WalshTransform.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/WalshTransform.lean index 4ecf5a6..6f062f1 100644 --- a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/WalshTransform.lean +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter02/WalshTransform.lean @@ -14,7 +14,7 @@ open Informal #doc (Manual) "Walsh transform" => -:::definition "carlet-2-def-walsh-transform" (parent := "carlet-chapter-2") (lean := "CryptBoolean.bitSignInt, CryptBoolean.bitSignInt_add, CryptBoolean.walshTerm, CryptBoolean.walshTransform") (uses := "carlet-2-def-boolean-function") (tags := "carlet, chapter-2, pages-22-23, fidelity-exact") +:::definition "carlet-2-def-walsh-transform" (parent := "carlet-chapter-2") (lean := "CryptBoolean.bitSignInt, CryptBoolean.bitSignInt_add, CryptBoolean.bitSignInt_injective, CryptBoolean.walshTerm, CryptBoolean.walshTransform") (uses := "carlet-2-def-boolean-function") (tags := "carlet, chapter-2, pages-22-23, fidelity-exact") *Walsh transform (Carlet, pp. 22--23).* Let $`f:V_n\to\mathbb F_2`. The Walsh transform of $`f` is the unnormalized Fourier transform of its sign function: diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter05/Classes.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter05/Classes.lean index bf62663..20c3aa3 100644 --- a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter05/Classes.lean +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter05/Classes.lean @@ -166,7 +166,7 @@ Iterating the one-product construction over the ANF support proves the result: e variables, doubles the zero-frequency Walsh coefficient, and decreases the total excess of monomial degrees above three. -:::theorem "carlet-5-quadratic-trace-representation" (parent := "carlet-chapter-5") (lean := "CryptBoolean.quadraticTraceMiddleNorm, CryptBoolean.quadraticTraceMiddleNorm_map_eq_pow, CryptBoolean.functionAlgebraicDegree_le_two_iff_exists_odd_quadraticTraceRepresentation, CryptBoolean.functionAlgebraicDegree_le_two_iff_exists_even_quadraticTraceRepresentation") (uses := "carlet-5-def-quadratic-symplectic-form, carlet-5-theorem-5, carlet-2-absolute-trace, carlet-2-trace-monomial-degree, carlet-2-trace-pairing-coordinates") (tags := "carlet, chapter-5, quadratic-functions, trace-representation, pages-70-71, fidelity-explicit-coordinate-and-subfield-maps") +:::theorem "carlet-5-quadratic-trace-representation" (parent := "carlet-chapter-5") (lean := "CryptBoolean.binaryFrobeniusLinear, CryptBoolean.binaryFrobeniusLinear_apply, CryptBoolean.absoluteTrace_mul_frobeniusPow, CryptBoolean.oddQuadraticTracePart, CryptBoolean.oddQuadraticTracePart_polar_eq_sum, CryptBoolean.functionAlgebraicDegree_traceMonomial_two_pow_add_one_le_two, CryptBoolean.two_pow_add_one_lt_odd_modulus, CryptBoolean.quadraticTraceMiddleNorm, CryptBoolean.quadraticTraceMiddle_finrank, CryptBoolean.quadraticTraceMiddleNorm_map_eq_pow, CryptBoolean.functionAlgebraicDegree_le_two_iff_exists_odd_quadraticTraceRepresentation, CryptBoolean.functionAlgebraicDegree_le_two_iff_exists_even_quadraticTraceRepresentation") (uses := "carlet-5-def-quadratic-symplectic-form, carlet-5-theorem-5, carlet-2-absolute-trace, carlet-2-trace-monomial-degree, carlet-2-trace-pairing-coordinates") (tags := "carlet, chapter-5, quadratic-functions, trace-representation, pages-70-71, fidelity-explicit-coordinate-and-subfield-maps") *Quadratic trace representation (Carlet, pp. 70--71).* Put $`K_j=\operatorname{GF}(2^j)`. If $`\theta:V_{2m+1}\simeq_{\mathbb F_2}K_{2m+1}`, then a Boolean function diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06.lean new file mode 100644 index 0000000..4e98911 --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06.lean @@ -0,0 +1,63 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBooleanBlueprint.Carlet.Chapter06.AlgebraicDegree +import CryptBooleanBlueprint.Carlet.Chapter06.Bentness +import CryptBooleanBlueprint.Carlet.Chapter06.Constructions +import CryptBooleanBlueprint.Carlet.Chapter06.Counting +import CryptBooleanBlueprint.Carlet.Chapter06.DecompositionsCounting +import CryptBooleanBlueprint.Carlet.Chapter06.Duality +import CryptBooleanBlueprint.Carlet.Chapter06.GeometricCharacterization +import CryptBooleanBlueprint.Carlet.Chapter06.HyperBent +import CryptBooleanBlueprint.Carlet.Chapter06.Kerdock +import CryptBooleanBlueprint.Carlet.Chapter06.LowDegree +import CryptBooleanBlueprint.Carlet.Chapter06.NNFCharacterization +import CryptBooleanBlueprint.Carlet.Chapter06.Normality +import CryptBooleanBlueprint.Carlet.Chapter06.SecondOrderCharacterization +import CryptBooleanBlueprint.Carlet.Chapter06.SecondaryConstructions +import CryptBooleanBlueprint.Carlet.Chapter06.Superclasses + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "Bent functions" => + +Carlet's Chapter 6 develops the extremal nonlinear Boolean functions in even +dimension. Write $`V_n=\mathbb F_2^n`, use the unnormalized Walsh transform +$`W_f`, and denote the dual of a bent function $`f` by $`\widetilde f`. + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.Bentness} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.Duality} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.LowDegree} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.AlgebraicDegree} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.Constructions} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.SecondaryConstructions} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.DecompositionsCounting} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.Counting} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.NNFCharacterization} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.GeometricCharacterization} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.SecondOrderCharacterization} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.HyperBent} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.Superclasses} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.Normality} + +{include 0 CryptBooleanBlueprint.Carlet.Chapter06.Kerdock} diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/AlgebraicDegree.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/AlgebraicDegree.lean new file mode 100644 index 0000000..28ada53 --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/AlgebraicDegree.lean @@ -0,0 +1,54 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBoolean.Carlet.Chapter06.DegreeRelation + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "Bound on algebraic degree" => + +:::proposition "carlet-6-prop-18-rothaus-degree-bound" (parent := "carlet-chapter-6") (lean := "CryptBoolean.functionAlgebraicDegree_le_half_of_isBent, CryptBoolean.functionAlgebraicDegree_eq_two_of_isBent") (uses := "carlet-6-prop-17-dual-nnf-divisibility, carlet-6-dual, carlet-2-def-algebraic-degree") (tags := "carlet, chapter-6, algebraic-degree, proposition-18, rothaus-bound, page-83, fidelity-exact") +*Proposition 18: Rothaus' bound (Carlet, p. 83).* Let $`n\ge4` be even. +Every bent function $`f:V_n\to\mathbb F_2` satisfies +$$` +\deg_{\mathrm{alg}}(f)\le n/2, +\qquad +\deg_{\mathrm{alg}}(\widetilde f)\le n/2. +` +In dimension $`n=2`, every bent function, and hence its dual, has algebraic +degree exactly two. +::: + +:::proposition "carlet-6-prop-19" (parent := "carlet-chapter-6") (lean := "CryptBoolean.two_pow_ceilDiv_dvd_booleanCharacterSum_of_degree_le, CryptBoolean.bentDual_functionAlgebraicDegree_relation") (uses := "carlet-6-rel-46-dual-poisson, carlet-6-prop-18-rothaus-degree-bound, carlet-6-dual, carlet-2-anf-existence-uniqueness") (tags := "carlet, chapter-6, algebraic-degree, proposition-19, relation-47, page-83, fidelity-exact-positive-even-dimension") +*Proposition 19 (Carlet, Relation (47), p. 83).* Let $`n\ge2` be even, let +$`f:V_n\to\mathbb F_2` be bent, and put +$$` +d=\deg_{\mathrm{alg}}(f), +\qquad +\widetilde d=\deg_{\mathrm{alg}}(\widetilde f). +` +Then +$$` +\frac n2-d +\ge +\frac{\frac n2-\widetilde d}{\widetilde d-1}. +` +::: + +For a degree-$`d` ANF monomial $`x^I` of $`f`, take +$`E=\{u\in V_n:u_i=0\text{ for every }i\in I\}`. Relation (46) gives +$$` +\sum_{u\in E}(-1)^{\widetilde f(u)} +=2^{n/2-d}\sum_{x\in E^\perp}(-1)^{f(x)}. +` +The rightmost sum is divisible by two but not by four. The McEliece--Ax +divisibility theorem supplies the comparison exponent +$`\lceil(n-d)/\widetilde d\rceil`; comparing the two powers of two yields +Relation (47). diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Bentness.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Bentness.lean new file mode 100644 index 0000000..570774e --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Bentness.lean @@ -0,0 +1,64 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBoolean.Carlet.Chapter06.SupportCode +import CryptBoolean.Carlet.Chapter06.WalshCongruence + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "Bentness" => + +:::definition "carlet-6-def-7-bent" (parent := "carlet-chapter-6") (lean := "CryptBoolean.natAbs_walshTransform_eq_two_pow_half_of_isBent, CryptBoolean.maxWalshMagnitude_eq_two_pow_half_of_isBent, CryptBoolean.nonlinearity_eq_two_pow_sub_two_pow_half_of_isBent, CryptBoolean.isBent_iff_forall_natAbs_walshTransform_eq_two_pow_half, CryptBoolean.isBent_add_affineFunction_iff, CryptBoolean.isBent_comp_affineEquiv_iff, CryptBoolean.abs_hammingDistance_affine_sub_half_of_isBent") (uses := "carlet-4-rel-36-covering-radius-bent, carlet-4-nonlinearity-affine-invariance, carlet-2-def-walsh-transform, carlet-2-def-hamming-distance") (tags := "carlet, chapter-6, definition-7, pages-77-78, fidelity-exact") +*Definition 7 (Carlet, pp. 77--78).* Let $`n` be even. A Boolean function +$`f:V_n\to\mathbb F_2` is bent when +$$` +\operatorname{nl}(f)=2^{n-1}-2^{n/2-1}. +` +Equivalently, $`|W_f(a)|=2^{n/2}` for every $`a\in V_n`, or the distance +from $`f` to every affine function is $`2^{n-1}\pm2^{n/2-1}`. Bentness is +preserved by affine changes of variables and by addition of affine functions. +::: + +:::lemma_ "carlet-6-lemma-2-walsh-congruence" (parent := "carlet-chapter-6") (lean := "CryptBoolean.isBent_iff_forall_walshTransform_modeq") (uses := "carlet-6-def-7-bent, carlet-2-parseval") (tags := "carlet, chapter-6, lemma-2, page-77, fidelity-exact") +*Lemma 2 (Carlet, p. 77).* Let $`n\ge2` be even. A Boolean function +$`f:V_n\to\mathbb F_2` is bent if and only if +$$` +W_f(a)\equiv 2^{n/2}\pmod {2^{n/2+1}} +\qquad(a\in V_n). +` +::: + +:::theorem "carlet-6-theorem-8-perfect-nonlinearity" (parent := "carlet-chapter-6") (lean := "CryptBoolean.isBent_iff_forall_nonzero_derivative_isBalanced, CryptBoolean.isBent_iff_satisfiesPropagationCriterion_dimension") (uses := "carlet-6-def-7-bent, carlet-2-rel-25-wiener-khinchin, carlet-4-def-propagation-criteria") (tags := "carlet, chapter-6, theorem-8, page-78, fidelity-exact") +*Theorem 8 (Carlet, p. 78).* A Boolean function $`f:V_n\to\mathbb F_2` +is bent if and only if every derivative in a nonzero direction is balanced: +$$` +\forall a\in V_n\setminus\{0\},\qquad D_af\text{ is balanced}. +` +Equivalently, $`f` satisfies the propagation criterion of degree $`n`. +::: + +:::proposition "carlet-6-prop-16-support-code" (parent := "carlet-chapter-6") (lean := "CryptBoolean.supportCodeMap, CryptBoolean.supportCode, CryptBoolean.supportCodewordWeight, CryptBoolean.supportCodewordWeight_zero, CryptBoolean.supportCodewordWeight_eq_card_filter, CryptBoolean.codeCharacterSum_support_eq_card_sub_two_weight, CryptBoolean.four_mul_supportCodewordWeight_eq, CryptBoolean.SupportCodeHasExactlyTwoNonzeroWeights, CryptBoolean.isBent_iff_supportCode_finrank_and_two_nonzero_weights") (uses := "carlet-6-def-7-bent, carlet-4-resiliency-support-dual-distance, carlet-2-balanced-zero-walsh, carlet-2-parseval") (tags := "carlet, chapter-6, proposition-16, pages-78-79, fidelity-corrected-dimension-range") +*Proposition 16 (Carlet, pp. 78--79; corrected dimension range).* Let +$`n\ge4` be even, let $`S_f=\{u_1,\ldots,u_w\}` be the support of +$`f:V_n\to\mathbb F_2`, and let +$$` +C_f=\{(v\mathbin\cdot u_1,\ldots,v\mathbin\cdot u_w):v\in V_n\}. +` +Then $`f` is bent if and only if $`\dim C_f=n` and the nonzero words of +$`C_f` have exactly the two weights +$$` +2^{n-2}\quad\text{and}\quad w_H(f)-2^{n-2}, +` +with both weights occurring. +::: + +For $`n=2`, every bent function has odd support size, so the second displayed +quantity can coincide with zero; the printed positive-even formulation is +therefore false in that dimension. diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Constructions.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Constructions.lean new file mode 100644 index 0000000..8067da8 --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Constructions.lean @@ -0,0 +1,60 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBoolean.Carlet.Chapter06.MaioranaMcFarlandGeneral +import CryptBoolean.Carlet.Chapter06.PartialSpreads + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "Primary constructions of bent functions" => + +:::theorem "carlet-6-maiorana-mcfarland" (parent := "carlet-chapter-6") (lean := "CryptBoolean.isMaioranaMcFarland_of_eq_permutation, CryptBoolean.walshTransform_maioranaMcFarlandPermutation, CryptBoolean.isBent_of_maioranaMcFarlandPermutation, CryptBoolean.bentDual_maioranaMcFarlandPermutation, CryptBoolean.isBent_iff_bijective_maioranaMcFarland") (uses := "carlet-6-def-7-bent, carlet-5-def-maiorana-mcfarland, carlet-5-affine-walsh-spectrum") (tags := "carlet, chapter-6, maiorana-mcfarland, relation-48, pages-83-84, fidelity-exact") +*Maiorana--McFarland construction (Carlet, Relation (48), pp. 83--84).* +For $`x,y\in V_m`, let +$$` +f(x,y)=x\mathbin\cdot\pi(y)+g(y), +` +where $`g:V_m\to\mathbb F_2` is arbitrary. The function $`f` is bent if +and only if $`\pi:V_m\to V_m` is bijective. In that case +$$` +\widetilde f(a,b)=b\mathbin\cdot\pi^{-1}(a)+g(\pi^{-1}(a)). +` +::: + +:::proposition "carlet-6-prop-20-general-maiorana-mcfarland" (parent := "carlet-chapter-6") (lean := "CryptBoolean.maioranaMcFarlandFiberCharacterSum, CryptBoolean.walshTransform_maioranaMcFarlandGeneral, CryptBoolean.isBent_iff_maioranaMcFarlandFiberCharacterSum_natAbs, CryptBoolean.isBent_maioranaMcFarlandGeneral_of_affineFibers") (uses := "carlet-6-maiorana-mcfarland, carlet-5-affine-flat-restriction-bound, carlet-6-def-7-bent") (tags := "carlet, chapter-6, proposition-20, relation-49, pages-84-85, fidelity-exact") +*Proposition 20 (Carlet, Relation (49), pp. 84--85).* Let $`n=r+s` be +even with $`r\le s`, let $`\varphi:V_s\to V_r`, and put +$$` +f_{\varphi,g}(x,y)=x\mathbin\cdot\varphi(y)+g(y). +` +For every $`a\in V_r` and $`b\in V_s`, +$$` +W_{f_{\varphi,g}}(a,b) +=2^r\sum_{y\in\varphi^{-1}(a)}(-1)^{g(y)+b\mathbin\cdot y}. +` +If every fiber $`\varphi^{-1}(a)` is an affine subspace of dimension +$`s-r` and, when $`r + +:::theorem "carlet-6-maiorana-mcfarland-count" (parent := "carlet-chapter-6") (lean := "CryptBoolean.MaioranaMcFarlandParameters, CryptBoolean.booleanMaioranaMcFarlandPermutation, CryptBoolean.booleanMaioranaMcFarlandPermutation_joinF₂CubeBlocks, CryptBoolean.booleanMaioranaMcFarlandOfParameters, CryptBoolean.booleanMaioranaMcFarlandOfParameters_injective, CryptBoolean.card_maioranaMcFarlandParameters, CryptBoolean.originalMaioranaMcFarlandClass, CryptBoolean.card_originalMaioranaMcFarlandClass, CryptBoolean.isBent_booleanMaioranaMcFarlandPermutation, CryptBoolean.originalMaioranaMcFarlandClass_subset_bentFunctionFamily") (uses := "carlet-6-maiorana-mcfarland") (tags := "carlet, chapter-6, counting, page-97, fidelity-exact") +*Number of Maiorana--McFarland functions (Carlet, p. 97).* In dimension +$`n=2m`, the original Maiorana--McFarland class contains exactly +$$` +(2^m)!\,2^{2^m} +` +distinct bent functions. +::: + +:::theorem "carlet-6-naive-bent-count-bound" (parent := "carlet-chapter-6") (lean := "CryptBoolean.bentFunctionFamily, CryptBoolean.mem_bentFunctionFamily_iff, CryptBoolean.card_bentFunctionFamily_le_naiveBound") (uses := "carlet-6-prop-18-rothaus-degree-bound, carlet-3-reed-muller-dimension") (tags := "carlet, chapter-6, counting, naive-bound, page-97, fidelity-exact") +*Naive upper bound for the number of bent functions (Carlet, p. 97).* If +$`n\ge4` is even, then the number $`B_n` of bent functions on $`V_n` +satisfies +$$` +B_n\le 2^{\sum_{i=0}^{n/2}\binom ni}. +` +::: diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/DecompositionsCounting.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/DecompositionsCounting.lean new file mode 100644 index 0000000..6ba8f9e --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/DecompositionsCounting.lean @@ -0,0 +1,37 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBoolean.Carlet.Chapter06.HyperplaneRestriction + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "Decompositions of bent functions" => + +:::theorem "carlet-6-theorem-11-hyperplane-restrictions" (parent := "carlet-chapter-6") (lean := "CryptBoolean.singletonF₂Cube, CryptBoolean.singletonF₂Cube_apply, CryptBoolean.walshTransform_append_singletonF₂Cube, CryptBoolean.linearHyperplaneRestriction, CryptBoolean.HasComplementaryHyperplaneRestrictionSpectra, CryptBoolean.isBent_iff_hasComplementaryHyperplaneRestrictionSpectra, CryptBoolean.hyperplaneExtension, CryptBoolean.hyperplaneExtension_append_singletonF₂Cube, CryptBoolean.linearHyperplaneRestriction_hyperplaneExtension_refl, CryptBoolean.isBent_hyperplaneExtension_of_complementaryWalshSpectra, CryptBoolean.isBent_iff_forall_hasComplementaryHyperplaneRestrictionSpectra, CryptBoolean.isBent_iff_exists_hasComplementaryHyperplaneRestrictionSpectra") (uses := "carlet-2-prop-9-restriction-square, carlet-6-def-7-bent") (tags := "carlet, chapter-6, theorem-11, pages-95-96, fidelity-exact") +*Theorem 11 (Carlet, pp. 95--96).* Let $`n\ge4` be even and let +$`f:V_n\to\mathbb F_2`. For a linear hyperplane $`E`, identify $`E` and +its complementary coset with $`V_{n-1}` and denote the two restrictions by +$`h_0,h_1`. The following are equivalent: + +1. $`f` is bent; +2. for every linear hyperplane, and equivalently for at least one linear + hyperplane, the transforms $`W_{h_0}` and $`W_{h_1}` take values in + $`\{0,\pm2^{n/2}\}`, and at every frequency exactly one is nonzero. +::: + +:::corollary "carlet-6-hyperplane-restriction-plateaued" (parent := "carlet-chapter-6") (lean := "CryptBoolean.hasPlateauedWalshAmplitude_linearHyperplaneRestriction_of_isBent, CryptBoolean.isPlateaued_linearHyperplaneRestriction_of_isBent, CryptBoolean.nonlinearity_linearHyperplaneRestriction_of_isBent") (uses := "carlet-6-theorem-11-hyperplane-restrictions, carlet-6-def-plateaued, carlet-4-rel-35-nonlinearity-walsh") (tags := "carlet, chapter-6, hyperplane-restriction, page-96, fidelity-exact") +*Hyperplane-restriction consequence (Carlet, p. 96).* Every restriction of +an $`n`-variable bent function to an affine hyperplane, with $`n\ge4` even, +is plateaued on $`V_{n-1}` with amplitude $`2^{n/2}` and has the optimal +odd-dimensional nonlinearity +$$` +2^{n-2}-2^{(n-2)/2}. +` +::: diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Duality.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Duality.lean new file mode 100644 index 0000000..175a829 --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Duality.lean @@ -0,0 +1,114 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBoolean.Carlet.Chapter06.DualAffine +import CryptBoolean.Carlet.Chapter06.DualCoefficientDivisibility +import CryptBoolean.Carlet.Chapter06.DualNNF +import CryptBoolean.Carlet.Chapter06.DualPoisson + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "The dual" => + +:::definition "carlet-6-dual" (parent := "carlet-chapter-6") (lean := "CryptBoolean.bentDual, CryptBoolean.walshTransform_eq_two_pow_half_mul_bitSignInt_bentDual, CryptBoolean.realSignView_bentDual, CryptBoolean.isBent_bentDual, CryptBoolean.walshTransform_bentDual, CryptBoolean.bentDual_bentDual") (uses := "carlet-6-def-7-bent, carlet-2-def-walsh-transform, carlet-2-fourier-inversion") (tags := "carlet, chapter-6, duality, section-6-1, page-79, fidelity-exact") +*Bent dual (Carlet, Section 6.1, p. 79).* Let $`n` be even and let +$`f:V_n\to\mathbb F_2` be bent. Its dual is the unique Boolean function +$`\widetilde f:V_n\to\mathbb F_2` satisfying +$$` +W_f(u)=2^{n/2}(-1)^{\widetilde f(u)} +\qquad(u\in V_n). +` +The function $`\widetilde f` is bent and satisfies +$$` +W_{\widetilde f}(a)=2^{n/2}(-1)^{f(a)}, +\qquad +\widetilde{\widetilde f}=f. +` +::: + +:::theorem "carlet-6-rel-44-dual-isometry" (parent := "carlet-chapter-6") (lean := "CryptBoolean.walshTransform_zero_bentDual_add, CryptBoolean.hammingDistance_bentDual") (uses := "carlet-6-dual, carlet-2-rel-22-plancherel, carlet-2-def-hamming-distance") (tags := "carlet, chapter-6, duality, relation-44, page-79, fidelity-exact") +*Relation (44) (Carlet, p. 79).* If $`f,g:V_n\to\mathbb F_2` are bent, +then +$$` +W_{\widetilde f+\widetilde g}(0)=W_{f+g}(0). +` +Consequently, +$$` +d_H(\widetilde f,\widetilde g)=d_H(f,g), +` +so duality preserves pairwise Hamming distance on bent functions. +::: + +:::theorem "carlet-6-rel-45-dual-derivatives" (parent := "carlet-chapter-6") (lean := "CryptBoolean.isBent_domainTranslate, CryptBoolean.isBent_domainTranslate_add_linear, CryptBoolean.bentDual_domainTranslate_add_linear, CryptBoolean.walshTransform_zero_bentDual_derivative_add_linear") (uses := "carlet-6-dual, carlet-6-rel-44-dual-isometry, carlet-2-prop-6-fourier-shifts, carlet-2-def-2-derivative") (tags := "carlet, chapter-6, duality, relation-45, pages-79-80, fidelity-exact") +*Relation (45) (Carlet, pp. 79--80).* Let $`f:V_n\to\mathbb F_2` be bent +and let $`a,b\in V_n`. The function +$$` +g(x)=f(x+b)+a\mathbin\cdot x +` +is bent, and its dual is +$$` +\widetilde g(x)=\widetilde f(x+a)+b\mathbin\cdot(x+a). +` +Writing $`\ell_c(x)=c\mathbin\cdot x`, one has +$$` +W_{D_a\widetilde f+\ell_b}(0) +=W_{D_bf+\ell_a}(0). +` +::: + +:::theorem "carlet-6-dual-nnf" (parent := "carlet-chapter-6") (lean := "CryptBoolean.booleanRealEmbedding_bentDual_eq_rawFourierTransform, CryptBoolean.booleanRealEmbedding_bentDual_eq_numericalCoeff_sum") (uses := "carlet-6-dual, carlet-2-nnf-existence-uniqueness, carlet-2-rel-30-nnf-fourier") (tags := "carlet, chapter-6, duality, numerical-normal-form, pages-79-80, fidelity-exact") +*Numerical normal form of the dual (Carlet, pp. 79--80).* Let +$`f:V_n\to\mathbb F_2` be bent, and write its numerical normal form as +$$` +f(x)=\sum_{S\subseteq[n]}\lambda_Sx^S. +` +If $`\delta_0(x)` is one at $`x=0` and zero elsewhere, then +$$` +\widetilde f(x) +=\frac12-\frac{2^{n/2}}2\,\delta_0(x) ++\frac{(-1)^{w_H(x)}}{2^{n/2}} + \sum_{\operatorname{supp}(x)\subseteq S} + 2^{n-|S|}\lambda_S. +` +This identity determines the numerical normal form of $`\widetilde f`. +::: + +:::proposition "carlet-6-prop-17-dual-nnf-divisibility" (parent := "carlet-chapter-6") (lean := "CryptBoolean.bentDual_and_self_nnfCoefficient_divisibility") (uses := "carlet-6-dual-nnf, carlet-6-lemma-2-walsh-congruence, carlet-2-prop-5-nnf-integrality") (tags := "carlet, chapter-6, duality, numerical-normal-form, proposition-17, page-80, fidelity-exact") +*Proposition 17 (Carlet, p. 80).* Let $`f:V_n\to\mathbb F_2` be bent, +where $`n` is even, and let $`\lambda_I` and $`\widetilde\lambda_I` be the +integer numerical-normal-form coefficients of $`f` and $`\widetilde f`. +For every proper subset $`I\subsetneq[n]` with $`|I|>n/2`, +$$` +2^{|I|-n/2}\mid\lambda_I, +\qquad +2^{|I|-n/2}\mid\widetilde\lambda_I. +` +::: + +:::corollary "carlet-6-half-degree-anf-complement" (parent := "carlet-chapter-6") (lean := "CryptBoolean.anfCoeff_bentDual_eq_complement_of_card_eq_half, CryptBoolean.anfCoeff_eq_bentDual_complement_of_card_eq_half") (uses := "carlet-6-prop-17-dual-nnf-divisibility, carlet-6-dual-nnf, carlet-2-anf-existence-uniqueness") (tags := "carlet, chapter-6, duality, algebraic-normal-form, page-81, fidelity-exact-with-dual-symmetry") +*Complementary half-degree ANF coefficients (Carlet, p. 81).* Let $`n\ge4`, +let $`f:V_n\to\mathbb F_2` be bent, and let $`c_{f,I}` denote the coefficient +of $`x^I` in the ANF of $`f`. For every $`I\subseteq[n]` with $`|I|=n/2`, +$$` +c_{\widetilde f,I}=c_{f,[n]\setminus I}, +\qquad +c_{f,I}=c_{\widetilde f,[n]\setminus I}. +` +::: + +:::theorem "carlet-6-rel-46-dual-poisson" (parent := "carlet-chapter-6") (lean := "CryptBoolean.bentDual_poissonSummationFormula") (uses := "carlet-6-dual, carlet-2-cor-1-poisson-summation") (tags := "carlet, chapter-6, duality, poisson-summation, relation-46, page-81, fidelity-exact") +*Relation (46) (Carlet, p. 81).* Let $`f:V_n\to\mathbb F_2` be bent, let +$`E\le V_n`, and let $`a,b\in V_n`. Then +$$` +\sum_{x\in a+E}(-1)^{\widetilde f(x)+b\mathbin\cdot x} +=2^{-n/2}|E|(-1)^{a\mathbin\cdot b} + \sum_{x\in b+E^\perp}(-1)^{f(x)+a\mathbin\cdot x}. +` +::: diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/GeometricCharacterization.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/GeometricCharacterization.lean new file mode 100644 index 0000000..e7bf26a --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/GeometricCharacterization.lean @@ -0,0 +1,53 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBoolean.Carlet.Chapter06.GeometricCharacterization + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "Geometric characterization" => + +:::lemma_ "carlet-6-lemma-3-subspace-indicators" (parent := "carlet-chapter-6") (lean := "CryptBoolean.linearSubspaceIndicatorInt, CryptBoolean.halfSubspaceCombination, CryptBoolean.ambientFunctionalKernel, CryptBoolean.mem_ambientFunctionalKernel_iff, CryptBoolean.finrank_ambientFunctionalKernel, CryptBoolean.nonzeroDualFinset, CryptBoolean.mem_nonzeroDualFinset, CryptBoolean.card_nonzeroDualFinset, CryptBoolean.functionalKernelCombination_modeq, CryptBoolean.HasHalfSubspaceRepresentation, CryptBoolean.hasHalfSubspaceRepresentation_indicator_of_finrank_eq, CryptBoolean.hasHalfSubspaceRepresentation_indicator_of_half_le_finrank, CryptBoolean.rankTwoIntermediateSubspace, CryptBoolean.mem_rankTwoIntermediateSubspace_iff, CryptBoolean.finrank_rankTwoIntermediateSubspace, CryptBoolean.rankTwoSubspaceDiamond, CryptBoolean.hasHalfSubspaceRepresentation_scaledIndicator_of_finrank_le_half, CryptBoolean.carletLemma3") (tags := "carlet, chapter-6, lemma-3, subspace-indicators, section-6-6-2, page-99, fidelity-exact") +*Lemma 3 (Carlet, p. 99).* Let $`n` be even and let $`F\le V_n` have +dimension $`d`. There are $`n/2`-dimensional subspaces +$`E_1,\ldots,E_k`, integers $`m_1,\ldots,m_k`, and an integer $`m` such +that, pointwise on $`V_n`, +$$` +2^{n/2-d}1_F\equiv m+\sum_{i=1}^k m_i1_{E_i} + \pmod {2^{n/2}} +\qquad(dn/2). +` +::: + +:::theorem "carlet-6-theorem-12-geometric-characterization" (parent := "carlet-chapter-6") (lean := "CryptBoolean.originIndicatorInt, CryptBoolean.geometricBentExpression, CryptBoolean.perpendicularGeometricBentExpression, CryptBoolean.integerWalshTransform_linearSubspaceIndicatorInt, CryptBoolean.integerWalshTransform_originIndicatorInt, CryptBoolean.integerWalshTransform_bitValueInt_eq_booleanNNFFourierCoeffInt, CryptBoolean.integerWalshTransform_halfSubspaceCombination, CryptBoolean.integerWalshTransform_geometricBentExpression, CryptBoolean.HasGeometricBentCongruence, CryptBoolean.isBent_of_hasGeometricBentCongruence, CryptBoolean.HasExactGPSRepresentation, CryptBoolean.isBent_and_bitValueInt_bentDual_of_exactGPSRepresentation, CryptBoolean.numericalMonomialInt, CryptBoolean.numericalMonomialInt_cast, CryptBoolean.numericalMonomialInt_eq_sum_coordinateZeroIndicators, CryptBoolean.finrank_coordinateZeroSubspace, CryptBoolean.linearSubspaceIndicatorInt_coordinateZeroSubspace_univ, CryptBoolean.bitValueInt_eq_sum_booleanNumericalCoeffInt_mul_numericalMonomialInt, CryptBoolean.hasGeometricBentCongruence_of_isBent, CryptBoolean.isBent_iff_hasGeometricBentCongruence") (uses := "carlet-6-prop-23-nnf-characterization, carlet-6-lemma-3-subspace-indicators, carlet-6-lemma-2-walsh-congruence, carlet-2-prop-7-subspace-indicator, carlet-6-dual") (tags := "carlet, chapter-6, theorem-12, relation-51, generalized-partial-spread, section-6-6-2, page-99, fidelity-exact") +*Theorem 12 (Carlet, Relation (51), p. 99).* Let $`n\ge2` be even. A +Boolean function $`f:V_n\to\mathbb F_2` is bent if and only if there are +$`n/2`-dimensional subspaces $`E_1,\ldots,E_k\le V_n` and integers +$`m_1,\ldots,m_k` such that, for every $`x\in V_n`, +$$` +f(x)\equiv\sum_{i=1}^k m_i1_{E_i}(x)-2^{n/2-1}\delta_0(x) + \pmod {2^{n/2}}. +` +If this congruence is an equality over the integers, then $`f` belongs to +the generalized partial-spread class and its dual is +$$` +\widetilde f(x)= +\sum_{i=1}^k m_i1_{E_i^\perp}(x)-2^{n/2-1}\delta_0(x). +` +In particular, the dual also belongs to the generalized partial-spread +class. +::: diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/HyperBent.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/HyperBent.lean new file mode 100644 index 0000000..a0767ac --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/HyperBent.lean @@ -0,0 +1,48 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBoolean.Carlet.Chapter06.HyperBentPartialSpread + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "Hyper-bent functions" => + +:::definition "carlet-6-def-hyper-bent" (parent := "carlet-chapter-6") (lean := "CryptBoolean.fieldWalshTransform, CryptBoolean.IsFieldBent, CryptBoolean.fieldPowerReindex, CryptBoolean.fieldPowerMap_bijective, CryptBoolean.fieldPowerEquiv, CryptBoolean.fieldPowerEquiv_apply, CryptBoolean.fieldPowerReindex_eq_comp_fieldPowerEquiv, CryptBoolean.IsHyperBent, CryptBoolean.exists_fieldWalshTransform_eq_walshTransform, CryptBoolean.exists_walshTransform_eq_fieldWalshTransform, CryptBoolean.isFieldBent_iff_isBent_comp_linearEquiv, CryptBoolean.IsHyperBent.isFieldBent, CryptBoolean.isHyperBent_iff_forall_isBent_powerReindex_comp_linearEquiv") (uses := "carlet-2-absolute-trace, carlet-2-trace-pairing-coordinates, carlet-6-def-7-bent") (tags := "carlet, chapter-6, hyper-bent, pages-100-101, fidelity-exact") +*Hyper-bent functions (Carlet, pp. 100--101).* Let $`n` be even and +$`f:\operatorname{GF}(2^n)\to\mathbb F_2`. The function $`f` is hyper-bent +when, for every integer $`i` coprime to $`2^n-1`, every $`a` in the field, +and both $`\varepsilon\in\mathbb F_2`, its distance to +$`x\mapsto\operatorname{Tr}_n(ax^i)+\varepsilon` is +$`2^{n-1}\pm2^{n/2-1}`. Equivalently, every function $`x\mapsto f(x^i)` +is bent. In particular, every hyper-bent function is bent. +::: + +:::lemma_ "carlet-6-lemma-4-subfield-intersection" (parent := "carlet-chapter-6") (lean := "CryptBoolean.quadraticSubfieldBasisMap_bijective, CryptBoolean.quadraticSubfieldBasisEquiv, CryptBoolean.quadraticSubfieldBasisEquiv_apply, CryptBoolean.existsUnique_subfield_power_intersection") (uses := "carlet-6-def-hyper-bent, carlet-2-absolute-trace") (tags := "carlet, chapter-6, lemma-4, page-102, fidelity-corrected-even-dimension") +*Lemma 4 (Carlet, p. 102; corrected dimension convention).* Let $`m>0`, +let $`K=\operatorname{GF}(2^m)` be the quadratic subfield of +$`L=\operatorname{GF}(2^{2m})`, and let $`a,\omega\in L\setminus K`. If +$`i` is coprime to $`2^{2m}-1`, then there is a unique $`z\in K` such that +$$` +a(z+\omega)^i\in K. +` +::: + +:::proposition "carlet-6-prop-25-psap-hyper-bent" (parent := "carlet-chapter-6") (lean := "CryptBoolean.quadraticSubfield_powerMap_bijective, CryptBoolean.pow_mem_quadraticSubfield_iff, CryptBoolean.relativeTrace_eq_zero_iff_mem_quadraticSubfield, CryptBoolean.absoluteTrace_mul_quadraticSubfield, CryptBoolean.sum_bitSignInt_absoluteTrace_mul_eq_zero, CryptBoolean.sum_quadraticSubfieldTraceCharacter_of_mem, CryptBoolean.sum_quadraticSubfieldTraceCharacter_of_not_mem, CryptBoolean.psapFunction, CryptBoolean.psapFunction_coordinate, CryptBoolean.sum_bitSignInt_field_eq_zero_of_balanced, CryptBoolean.fieldPowerTraceTransform, CryptBoolean.fieldPowerTraceTransform_psap_eq, CryptBoolean.fieldPowerTraceTransform_psap_natAbs, CryptBoolean.isHyperBent_of_forall_fieldPowerTraceTransform, CryptBoolean.isHyperBent_psapFunction") (uses := "carlet-6-def-hyper-bent, carlet-6-lemma-4-subfield-intersection, carlet-6-partial-spread-construction, carlet-5-quadratic-trace-representation") (tags := "carlet, chapter-6, proposition-25, pages-101-102, fidelity-corrected-positive-half-dimension") +*Proposition 25 (Carlet, pp. 101--102).* Let $`m\ge2`, put +$`K=\operatorname{GF}(2^m)` and $`L=\operatorname{GF}(2^{2m})`, choose +$`\omega\in L\setminus K`, and write every $`x\in L` uniquely as +$`x=y'+\omega y` with $`y',y\in K`. If $`g:K\to\mathbb F_2` is balanced +and $`g(0)=0`, define +$$` +f(y'+\omega y)=g(y'/y), +` +with $`y'/y=0` when $`y=0`. Then $`f` is hyper-bent. Equivalently, every +function in Dillon's class $`PS_{ap}` is hyper-bent. +::: diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Kerdock.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Kerdock.lean new file mode 100644 index 0000000..599fee1 --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Kerdock.lean @@ -0,0 +1,76 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBoolean.Carlet.Chapter06.CompleteQuadratic +import CryptBoolean.Carlet.Chapter06.Kerdock +import CryptBoolean.Carlet.Chapter06.KerdockCoordinateIdentity +import CryptBoolean.Carlet.Chapter06.KerdockFieldConstruction + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "Kerdock codes" => + +:::theorem "carlet-6-rel-56-complete-quadratic" (parent := "carlet-chapter-6") (lean := "FABL.completeQuadraticBit, CryptBoolean.functionAlgebraicDegree_completeQuadraticBit_le_two, CryptBoolean.completeQuadraticBit_eq_choose_support_card, CryptBoolean.completeQuadraticPolarFrequency, CryptBoolean.quadraticPolarKernel_completeQuadraticBit_eq_crossSum, CryptBoolean.quadraticPolarKernel_completeQuadraticBit_eq_dotProduct, CryptBoolean.completeQuadraticPolarFrequency_eq_zero_of_even, CryptBoolean.quadraticRadical_completeQuadraticBit_eq_bot, CryptBoolean.isBent_completeQuadraticBit, CryptBoolean.completeQuadraticBit_zero_dimension, CryptBoolean.isBent_completeQuadraticBit_zero_dimension, CryptBoolean.completeQuadraticBit_two_dimension, CryptBoolean.isBent_completeQuadraticBit_two_dimension") (uses := "carlet-6-quadratic-bent-characterization, carlet-2-def-support-weight") (tags := "carlet, chapter-6, relation-56, pages-109-110, fidelity-exact") +*Relation (56) (Carlet, pp. 109--110).* Define the complete quadratic +function on $`V_n` by +$$` +q_n(x)=\sum_{1\le i + +:::theorem "carlet-6-quadratic-bent-characterization" (parent := "carlet-chapter-6") (lean := "CryptBoolean.isBent_iff_quadraticRadical_eq_bot, CryptBoolean.isBent_iff_linearKernel_eq_bot_of_degree_le_two") (uses := "carlet-6-def-7-bent, carlet-5-def-quadratic-symplectic-form, carlet-5-theorem-5, carlet-5-quadratic-weight-nonlinearity-values") (tags := "carlet, chapter-6, section-6-2, pages-80-81, fidelity-exact") +*Quadratic bent functions (Carlet, Section 6.2, pp. 80--81).* Let $`n\ge2` +be even and let $`f:V_n\to\mathbb F_2` have algebraic degree at most two. The +following conditions are equivalent: + +1. $`f` is bent; +2. $`w_H(f)=2^{n-1}\pm2^{n/2-1}`; +3. the alternating polar form +$$` +\phi_f(x,y)=f(0)+f(x)+f(y)+f(x+y) +` + is nondegenerate, equivalently the linear kernel of $`f` is $`\{0\}`; +4. the symmetric zero-diagonal coefficient matrix of the quadratic part of + $`f` is nonsingular; +5. after an invertible affine change of variables, $`f` has the form +$$` +x_1x_2+x_3x_4+\cdots+x_{n-1}x_n+\varepsilon +\qquad(\varepsilon\in\mathbb F_2). +` +::: diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/NNFCharacterization.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/NNFCharacterization.lean new file mode 100644 index 0000000..4af9569 --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/NNFCharacterization.lean @@ -0,0 +1,33 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBoolean.Carlet.Chapter06.NNFCharacterization + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "Characterization through the NNF" => + +:::proposition "carlet-6-prop-23-nnf-characterization" (parent := "carlet-chapter-6") (lean := "CryptBoolean.booleanNNFFourierCoeffInt, CryptBoolean.booleanNNFFourierCoeffInt_cast, CryptBoolean.walshTransform_eq_indicator_sub_two_mul_booleanNNFFourierCoeffInt, CryptBoolean.isBent_iff_forall_booleanNNFFourierCoeffInt_modeq, CryptBoolean.SatisfiesBentNNFCoefficientConditions, CryptBoolean.isBent_iff_nnfCoefficientConditions") (uses := "carlet-6-lemma-2-walsh-congruence, carlet-2-rel-30-nnf-fourier, carlet-2-prop-4-nnf-mobius, carlet-2-prop-5-nnf-integrality") (tags := "carlet, chapter-6, proposition-23, numerical-normal-form, section-6-6-1, page-98, fidelity-exact") +*Proposition 23 (Carlet, p. 98).* Let $`n\ge2` be even, and let +$`f:V_n\to\mathbb F_2` have numerical normal form +$$` +f(x)=\sum_{I\subseteq[n]}\lambda_Ix^I. +` +Then $`f` is bent if and only if both of the following conditions hold: + +1. for every $`I\subseteq[n]` with $`n/2<|I| + +:::definition "carlet-6-def-8-normal-extension" (parent := "carlet-chapter-6") (lean := "CryptBoolean.IsNormalExtension, CryptBoolean.IsNormalExtension.isBent_left, CryptBoolean.IsNormalExtension.isBent_right, CryptBoolean.isNormalExtension_refl") (uses := "carlet-6-def-7-bent") (tags := "carlet, chapter-6, definition-8, normal-extension, pages-107-108, fidelity-exact-coordinate-invariant-form") +*Normal extension (Carlet, Definition 8, pp. 107--108).* Let +$`\beta:V_k\to\mathbb F_2` and $`f:V_n\to\mathbb F_2` be bent. Write +$`\beta\preccurlyeq f` when there are a nonnegative integer $`m` and a +linear isomorphism +$$` +L:V_k\times V_m\times V_m\longrightarrow V_n +` +such that +$$` +f\bigl(L(u,w,0)\bigr)=\beta(u) +\qquad(u\in V_k,\ w\in V_m). +` +Equivalently, $`V_n=U\oplus W_1\oplus W_2` with +$`\dim W_1=\dim W_2`, and the restriction of $`f` to +$`U\oplus W_1` is $`\beta` pulled back from $`U`. Every bent function is +a normal extension of itself. +::: + +:::theorem "carlet-6-normal-extension-composition-duality" (parent := "carlet-chapter-6") (lean := "CryptBoolean.walshAdjointLinearEquiv, CryptBoolean.walshTransform_comp_linearEquiv, CryptBoolean.bentDual_comp_linearEquiv, CryptBoolean.bentDual_canonical_normalExtension, CryptBoolean.IsNormalExtension.trans, CryptBoolean.IsNormalExtension.bentDual") (uses := "carlet-6-def-8-normal-extension, carlet-6-dual, carlet-6-rel-46-dual-poisson") (tags := "carlet, chapter-6, normal-extension, duality, transitivity, page-108, fidelity-exact") +*Composition and duality of normal extensions (Carlet, p. 108).* The +relation $`\preccurlyeq` is transitive. Moreover, if +$`\beta\preccurlyeq f`, then +$$` +\widetilde\beta\preccurlyeq\widetilde f. +` +In standard coordinates, duality exchanges the two equal complementary +summands. +::: + +:::theorem "carlet-6-normal-zero-dimensional-characterization" (parent := "carlet-chapter-6") (lean := "CryptBoolean.zeroDimensionalBooleanFunction, CryptBoolean.zeroDimensionalBooleanFunction_apply, CryptBoolean.isBent_zeroDimensionalBooleanFunction, CryptBoolean.IsSubspaceNormal, CryptBoolean.IsAffineNormalExtension, CryptBoolean.isKNormal_comp_affineEquiv_iff, CryptBoolean.exists_isNormalExtension_zeroDimensional_iff_isSubspaceNormal, CryptBoolean.exists_isAffineNormalExtension_zeroDimensional_iff_isKNormal, CryptBoolean.exists_isKNormal_not_isNormalExtension_zeroDimensional") (uses := "carlet-6-def-8-normal-extension, carlet-5-def-4-normality, carlet-2-affine-invariance") (tags := "carlet, chapter-6, normality, zero-dimensional-extension, page-108, fidelity-source-correction") +*Zero-dimensional normal extensions (Carlet, p. 108; corrected normality convention).* Let $`f:V_n\to\mathbb F_2` be bent. If normality means that +$`f` is constant on an $`n/2`-dimensional linear subspace, then +$$` +f\text{ is normal} +\quad\Longleftrightarrow\quad +\varepsilon\preccurlyeq f +\text{ for some }\varepsilon\in\mathbb F_2. +` +For the affine-flat convention of Definition 4, the exact statement is +instead +$$` +f\text{ is }(n/2)\text{-normal} +\quad\Longleftrightarrow\quad +\varepsilon\preccurlyeq(f\circ A) +` +for some $`\varepsilon\in\mathbb F_2` and some affine automorphism $`A` +of $`V_n`. + +The affine automorphism cannot in general be omitted. The two-variable +function +$$` +f(x_1,x_2)=(x_1+1)(x_2+1) +` +is bent and constant on a one-dimensional affine flat, but it is not +constant on any one-dimensional linear subspace. +::: + +:::proposition "carlet-6-prop-29-direct-sum-normality" (parent := "carlet-chapter-6") (lean := "CryptBoolean.AreLinearlyEquivalentOrComplementary, CryptBoolean.isSubspaceNormal_booleanDirectSum_iff") (uses := "carlet-6-direct-sum, carlet-6-def-8-normal-extension, carlet-6-normal-zero-dimensional-characterization, carlet-5-affine-flat-restriction-bound") (tags := "carlet, chapter-6, proposition-29, normality, direct-sum, page-108, fidelity-exact-linear-subspace-convention") +*Proposition 29 (Carlet, p. 108).* Let +$`f_i:V_i\to\mathbb F_2` be bent for $`i=1,2`. The direct sum +$`f_1\oplus f_2` is normal if and only if there are bent functions +$`\beta_i` such that $`\beta_i\preccurlyeq f_i` for $`i=1,2` and either +$`\beta_1` is linearly equivalent to $`\beta_2`, or $`\beta_1` is linearly +equivalent to $`\beta_2+1`. +::: + +:::proposition "carlet-6-prop-30-normality-descends" (parent := "carlet-chapter-6") (lean := "CryptBoolean.isSubspaceNormal_comp_linearEquiv_iff, CryptBoolean.IsNormalExtension.isSubspaceNormal_left") (uses := "carlet-6-def-8-normal-extension, carlet-6-normal-zero-dimensional-characterization, carlet-6-prop-31-normal-extension-replacement, carlet-5-affine-flat-restriction-bound") (tags := "carlet, chapter-6, proposition-30, normality, normal-extension, page-108, fidelity-exact-linear-subspace-convention") +*Proposition 30 (Carlet, p. 108).* If $`\beta\preccurlyeq f` and the bent +function $`f` is normal, then the bent function $`\beta` is normal. +::: + +:::proposition "carlet-6-prop-31-normal-extension-replacement" (parent := "carlet-chapter-6") (lean := "CryptBoolean.canonicalNormalExtensionReplacement, CryptBoolean.canonicalNormalExtensionReplacement_apply_append, CryptBoolean.isBent_canonicalNormalExtensionReplacement, CryptBoolean.normalExtensionReplacement, CryptBoolean.normalExtensionReplacement_apply, CryptBoolean.normalExtensionReplacement_isNormalExtension") (uses := "carlet-6-def-8-normal-extension, carlet-6-normal-extension-composition-duality, carlet-6-rel-46-dual-poisson") (tags := "carlet, chapter-6, proposition-31, normal-extension, replacement, page-108, fidelity-exact-coordinate-invariant-form") +*Proposition 31 (Carlet, p. 108).* Let $`\beta` be bent on $`U`, let +$`f` be bent on $`U\times W\times W`, and suppose +$`\beta\preccurlyeq f` through +$$` +f(x,y,0)=\beta(x). +` +For any bent $`\beta':U\to\mathbb F_2`, define +$$` +f'(x,y,z)= +\begin{cases} +\beta'(x),&z=0,\\ +f(x,y,z),&z\ne0. +\end{cases} +` +Then $`f'` is bent and $`\beta'\preccurlyeq f'`. +::: diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/SecondOrderCharacterization.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/SecondOrderCharacterization.lean new file mode 100644 index 0000000..a3f10c9 --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/SecondOrderCharacterization.lean @@ -0,0 +1,31 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBoolean.Carlet.Chapter06.SecondOrderCharacterization + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "Characterization by second-order covering sequences" => + +:::proposition "carlet-6-prop-24-second-order-characterization" (parent := "carlet-chapter-6") (lean := "CryptBoolean.secondDerivativeDoubleSum, CryptBoolean.rawTripleConvolution, CryptBoolean.secondDerivativeDoubleSum_eq_mul_rawTripleConvolution, CryptBoolean.rawFourierTransform_rawTripleConvolution, CryptBoolean.rawFourierTransform_const_mul_realSignView, CryptBoolean.eq_of_rawFourierTransform_eq, CryptBoolean.isBent_iff_forall_secondDerivativeDoubleSum_eq_two_pow, CryptBoolean.secondDerivativeDoubleSum_eq_two_pow_iff_rawTripleConvolution_eq, CryptBoolean.isBent_iff_rawTripleConvolution_realSignView_eq, CryptBoolean.isBent_iff_forall_walshTransform_cube_eq") (uses := "carlet-6-theorem-8-perfect-nonlinearity, carlet-4-autocorrelation-indicator-bounds, carlet-4-second-derivative-sum, carlet-2-def-convolution, carlet-2-prop-8-convolution, carlet-2-fourier-inversion") (tags := "carlet, chapter-6, proposition-24, relation-52, second-order-covering-sequence, section-6-6-3, page-100, fidelity-exact") +*Proposition 24 (Carlet, Relation (52), p. 100).* A Boolean function +$`f:V_n\to\mathbb F_2` is bent if and only if, for every $`x\in V_n`, +$$` +\sum_{a,b\in V_n}(-1)^{D_aD_bf(x)}=2^n. +` +Equivalently, for the sign function $`f_\chi=(-1)^f`, +$$` +f_\chi\otimes f_\chi\otimes f_\chi=2^nf_\chi, +` +or, at every $`u\in V_n`, +$$` +W_f(u)^3=2^nW_f(u). +` +::: diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/SecondaryConstructions.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/SecondaryConstructions.lean new file mode 100644 index 0000000..057ad06 --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/SecondaryConstructions.lean @@ -0,0 +1,115 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBoolean.Carlet.Chapter06.DirectSum +import CryptBoolean.Carlet.Chapter06.FlatSwitching +import CryptBoolean.Carlet.Chapter06.IndirectSum +import CryptBoolean.Carlet.Chapter06.PermutationReindex +import CryptBoolean.Carlet.Chapter06.Rothaus + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "Secondary constructions of bent functions" => + +:::theorem "carlet-6-direct-sum" (parent := "carlet-chapter-6") (lean := "CryptBoolean.IsDecomposable, CryptBoolean.isDecomposable_booleanDirectSum, CryptBoolean.walshTransform_directSum, CryptBoolean.isBent_booleanDirectSum, CryptBoolean.bentDual_booleanDirectSum_append") (uses := "carlet-6-def-7-bent, carlet-6-dual") (tags := "carlet, chapter-6, direct-sum, pages-88-89, fidelity-exact") +*Direct sum (Carlet, pp. 88--89).* If $`f:V_n\to\mathbb F_2` and +$`g:V_m\to\mathbb F_2` are bent, then +$$` +h(x,y)=f(x)+g(y) +` +is bent on $`V_{n+m}`. Its spectrum and dual factor as +$`W_h(a,b)=W_f(a)W_g(b)` and +$`\widetilde h(a,b)=\widetilde f(a)+\widetilde g(b)`. +::: + +:::theorem "carlet-6-rothaus-construction" (parent := "carlet-chapter-6") (lean := "CryptBoolean.rothausConstruction, CryptBoolean.rothausConstruction_append, CryptBoolean.isBent_rothausConstruction") (uses := "carlet-6-theorem-10-slice-construction, carlet-6-cor-4-three-function-construction") (tags := "carlet, chapter-6, rothaus, page-89, fidelity-exact") +*Dillon--Rothaus construction (Carlet, p. 89).* Let $`g,h,k`, and +$`g+h+k` be bent functions on $`V_n`. Then the function on +$`\mathbb F_2^2\times V_n` given by +$$` +gh+gk+hk+(g+h)x_1+(g+k)x_2+x_1x_2 +` +is bent. +::: + +:::theorem "carlet-6-theorem-9-flat-switching" (parent := "carlet-chapter-6") (lean := "CryptBoolean.flatSwitch, CryptBoolean.IsBalancedOnAffineFlat, CryptBoolean.IsConstantOrBalancedOnAffineFlat, CryptBoolean.affineFlatWalshSum, CryptBoolean.walshTransform_sub_flatSwitch, CryptBoolean.affineFlatWalshSum_eq_bitSignInt_mul_walshTransform_restriction, CryptBoolean.affineSubspaceRestrictionImbalance_bentDual_add_linear, CryptBoolean.abs_affineSubspaceRestrictionImbalance_bentDual_add_linear, CryptBoolean.autocorrelation_flatSwitch, CryptBoolean.isBent_flatSwitch_iff_derivative_balanced_on_affineFlat, CryptBoolean.isBent_flatSwitch_iff_bentDual_add_linear_constant_or_balanced, CryptBoolean.derivative_balanced_on_affineFlat_iff_bentDual_add_linear_constant_or_balanced, CryptBoolean.two_pow_half_dvd_walshTransform_affineFlatRestriction, CryptBoolean.half_dimension_le_finrank_of_isBent_flatSwitch, CryptBoolean.functionAlgebraicDegree_affineFlatRestriction_le_of_isBent_flatSwitch, CryptBoolean.isBent_flatSwitch_of_half_dimension_of_restriction_degree_le_one") (uses := "carlet-6-theorem-8-perfect-nonlinearity, carlet-6-rel-46-dual-poisson, carlet-2-prop-11-walsh-divisibility, carlet-3-prop-12") (tags := "carlet, chapter-6, theorem-9, pages-90-91, fidelity-exact") +*Theorem 9 (Carlet, pp. 90--91).* Let $`f` be bent on $`V_n`, let +$`b+E` be an affine flat, and put $`f^*=f+\mathbf1_{b+E}`. Then $`f^*` is +bent if and only if either of the following equivalent conditions holds: + +1. for every $`a\notin E`, the derivative $`D_af` is balanced on $`b+E`; +2. on every coset of $`E^\perp`, the restriction of + $`\widetilde f(x)+b\mathbin\cdot x` is constant or balanced. + +If both $`f` and $`f^*` are bent, then $`\dim E\ge n/2` and the restriction +of $`f` to $`b+E` has algebraic degree at most +$`\dim E-n/2+1`. Conversely, if $`\dim E=n/2` and that restriction is +affine, then $`f^*` is bent. +::: + +:::theorem "carlet-6-theorem-10-slice-construction" (parent := "carlet-chapter-6") (lean := "CryptBoolean.firstBlockSlice, CryptBoolean.dualSliceFunction, CryptBoolean.walshTransform_eq_two_pow_half_mul_walshTransform_dualSliceFunction, CryptBoolean.isBent_iff_forall_isBent_dualSliceFunction, CryptBoolean.bentDual_append_eq_bentDual_dualSliceFunction") (uses := "carlet-6-def-7-bent, carlet-6-dual") (tags := "carlet, chapter-6, theorem-10, pages-91-92, fidelity-exact") +*Theorem 10 (Carlet, pp. 91--92).* Let $`n,m` be even and let +$`f:V_n\times V_m\to\mathbb F_2`. Suppose every slice +$`f_y(x)=f(x,y)` is bent, and define $`\varphi_s(y)=\widetilde{f_y}(s)`. +Then $`f` is bent if and only if every $`\varphi_s` is bent. In that case +$$` +\widetilde f(s,t)=\widetilde{\varphi_s}(t). +` +::: + +:::theorem "carlet-6-indirect-sum" (parent := "carlet-chapter-6") (lean := "CryptBoolean.indirectSum, CryptBoolean.indirectSum_append, CryptBoolean.isBent_indirectSum, CryptBoolean.bentDual_indirectSum_append") (uses := "carlet-6-theorem-10-slice-construction") (tags := "carlet, chapter-6, indirect-sum, page-92, fidelity-exact") +*Indirect sum (Carlet, p. 92).* If $`f_1,f_2` are bent on $`V_n` and +$`g_1,g_2` are bent on $`V_m`, then +$$` +h(x,y)=f_1(x)+g_1(y)+(f_1+f_2)(x)(g_1+g_2)(y) +` +is bent. Its dual is obtained by applying the same formula to the four +duals. +::: + +:::proposition "carlet-6-prop-21-permutation-reindexing" (parent := "carlet-chapter-6") (lean := "CryptBoolean.hammingDistance_comp_perm, CryptBoolean.hammingDistance_comp_perm_symm_linearFunction, CryptBoolean.walshTransform_comp_perm_symm_eq_two_pow_sub_two_hammingDistance, CryptBoolean.isBent_comp_perm_symm_of_hammingDistance") (uses := "carlet-6-def-7-bent, carlet-2-def-hamming-distance") (tags := "carlet, chapter-6, proposition-21, pages-93-94, fidelity-exact") +*Proposition 21 (Carlet, pp. 93--94).* Let $`\sigma` be a permutation of +$`V_n`, with coordinate functions $`\sigma_1,\ldots,\sigma_n`. If +$$` +d_H\!\left(f,\sum_{i=1}^n a_i\sigma_i\right) +=2^{n-1}\pm2^{n/2-1} +\qquad(a\in V_n), +` +then $`f\circ\sigma^{-1}` is bent. +::: + +:::proposition "carlet-6-prop-22-three-function-identity" (parent := "carlet-chapter-6") (lean := "CryptBoolean.threeFunctionSum, CryptBoolean.threeFunctionPairwiseProductSum, CryptBoolean.bitValueInt_threeFunctionIdentity, CryptBoolean.rawFourierTransform_threeFunctionIdentity, CryptBoolean.walshTransform_cast_eq_rawFourierTransform_sub_two_mul, CryptBoolean.walshTransform_threeFunctionIdentity") (uses := "carlet-2-pseudoboolean-fourier, carlet-2-def-walsh-transform") (tags := "carlet, chapter-6, proposition-22, relation-50, pages-94-95, fidelity-exact") +*Proposition 22 (Carlet, Relation (50), pp. 94--95).* For Boolean functions +$`f_1,f_2,f_3`, put +$$` +s_1=f_1+f_2+f_3, +\qquad +s_2=f_1f_2+f_1f_3+f_2f_3. +` +As integer-valued functions, $`f_1+f_2+f_3=s_1+2s_2`; consequently +$$` +W_{f_1}+W_{f_2}+W_{f_3}=W_{s_1}+2W_{s_2}. +` +::: + +:::corollary "carlet-6-cor-4-three-function-construction" (parent := "carlet-chapter-6") (lean := "CryptBoolean.isBent_threeFunctionPairwiseProductSum_and_bentDual_eq, CryptBoolean.isBent_threeFunctionSum_of_two_pow_half_dvd_walshTransform") (uses := "carlet-6-prop-22-three-function-identity, carlet-6-lemma-2-walsh-congruence, carlet-6-dual") (tags := "carlet, chapter-6, corollary-4, page-95, fidelity-exact") +*Corollary 4 (Carlet, p. 95).* Suppose $`f_1,f_2,f_3` are bent. If +$`s_1=f_1+f_2+f_3` is bent and +$`\widetilde{s_1}=\widetilde f_1+\widetilde f_2+\widetilde f_3`, then +$`s_2=f_1f_2+f_1f_3+f_2f_3` is bent and +$$` +\widetilde{s_2} +=\widetilde f_1\widetilde f_2+ + \widetilde f_1\widetilde f_3+ + \widetilde f_2\widetilde f_3. +` +Conversely, if $`2^{n/2}` divides every Walsh coefficient of $`s_2`, then +$`s_1` is bent. +::: diff --git a/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Superclasses.lean b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Superclasses.lean new file mode 100644 index 0000000..60651be --- /dev/null +++ b/blueprint-verso/CryptBooleanBlueprint/Carlet/Chapter06/Superclasses.lean @@ -0,0 +1,162 @@ +/- +Copyright (c) 2026 Asher Yan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Asher Yan with Codex +-/ +import Verso +import VersoManual +import VersoBlueprint +import CryptBoolean.Carlet.Chapter06.PartialBent +import CryptBoolean.Carlet.Chapter06.PartialBentCounterexamples +import CryptBoolean.Carlet.Chapter06.PartialBentDual +import CryptBoolean.Carlet.Chapter06.PartiallyBent +import CryptBoolean.Carlet.Chapter06.PlateauedOrphan +import CryptBoolean.Carlet.Chapter06.PlateauedSecondOrder +import CryptBoolean.Carlet.Chapter06.PlateauedSupport + +open Verso.Genre +open Verso.Genre.Manual +open Informal + +#doc (Manual) "Superclasses of bent functions" => + +:::proposition "carlet-6-prop-26-partially-bent" (parent := "carlet-chapter-6") (lean := "CryptBoolean.autocorrelationSupport, CryptBoolean.mem_autocorrelationSupport, CryptBoolean.nonzeroAutocorrelationCount, CryptBoolean.rawFourierSupport_autocorrelation, CryptBoolean.two_pow_le_nonzeroAutocorrelationCount_mul_card_walshSupport, CryptBoolean.IsPartiallyBent, CryptBoolean.isPartiallyBent_of_functionAlgebraicDegree_le_two, CryptBoolean.HasBentAffineComplementDecomposition, CryptBoolean.HasBentAffineComplementDecomposition.isPartiallyBent, CryptBoolean.HasBentAffineComplementDecomposition.linearKernel_eq_affineSubspace, CryptBoolean.HasBentAffineComplementDecomposition.dimensions_add, CryptBoolean.HasBentAffineComplementDecomposition.even_bentDimension, CryptBoolean.exists_hasBentAffineComplementDecomposition_of_isPartiallyBent, CryptBoolean.isPartiallyBent_iff_exists_bentAffineComplementDecomposition, CryptBoolean.isLinearStructure_iff_abs_autocorrelation_eq_two_pow, CryptBoolean.isPartiallyBent_of_nonzeroAutocorrelationCount_mul_card_walshSupport_eq, CryptBoolean.nonzeroAutocorrelationCount_mul_card_walshSupport_eq_of_isPartiallyBent, CryptBoolean.nonzeroAutocorrelationCount_mul_card_walshSupport_eq_two_pow_iff, CryptBoolean.HasBentAffineComplementDecomposition.nonzeroAutocorrelationCount_eq, CryptBoolean.hasPlateauedWalshSpectrum_of_isPartiallyBent, CryptBoolean.IsPartiallyBent.isPlateaued, CryptBoolean.isPlateaued_of_functionAlgebraicDegree_le_two, CryptBoolean.HasBentAffineComplementDecomposition.hasPlateauedWalshAmplitude") (uses := "carlet-2-rel-25-wiener-khinchin, carlet-2-parseval, carlet-4-def-linear-kernel, carlet-6-def-plateaued") (tags := "carlet, chapter-6, proposition-26, relation-53, pages-103-104, fidelity-exact") +*Proposition 26 (Carlet, Relation (53), pp. 103--104).* For a Boolean +function $`f:V_n\to\mathbb F_2`, let +$$` +N_{\Delta_f}=|\{b:\Delta_f(b)\ne0\}|, +\qquad +N_{W_f}=|\{u:W_f(u)\ne0\}|. +` +Then $`N_{\Delta_f}N_{W_f}\ge2^n`. Equality holds if and only if every +derivative $`D_bf` is balanced or constant. Equivalently, there are +complementary subspaces $`E,E'` and functions $`g,h`, with $`g` bent on +$`E` and $`h` affine on $`E'`, such that +$$` +f(x+y)=g(x)+h(y) +\qquad(x\in E,\ y\in E'). +` +Such functions are called partially bent. Every quadratic function is +partially bent, and every partially bent function is plateaued. +::: + +:::proposition "carlet-6-prop-27-fourier-uncertainty" (parent := "carlet-chapter-6") (lean := "CryptBoolean.pseudoBooleanSupport, CryptBoolean.mem_pseudoBooleanSupport, CryptBoolean.two_pow_le_card_pseudoBooleanSupport_mul_card_rawFourierSupport, CryptBoolean.IsModulatedAffineFlatIndicator, CryptBoolean.IsModulatedAffineFlatIndicator.card_support_mul_card_rawFourierSupport_eq, CryptBoolean.isModulatedAffineFlatIndicator_of_card_support_mul_card_rawFourierSupport_eq, CryptBoolean.card_support_mul_card_rawFourierSupport_eq_two_pow_iff") (uses := "carlet-2-pseudoboolean-fourier, carlet-2-parseval, carlet-2-cor-1-poisson-summation") (tags := "carlet, chapter-6, proposition-27, pages-104-105, fidelity-exact-nonzero-modulation") +*Proposition 27 (Carlet, pp. 104--105).* Let +$`\varphi:V_n\to\mathbb R` be nonzero, and write +$$` +N_\varphi=|\{x:\varphi(x)\ne0\}|, +\qquad +N_{\widehat\varphi}=|\{u:\widehat\varphi(u)\ne0\}|. +` +Then $`N_\varphi N_{\widehat\varphi}\ge2^n`. Equality holds if and only if +there are a nonzero real number $`\lambda`, a frequency $`u`, and an affine +flat $`F` such that +$$` +\varphi(x)= +\begin{cases} +\lambda(-1)^{u\mathbin\cdot x},&x\in F,\\ +0,&x\notin F. +\end{cases} +` +::: + +:::definition "carlet-6-def-partial-bent" (parent := "carlet-chapter-6") (lean := "CryptBoolean.HasPartialBentFourierLevels, CryptBoolean.IsPartialBent, CryptBoolean.partialBentIntegerFourier, CryptBoolean.partialBentIntegerFourier_cast") (uses := "carlet-2-pseudoboolean-fourier") (tags := "carlet, chapter-6, partial-bent, page-105, fidelity-exact") +*Partial bent functions (Carlet, p. 105).* Let $`n` be even. A Boolean +function $`f:V_n\to\mathbb F_2` is partial bent if there is an integer +$`\lambda` such that, on $`V_n\setminus\{0\}`, its raw Fourier transform as +a $`\{0,1\}`-valued function takes exactly the two values $`\lambda` and +$`\lambda+2^{n/2}`. +::: + +:::theorem "carlet-6-partial-bent-duality" (parent := "carlet-chapter-6") (lean := "CryptBoolean.partialBentDual, CryptBoolean.partialBentDual_zero, CryptBoolean.exists_partialBentDual_fourierLevels, CryptBoolean.partialBentDual_involution, CryptBoolean.exists_isPartialBent_partialBentDual_and_involution") (uses := "carlet-6-def-partial-bent, carlet-2-cor-2-fourier-involution") (tags := "carlet, chapter-6, partial-bent, duality, page-105, fidelity-formal-zero-frequency-convention") +*Duality for partial bent functions (Carlet, p. 105).* Let $`f` be partial +bent with Fourier levels $`\lambda` and $`\lambda+2^{n/2}`. Define its dual +at zero by $`\widetilde f(0)=f(0)` and, for every nonzero $`u`, by +$$` +\widetilde f(u)= +\begin{cases} +0,&\widehat f(u)=\lambda,\\ +1,&\widehat f(u)=\lambda+2^{n/2}. +\end{cases} +` +Then $`\widetilde f` is partial bent and $`\widetilde{\widetilde f}=f`. +::: + +:::theorem "carlet-6-partial-bent-degree-bound" (parent := "carlet-chapter-6") (lean := "CryptBoolean.partialBentDegreeCounterexample, CryptBoolean.partialBentDegreeCounterexample_refutes_bound") (uses := "carlet-6-def-partial-bent, carlet-6-prop-18-rothaus-degree-bound") (tags := "carlet, chapter-6, partial-bent, algebraic-degree, rothaus-bound, counterexample, page-105, fidelity-source-error-exact-two-level-counterexample") +*Counterexample to the printed partial-bent degree bound (Carlet, p. 105).* +On $`V_2`, let $`f` be the indicator of the point $`(1,0)`. Then $`f` is +partial bent, but +$$` +\deg_{\mathrm{alg}}(f)=2>2/2. +` +Thus the printed half-dimension bound requires additional regularity +hypotheses beyond the exact punctured two-level definition. +::: + +:::theorem "carlet-6-partial-bent-types" (parent := "carlet-chapter-6") (lean := "CryptBoolean.partialBent_fourier_level_types") (uses := "carlet-6-def-partial-bent, carlet-2-parseval") (tags := "carlet, chapter-6, partial-bent, types, parseval, page-105, fidelity-source-correction-type-formula") +*The two types of partial bent functions (Carlet, p. 105; corrected).* Let +$`n>0` be even, put $`q=2^{n/2}` and $`e=f(0)`, and let $`f` be partial +bent with Fourier levels $`\lambda` and $`\lambda+q`. Exactly one of the +two identities +$$` +\widehat f(0)-e=-(\lambda-e)(q-1) +` +and +$$` +\widehat f(0)-e=(q+\lambda-e)(q+1) +` +holds; these alternatives define the two types. +::: + +:::theorem "carlet-6-partial-bent-disjoint-support-sum" (parent := "carlet-chapter-6") (lean := "CryptBoolean.partialBentSumCounterexampleCompanion, CryptBoolean.partialBentCounterexamples_refute_disjoint_support_sum") (uses := "carlet-6-def-partial-bent, carlet-6-partial-bent-types, carlet-2-pseudoboolean-fourier") (tags := "carlet, chapter-6, partial-bent, sum, supports, counterexample, page-105, fidelity-source-error-exact-two-level-counterexample") +*Counterexample to the printed partial-bent sum assertion (Carlet, p. 105).* +On $`V_2`, let $`f` be the indicator of $`\{(1,0)\}` and let $`g(x)=x_2`, +the indicator of $`\{(0,1),(1,1)\}`. Their punctured Fourier levels are +$`\{-1,1\}` and $`\{-2,0\}`, respectively. Both functions are partial bent +of the corrected first type, and +$$` +\operatorname{supp}(f)\cap\operatorname{supp}(g)\subseteq\{0\}. +` +Nevertheless, $`f+g` is not partial bent. Hence the printed closure assertion +also requires an additional regularity convention. +::: + +:::definition "carlet-6-def-plateaued" (parent := "carlet-chapter-6") (lean := "CryptBoolean.HasPlateauedWalshAmplitude, CryptBoolean.IsPlateaued, CryptBoolean.isPlateaued_iff_hasPlateauedWalshSpectrum, CryptBoolean.isBent_iff_isPlateaued_and_forall_walshTransform_ne_zero, CryptBoolean.card_walshSupport_mul_amplitude_sq_eq_two_pow_two_mul, CryptBoolean.exists_plateauedAmplitudeExponent, CryptBoolean.two_pow_add_one_div_two_dvd_walshTransform_of_hasPlateauedWalshAmplitude") (uses := "carlet-2-def-walsh-transform, carlet-2-parseval, carlet-6-def-7-bent") (tags := "carlet, chapter-6, plateaued, pages-105-106, fidelity-exact") +*Plateaued functions (Carlet, pp. 105--106).* A Boolean function is +plateaued with amplitude $`\lambda>0` when every Walsh coefficient belongs +to $`\{0,\lambda,-\lambda\}`. A plateaued function is bent exactly when +its Walsh transform has full support. Parseval's identity forces +$`\lambda=2^r` with $`2r\ge n`; consequently every Walsh coefficient is +divisible by $`2^{\lceil n/2\rceil}`. +::: + +:::theorem "carlet-6-plateaued-support-nonlinearity" (parent := "carlet-chapter-6") (lean := "CryptBoolean.maxWalshMagnitude_eq_of_hasPlateauedWalshAmplitude, CryptBoolean.sum_walshTransform_sq_walshSupport, CryptBoolean.two_pow_sq_le_card_walshSupport_mul_maxWalshMagnitude_sq, CryptBoolean.two_pow_sq_eq_card_walshSupport_mul_maxWalshMagnitude_sq_iff_plateaued, CryptBoolean.nonlinearity_cast_le_walshSupport_bound, CryptBoolean.nonlinearity_cast_eq_walshSupport_bound_iff_plateaued") (uses := "carlet-6-def-plateaued, carlet-4-rel-35-nonlinearity-walsh, carlet-2-parseval") (tags := "carlet, chapter-6, plateaued, page-106, fidelity-exact") +*Walsh-support bound (Carlet, p. 106).* If $`N_{W_f}` is the cardinality +of the Walsh support of $`f:V_n\to\mathbb F_2`, then +$$` +\operatorname{nl}(f) +\le 2^{n-1}\left(1-\frac1{\sqrt{N_{W_f}}}\right). +` +Equality holds if and only if $`f` is plateaued. +::: + +:::proposition "carlet-6-prop-28-second-order-plateaued" (parent := "carlet-chapter-6") (lean := "CryptBoolean.hasPlateauedWalshAmplitude_iff_forall_walshTransform_cube_eq, CryptBoolean.isPlateaued_iff_exists_forall_secondDerivativeDoubleSum_eq_sq") (uses := "carlet-6-def-plateaued, carlet-6-prop-24-second-order-characterization") (tags := "carlet, chapter-6, proposition-28, relation-55, page-106, fidelity-exact") +*Proposition 28 (Carlet, Relation (55), p. 106).* A Boolean function +$`f:V_n\to\mathbb F_2` is plateaued if and only if there is a positive +integer $`\lambda` such that, for every $`x\in V_n`, +$$` +\sum_{a,b\in V_n}(-1)^{D_aD_bf(x)}=\lambda^2. +` +The integer $`\lambda` is the Walsh amplitude. +::: + +:::theorem "carlet-6-plateaued-coset-orphan" (parent := "carlet-chapter-6") (lean := "CryptBoolean.IsFirstOrderCosetLeader, CryptBoolean.FirstOrderCosetBelow, CryptBoolean.IsFirstOrderOrphan, CryptBoolean.IsPlateaued.add_affineFunction, CryptBoolean.eq_of_plateaued_cosetLeaders_of_support_subset, CryptBoolean.isFirstOrderOrphan_of_isPlateaued") (uses := "carlet-6-def-plateaued, carlet-6-plateaued-support-nonlinearity, carlet-3-reed-muller-code, carlet-4-def-nonlinearity, carlet-2-parseval") (tags := "carlet, chapter-6, plateaued, orphan, page-106, fidelity-source-correction-non-affine-hypothesis") +*Langevin's orphan theorem (Carlet, p. 106).* Order the cosets of +$`R(1,n)` as follows: $`g+R(1,n)` is below $`f+R(1,n)` when there are +minimum-weight representatives $`g_1` and $`f_1` of the respective cosets +such that $`\operatorname{supp}(g_1)\subseteq\operatorname{supp}(f_1)`. +A maximal coset for this order is called an orphan. If $`f` is plateaued and +$`f\notin R(1,n)`, then $`f+R(1,n)` is an orphan. The non-affine hypothesis +is necessary: affine functions are plateaued, while $`R(1,n)` is the least +coset in this order. +::: diff --git a/blueprint-verso/scripts/check_statement_style.py b/blueprint-verso/scripts/check_statement_style.py index 61a003c..ad6f958 100644 --- a/blueprint-verso/scripts/check_statement_style.py +++ b/blueprint-verso/scripts/check_statement_style.py @@ -119,9 +119,9 @@ def main() -> None: errors.append(f"{location}: {block.identifier} must have {expected}, but not both") formalized = sum("(lean :=" in block.header for block in blocks) open_count = sum("source-open" in block.header for block in blocks) - if (len(blocks), formalized, open_count) != (149, 146, 3): + if (len(blocks), formalized, open_count) != (209, 206, 3): errors.append( - "expected 149 statements split into 146 formalized and 3 open; " + "expected 209 statements split into 206 formalized and 3 open; " f"found {len(blocks)}, {formalized}, and {open_count}" ) if errors: diff --git a/blueprint-verso/scripts/validate_manifest.py b/blueprint-verso/scripts/validate_manifest.py index 7839d93..4b34a28 100755 --- a/blueprint-verso/scripts/validate_manifest.py +++ b/blueprint-verso/scripts/validate_manifest.py @@ -8,21 +8,23 @@ from pathlib import Path -EXPECTED_STATEMENTS = 149 -EXPECTED_FORMALIZED = 146 -EXPECTED_DECLARATIONS = 961 -EXPECTED_EDGES = 296 +EXPECTED_STATEMENTS = 209 +EXPECTED_FORMALIZED = 206 +EXPECTED_DECLARATIONS = 1338 +EXPECTED_EDGES = 467 EXPECTED_CHAPTERS = { - "chapter-2": 38, + "chapter-2": 41, "chapter-3": 7, "chapter-4": 73, "chapter-5": 31, + "chapter-6": 57, } EXPECTED_GROUPS = { - "«carlet-chapter-2»": 38, + "«carlet-chapter-2»": 41, "«carlet-chapter-3»": 7, "«carlet-chapter-4»": 73, "«carlet-chapter-5»": 31, + "«carlet-chapter-6»": 57, } EXPECTED_OPEN = { "carlet-5-theorem-7-weil-bound", diff --git a/lakefile.lean b/lakefile.lean index 544d2ae..f87419b 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -5,7 +5,7 @@ open Lake DSL require FABL from git "https://github.com/Polarnova/FABL.git" @ "v0.5.6" package CryptBooleanFunction where - version := v!"0.4.1" + version := v!"0.5.0" description := "Cryptographic Boolean Functions in Lean" keywords := #["mathematics", "boolean-functions", "cryptography", "formalization"] license := "Apache-2.0"