Skip to content

Commit 6e8f675

Browse files
feat: statement of the Binary Basefold protocol
1 parent a379a55 commit 6e8f675

14 files changed

Lines changed: 6705 additions & 573 deletions

File tree

ArkLib.lean

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,10 @@ import ArkLib.OracleReduction.Security.RoundByRound
138138
import ArkLib.OracleReduction.Security.SpecialSoundness
139139
import ArkLib.OracleReduction.Security.StateRestoration
140140
import ArkLib.OracleReduction.VectorIOR
141-
import ArkLib.ProofSystem.Binius.Basic
141+
import ArkLib.ProofSystem.Binius.BinaryBasefold.FoldPhase
142+
import ArkLib.ProofSystem.Binius.BinaryBasefold.General
143+
import ArkLib.ProofSystem.Binius.BinaryBasefold.Prelude
144+
import ArkLib.ProofSystem.Binius.BinaryBasefold.QueryPhase
142145
import ArkLib.ProofSystem.Component.CheckClaim
143146
import ArkLib.ProofSystem.Component.DoNothing
144147
import ArkLib.ProofSystem.Component.NoInteraction

ArkLib/Data/FieldTheory/AdditiveNTT/AdditiveNTT.lean

Lines changed: 912 additions & 341 deletions
Large diffs are not rendered by default.

ArkLib/Data/FieldTheory/AdditiveNTT/NovelPolynomialBasis.lean

Lines changed: 296 additions & 184 deletions
Large diffs are not rendered by default.

ArkLib/Data/Nat/Bitwise.lean

Lines changed: 111 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ import Mathlib.Algebra.BigOperators.Fin
1515

1616
/-!
1717
# Bit operations on natural numbers
18-
1918
-/
20-
2119
namespace Nat
2220

2321
-- Note: this is already done with `Nat.sub_add_eq_max`
@@ -26,6 +24,19 @@ theorem max_eq_add_sub {m n : Nat} : Nat.max m n = m + (n - m) := by
2624
· simp [Nat.sub_eq_zero_of_le, h]
2725
· simp only [Nat.max_eq_right (Nat.le_of_not_le h), Nat.add_sub_of_le (Nat.le_of_not_le h)]
2826

27+
theorem sub_add_eq_sub_sub_rev (a b c : Nat) (h1 : c ≤ b) (h2 : b ≤ a) :
28+
a - b + c = a - (b - c) := by
29+
conv =>
30+
rhs
31+
rw [← Nat.sub_add_cancel h2]
32+
rw [Nat.add_sub_assoc (Nat.sub_le b c)]
33+
rw [Nat.sub_sub_self h1]
34+
35+
@[simp]
36+
lemma lt_add_of_pos_right_of_le (a b c : ℕ) [NeZero c] (h : a ≤ b) : a < b + c := by
37+
apply Nat.lt_of_le_of_lt (n:=a) (m:=b) (k:=b + c) h
38+
apply Nat.lt_add_of_pos_right (by exact pos_of_neZero c)
39+
2940
/--
3041
Returns the `k`-th least significant bit of a natural number `n` as a natural number (in `{0, 1}`).
3142
@@ -135,7 +146,8 @@ lemma eq_iff_eq_all_getBits {n m : ℕ} : n = m ↔ ∀ k, getBit k n = getBit k
135146
rw [h_all_getBits k]
136147

137148
lemma shiftRight_and_one_distrib {n m k : ℕ} :
138-
(n &&& m) >>> k &&& 1 = ((n >>> k) &&& 1) &&& ((m >>> k) &&& 1) := by
149+
Nat.getBit k (n &&& m) = Nat.getBit k n &&& Nat.getBit k m := by
150+
unfold getBit
139151
rw [Nat.shiftRight_and_distrib]
140152
conv =>
141153
lhs
@@ -145,26 +157,26 @@ lemma shiftRight_and_one_distrib {n m k : ℕ} :
145157
rw [Nat.and_assoc]
146158

147159
lemma and_eq_zero_iff_and_each_getBit_eq_zero {n m : ℕ} :
148-
n &&& m = 0 ↔ ∀ k, ((n >>> k) &&& 1) &&& ((m >>> k) &&& 1) = 0 := by
160+
n &&& m = 0 ↔ ∀ k, Nat.getBit k n &&& Nat.getBit k m = 0 := by
149161
constructor
150162
· intro h_and_zero
151163
intro k
152164
have h_k := shiftRight_and_one_distrib (n := n) (m := m) (k := k)
153165
rw [←h_k]
154-
rw [h_and_zero, Nat.zero_shiftRight, Nat.zero_and]
166+
rw [h_and_zero, getBit, Nat.zero_shiftRight, Nat.zero_and]
155167
· intro h_forall_k -- h_forall_k : ∀ (k : ℕ), n >>> k &&& 1 &&& (m >>> k &&& 1) = 0
156168
apply eq_iff_eq_all_getBits.mpr
157169
unfold getBit
158170
intro k
159171
-- ⊢ (n &&& m) >>> k &&& 1 = 0 >>> k &&& 1
160172
have h_forall_k_eq : ∀ k, ((n &&& m) >>> k) &&& 1 = 0 := by
161173
intro k
162-
rw [shiftRight_and_one_distrib]
174+
rw [←getBit, shiftRight_and_one_distrib]
163175
exact h_forall_k k
164176
rw [h_forall_k_eq k]
165177
rw [Nat.zero_shiftRight, Nat.zero_and]
166178

167-
lemma getBit_two_pow {i k: ℕ} : (getBit k (2^i) = if i == k then 1 else 0) := by
179+
lemma getBit_two_pow {i k : ℕ} : (getBit k (2^i) = if i == k then 1 else 0) := by
168180
have h_two_pow_i: 2^i = 1 <<< i := by
169181
simp only [Nat.shiftLeft_eq, one_mul]
170182
rw [getBit, h_two_pow_i]
@@ -215,19 +227,20 @@ lemma getBit_two_pow {i k: ℕ} : (getBit k (2^i) = if i == k then 1 else 0) :=
215227
omega
216228
rw [h_res]
217229

218-
lemma and_two_pow_eq_zero_of_getBit_0 {n i : ℕ} (h_getBit: getBit i n = 0) : n &&& (2 ^ i) = 0 := by
230+
lemma and_two_pow_eq_zero_of_getBit_0 {n i : ℕ} (h_getBit : getBit i n = 0)
231+
: n &&& (2 ^ i) = 0 := by
219232
apply and_eq_zero_iff_and_each_getBit_eq_zero.mpr
220233
intro k
221234
have h_getBit_two_pow := getBit_two_pow (i := i) (k := k)
222235
if h_k: k = i then
223236
simp only [h_k, BEq.rfl, ↓reduceIte] at h_getBit_two_pow
224237
rw [getBit, h_k.symm] at h_getBit
225-
rw [h_getBit, Nat.zero_and]
238+
rw [getBit, h_getBit, Nat.zero_and]
226239
else
227240
push_neg at h_k
228241
simp only [beq_iff_eq, h_k.symm, ↓reduceIte] at h_getBit_two_pow
229242
rw [getBit] at h_getBit_two_pow
230-
rw [h_getBit_two_pow]
243+
rw [getBit, getBit, h_getBit_two_pow]
231244
rw [Nat.and_zero]
232245

233246
lemma and_two_pow_eq_two_pow_of_getBit_1 {n i : ℕ} (h_getBit: getBit i n = 1) :
@@ -1203,4 +1216,92 @@ lemma getBit_of_binaryFinMapToNat {n : ℕ} (m : Fin n → ℕ) (h_binary: ∀ j
12031216
simp only [ite_eq_right_iff, one_ne_zero, imp_false, ne_eq]
12041217
omega
12051218

1219+
/-- Middle bits: take `len` bits starting at `offset` from `n`. -/
1220+
def getMiddleBits (offset len n : ℕ) : ℕ :=
1221+
getLowBits (numLowBits:=len) (n:=n >>> offset)
1222+
1223+
/-- Bit-level characterization of middle bits. -/
1224+
lemma getBit_of_middleBits {n offset len k : ℕ} :
1225+
getBit k (getMiddleBits offset len n) =
1226+
if k < len then getBit (k + offset) n else 0 := by
1227+
unfold getMiddleBits
1228+
-- use existing lemmas
1229+
rw [getBit_of_lowBits, getBit_of_shiftRight]
1230+
1231+
/-- Middle bits are strictly less than `2^len`. -/
1232+
lemma getMiddleBits_lt_two_pow {n offset len : ℕ} :
1233+
getMiddleBits offset len n < 2 ^ len := by
1234+
unfold getMiddleBits
1235+
exact getLowBits_lt_two_pow (n := n >>> offset) len
1236+
1237+
/-- Middle bits as a modulus form. -/
1238+
lemma getMiddleBits_eq_mod {n offset len : ℕ} :
1239+
getMiddleBits offset len n = (n >>> offset) % (2 ^ len) := by
1240+
unfold getMiddleBits
1241+
exact getLowBits_eq_mod_two_pow (n := n >>> offset) (numLowBits := len)
1242+
1243+
lemma and_shl_eq_zero_of_lt_two_pow {a n b : ℕ} (hb : b < 2 ^ n) : (a <<< n) &&& b = 0 := by
1244+
apply Nat.and_eq_zero_iff_and_each_getBit_eq_zero.mpr
1245+
intro k
1246+
rw [getBit_of_shiftLeft]
1247+
rw [getBit_of_lt_two_pow (a := ⟨b, hb⟩)]
1248+
split_ifs with h_k_lt_n
1249+
· simp only [Nat.zero_and]
1250+
· simp only [Nat.and_zero]
1251+
1252+
/-- Concatenate high (length m) and low (length n) using shifts. -/
1253+
def joinBits {n m : ℕ} (low : Fin (2 ^ n)) (high : Fin (2 ^ m)) : Fin (2 ^ (m+n)) :=
1254+
⟨(high.val <<< n) ||| low.val, by
1255+
have h_and_zero := and_shl_eq_zero_of_lt_two_pow (a := high.val) (b := low.val) (hb := low.isLt)
1256+
rw [←Nat.sum_of_and_eq_zero_is_or h_and_zero]
1257+
rw [Nat.shiftLeft_eq, mul_comm, Nat.pow_add]
1258+
-- ⊢ 2 ^ n * ↑high + ↑low < 2 ^ m * 2 ^ n
1259+
calc
1260+
2 ^ n * high.val + low.val < 2 ^ n * high.val + 2 ^ n := by
1261+
exact Nat.add_lt_add_left low.isLt _
1262+
_ = 2 ^ n * (high.val + 1) := by rw [Nat.mul_add, Nat.mul_one]
1263+
_ ≤ 2 ^ n * (2 ^ m) := by -- `high.val < 2^m` implies `high.val + 1 ≤ 2^m`
1264+
exact Nat.mul_le_mul_left _ (Nat.succ_le_of_lt high.isLt)
1265+
_ = 2 ^ m * 2 ^ n := by rw [mul_comm]
1266+
1267+
1268+
/-- Bit characterization: below cut use low, above cut use high. -/
1269+
lemma getBit_joinBits {n m k : ℕ} (low : Fin (2 ^ n)) (high : Fin (2 ^ m)) :
1270+
getBit k (joinBits low high).val =
1271+
if k < n then getBit k low.val else getBit (k - n) high.val := by
1272+
unfold joinBits
1273+
dsimp
1274+
rw [getBit_of_or]
1275+
rw [getBit_of_shiftLeft]
1276+
rw [getBit_of_lt_two_pow (a := low)]
1277+
split_ifs with h_k
1278+
· simp only [zero_or]
1279+
· simp only [Nat.or_zero]
1280+
1281+
/-- Low n bits of joinBits are exactly low. -/
1282+
lemma getLowBits_joinBits {n m : ℕ} (low : Fin (2 ^ n)) (high : Fin (2 ^ m)) :
1283+
getLowBits n (joinBits low high).val = low.val := by
1284+
unfold joinBits
1285+
dsimp
1286+
rw [getLowBits_eq_mod_two_pow]
1287+
have h_and_zero := and_shl_eq_zero_of_lt_two_pow (a := high.val) (b := low.val) (hb := low.isLt)
1288+
rw [←Nat.sum_of_and_eq_zero_is_or h_and_zero]
1289+
rw [Nat.shiftLeft_eq, mul_comm, add_mod, mul_mod, mod_self, zero_mul, zero_mod, zero_add]
1290+
rw [Nat.mod_mod]
1291+
exact Nat.mod_eq_of_lt low.isLt
1292+
1293+
/-- Dropping low n bits by shifting right recovers high. -/
1294+
lemma getHighBits_no_shl_joinBits {n m : ℕ} (low : Fin (2 ^ n)) (high : Fin (2 ^ m)) :
1295+
getHighBits_no_shl n (joinBits low high).val = high.val := by
1296+
unfold joinBits getHighBits_no_shl
1297+
dsimp
1298+
have h_and_zero := and_shl_eq_zero_of_lt_two_pow (a := high.val) (b := low.val) (hb := low.isLt)
1299+
rw [←Nat.sum_of_and_eq_zero_is_or h_and_zero]
1300+
rw [Nat.add_shiftRight_distrib h_and_zero]
1301+
rw [Nat.shiftLeft_shiftRight]
1302+
rw [Nat.shiftRight_eq_div_pow]
1303+
have h: low.val/2^n = 0 := by
1304+
apply Nat.div_eq_zero_iff_lt (x:=low) (k:=2^n) (h:=by exact Nat.two_pow_pos n).mpr (by omega)
1305+
simp only [h, add_zero]
1306+
12061307
end Nat

ArkLib/Data/Polynomial/Frobenius.lean

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ section FieldVanishingPolynomialEquality
2626
The polynomial `X^q - X` factors into the product of `(X - c)` ∀ `c` ∈ `Fq`,
2727
i.e. `∏_{c ∈ Fq} (X - c) = X^q - X`.
2828
-/
29-
theorem prod_X_sub_C_eq_X_pow_card_sub_X (h_Fq_card_gt_1 : Fintype.card Fq > 1):
29+
theorem prod_X_sub_C_eq_X_pow_card_sub_X :
3030
(∏ c ∈ (Finset.univ : Finset Fq), (Polynomial.X - Polynomial.C c)) =
3131
Polynomial.X^(Fintype.card Fq) - Polynomial.X := by
3232

@@ -46,7 +46,7 @@ theorem prod_X_sub_C_eq_X_pow_card_sub_X (h_Fq_card_gt_1 : Fintype.card Fq > 1):
4646
apply Polynomial.monic_X_pow_sub
4747
-- The condition is that degree(X) < Fintype.card Fq
4848
rw [Polynomial.degree_X]
49-
exact_mod_cast h_Fq_card_gt_1
49+
exact_mod_cast (by exact Fintype.one_lt_card)
5050

5151
have h_roots_P : P.roots = (Finset.univ : Finset Fq).val := by
5252
apply Polynomial.roots_prod_X_sub_C
@@ -74,7 +74,7 @@ theorem prod_X_sub_C_eq_X_pow_card_sub_X (h_Fq_card_gt_1 : Fintype.card Fq > 1):
7474
have degLt : (X : Fq[X]).natDegree < ((X : Fq[X]) ^ Fintype.card Fq).natDegree := by
7575
rw [Polynomial.natDegree_X_pow]
7676
rw [Polynomial.natDegree_X]
77-
exact h_Fq_card_gt_1
77+
exact Fintype.one_lt_card
7878
rw [Polynomial.natDegree_sub_eq_left_of_natDegree_lt degLt]
7979
rw [Polynomial.natDegree_X_pow]
8080

@@ -97,8 +97,7 @@ variable {L : Type*} [CommRing L] [Algebra Fq L]
9797
The identity `∏_{c ∈ Fq} (X - c) = X^q - X` also holds in the polynomial ring `L[X]`,
9898
where `L` is any field extension of `Fq`.
9999
-/
100-
theorem prod_X_sub_C_eq_X_pow_card_sub_X_in_L
101-
(h_Fq_card_gt_1 : Fintype.card Fq > 1):
100+
theorem prod_X_sub_C_eq_X_pow_card_sub_X_in_L :
102101
(∏ c ∈ (Finset.univ : Finset Fq), (Polynomial.X - Polynomial.C (algebraMap Fq L c))) =
103102
Polynomial.X^(Fintype.card Fq) - Polynomial.X := by
104103

@@ -128,14 +127,14 @@ theorem prod_X_sub_C_eq_X_pow_card_sub_X_in_L
128127

129128
-- The goal is now `map f (LHS_base) = map f (RHS_base)`.
130129
-- This is true if `LHS_base = RHS_base`, which is exactly our previous theorem.
131-
rw [prod_X_sub_C_eq_X_pow_card_sub_X h_Fq_card_gt_1]
130+
rw [prod_X_sub_C_eq_X_pow_card_sub_X]
132131

133132
/--
134133
The identity `∏_{c ∈ Fq} (X - c) = X^q - X` also holds in the polynomial ring `L[X]`,
135134
where `L` is any field extension of `Fq`.
136135
-/
137136
theorem prod_poly_sub_C_eq_poly_pow_card_sub_poly_in_L
138-
(h_Fq_card_gt_1 : Fintype.card Fq > 1) (p : L[X]):
137+
(p : L[X]) :
139138
(∏ c ∈ (Finset.univ : Finset Fq), (p - Polynomial.C (algebraMap Fq L c))) =
140139
p^(Fintype.card Fq) - p := by
141140

@@ -148,7 +147,7 @@ theorem prod_poly_sub_C_eq_poly_pow_card_sub_poly_in_L
148147

149148
-- From the previous theorem, we have the base identity in L[X]:
150149
-- `(∏ c, (X - C c)) = X^q - X`
151-
let base_identity := prod_X_sub_C_eq_X_pow_card_sub_X_in_L (L := L) h_Fq_card_gt_1
150+
let base_identity := prod_X_sub_C_eq_X_pow_card_sub_X_in_L (L := L) (Fq:=Fq)
152151

153152
-- `APPROACH : f = g => f.comp(p) = g.comp(p)`
154153
have h_composed_eq : (∏ c ∈ (Finset.univ : Finset Fq), (X - C (algebraMap Fq L c))).comp p
@@ -186,30 +185,28 @@ The Frobenius identity for polynomials in `Fq[X]`.
186185
The `q`-th power of a sum of polynomials is the sum of their `q`-th powers.
187186
-/
188187
theorem frobenius_identity_in_ground_field
189-
{h_Fq_char_prime : Fact (Nat.Prime (ringChar Fq))} (f g : Fq[X]) :
188+
[Fact (Nat.Prime (ringChar Fq))] (f g : Fq[X]) :
190189
(f + g)^(Fintype.card Fq) = f^(Fintype.card Fq) + g^(Fintype.card Fq) := by
191190
-- The Freshman's Dream `(a+b)^e = a^e + b^e` holds if `e` is a power of the characteristic.
192191
-- First, we establish that `q = p^n` where `p` is the characteristic of `Fq`.
193192
let p := ringChar Fq
194-
have h_p_prime : Fact p.Prime := h_Fq_char_prime
195193
obtain ⟨n, hp, hn⟩ := FiniteField.card Fq p
196194
rw [hn]
197195
-- The polynomial ring `Fq[X]` also has characteristic `p`.
198196
haveI : CharP Fq[X] p := Polynomial.charP
199197
-- Apply the general "Freshman's Dream" theorem for prime powers.
200-
exact add_pow_expChar_pow f g p ↑n
198+
exact add_pow_expChar_pow f g p ↑n -- this one requires `h_Fq_char_prime`
201199

202200
variable {L : Type*} [CommRing L] [Algebra Fq L] [Nontrivial L]
203201

204202
/--
205203
The lifted Frobenius identity for polynomials in `L[X]`, where `L` is an `Fq`-algebra.
206204
The exponent `q` is the cardinality of the base field `Fq`.
207205
-/
208-
theorem frobenius_identity_in_algebra {h_Fq_char_prime : Fact (Nat.Prime (ringChar Fq))}
206+
theorem frobenius_identity_in_algebra [Fact (Nat.Prime (ringChar Fq))]
209207
(f g : L[X]) : (f + g)^(Fintype.card Fq) = f^(Fintype.card Fq) + g^(Fintype.card Fq) := by
210208
-- The logic is identical. The key is that `L` inherits the characteristic of `Fq`.
211209
let p := ringChar Fq
212-
haveI : Fact p.Prime := h_Fq_char_prime
213210
obtain ⟨n, hp, hn⟩ := FiniteField.card Fq p
214211

215212
-- Rewrite the goal using `q = p^n`.

ArkLib/OracleReduction/ProtocolSpec/SeqCompose.lean

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,16 @@ instance [O₁ : ∀ i, OracleInterface.{0, u, v} (pSpec₁.Message i)]
379379
(α₁ := pSpec₁.dir) (β₁ := pSpec₂.dir)
380380
(α₂ := pSpec₁.Type) (β₂ := pSpec₂.Type) (fun i h => O₁ ⟨i, h⟩) (fun i h => O₂ ⟨i, h⟩) i h
381381

382+
/-- If two protocols' types have oracle representations, then their concatenation's types also
383+
have oracle representations. -/
384+
instance [O₁ : ∀ i, OracleInterface.{0, u, v} (pSpec₁.Type i)]
385+
[O₂ : ∀ i, OracleInterface.{0, u, v} (pSpec₂.Type i)] :
386+
∀ i, OracleInterface.{0, u, v} ((pSpec₁ ++ₚ pSpec₂).Type i) :=
387+
fun ⟨i, h⟩ => Fin.fappend₂ (A := Direction) (B := Type)
388+
(F := fun _dir type => OracleInterface type)
389+
(α₁ := pSpec₁.dir) (β₁ := pSpec₂.dir)
390+
(α₂ := pSpec₁.Type) (β₂ := pSpec₂.Type) (fun i => O₁ i) (fun i => O₂ i) ⟨i, h⟩
391+
382392
instance : ∀ i, OracleInterface ((pSpec₁ ++ₚ pSpec₂).Challenge i) := challengeOracleInterface
383393

384394
@[simp]

ArkLib/ProofSystem/Binius/Basic.lean

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)