1
1
/-
2
2
Copyright (c) 2018 Chris Hughes. All rights reserved.
3
3
Released under Apache 2.0 license as described in the file LICENSE.
4
- Authors: Chris Hughes
4
+ Authors: Chris Hughes, Michael Stoll
5
5
-/
6
-
7
- import field_theory.finite.basic
8
- import data.zmod.basic
9
- import data.nat.parity
10
6
import number_theory.legendre_symbol.gauss_eisenstein_lemmas
7
+ import number_theory.legendre_symbol.quadratic_char
11
8
12
9
/-!
13
- # Quadratic reciprocity.
10
+ # Legendre symbol and quadratic reciprocity.
14
11
15
12
This file contains results about quadratic residues modulo a prime number.
16
13
@@ -32,8 +29,7 @@ Also proven are conditions for `-1` and `2` to be a square modulo a prime,
32
29
The proof of quadratic reciprocity implemented uses Gauss' lemma and Eisenstein's lemma
33
30
-/
34
31
35
- open function finset nat finite_field zmod
36
- open_locale big_operators nat
32
+ open finset nat char
37
33
38
34
namespace zmod
39
35
@@ -43,21 +39,15 @@ variables (p q : ℕ) [fact p.prime] [fact q.prime]
43
39
lemma euler_criterion_units (x : (zmod p)ˣ) :
44
40
(∃ y : (zmod p)ˣ, y ^ 2 = x) ↔ x ^ (p / 2 ) = 1 :=
45
41
begin
46
- cases nat.prime.eq_two_or_odd (fact.out p.prime) with hp2 hp_odd,
47
- { substI p, refine iff_of_true ⟨1 , _⟩ _; apply subsingleton.elim },
48
- obtain ⟨g, hg⟩ := is_cyclic.exists_generator (zmod p)ˣ,
49
- obtain ⟨n, hn⟩ : x ∈ submonoid.powers g, { rw mem_powers_iff_mem_zpowers, apply hg },
50
- split,
51
- { rintro ⟨y, rfl⟩, rw [← pow_mul, two_mul_odd_div_two hp_odd, units_pow_card_sub_one_eq_one], },
52
- { subst x, assume h,
53
- have key : 2 * (p / 2 ) ∣ n * (p / 2 ),
54
- { rw [← pow_mul] at h,
55
- rw [two_mul_odd_div_two hp_odd, ← card_units, ← order_of_eq_card_of_forall_mem_zpowers hg],
56
- apply order_of_dvd_of_pow_eq_one h },
57
- have : 0 < p / 2 := nat.div_pos (fact.out (1 < p)) dec_trivial,
58
- obtain ⟨m, rfl⟩ := dvd_of_mul_dvd_mul_right this key,
59
- refine ⟨g ^ m, _⟩,
60
- rw [mul_comm, pow_mul], },
42
+ by_cases hc : p = 2 ,
43
+ { substI hc,
44
+ simp only [eq_iff_true_of_subsingleton, exists_const], },
45
+ { have h₀ := finite_field.unit_is_square_iff (by rwa ring_char_zmod_n) x,
46
+ have hs : (∃ y : (zmod p)ˣ, y ^ 2 = x) ↔ is_square(x) :=
47
+ by { rw is_square_iff_exists_sq x,
48
+ simp_rw eq_comm, },
49
+ rw hs,
50
+ rwa card p at h₀, },
61
51
end
62
52
63
53
/-- Euler's Criterion: a nonzero `a : zmod p` is a square if and only if `x ^ (p / 2) = 1`. -/
@@ -116,62 +106,101 @@ lemma pow_div_two_eq_neg_one_or_one {a : zmod p} (ha : a ≠ 0) :
116
106
a ^ (p / 2 ) = 1 ∨ a ^ (p / 2 ) = -1 :=
117
107
begin
118
108
cases nat.prime.eq_two_or_odd (fact.out p.prime) with hp2 hp_odd,
119
- { substI p, revert a ha, exact dec_trivial },
109
+ { substI p, revert a ha, dec_trivial },
120
110
rw [← mul_self_eq_one_iff, ← pow_add, ← two_mul, two_mul_odd_div_two hp_odd],
121
111
exact pow_card_sub_one_eq_one ha
122
112
end
123
113
124
- /-- The Legendre symbol of `a` and `p`, `legendre_sym p a`, is an integer defined as
114
+ /-- The Legendre symbol of `a : ℤ` and a prime `p`, `legendre_sym p a`,
115
+ is an integer defined as
125
116
126
117
* `0` if `a` is `0` modulo `p`;
127
- * `1` if `a ^ (p / 2)` is `1` modulo `p`
128
- (by `euler_criterion` this is equivalent to “`a` is a square modulo `p`”);
118
+ * `1` if `a` is a square modulo `p`
129
119
* `-1` otherwise.
130
120
131
121
Note the order of the arguments! The advantage of the order chosen here is
132
122
that `legendre_sym p` is a multiplicative function `ℤ → ℤ`.
133
123
-/
134
- def legendre_sym (p : ℕ) (a : ℤ) : ℤ :=
135
- if (a : zmod p) = 0 then 0
136
- else if (a : zmod p) ^ (p / 2 ) = 1 then 1
137
- else -1
124
+ def legendre_sym (p : ℕ) [fact p.prime] (a : ℤ) : ℤ := quadratic_char (zmod p) a
138
125
126
+ /-- We have the congruence `legendre_sym p a ≡ a ^ (p / 2) mod p`. -/
139
127
lemma legendre_sym_eq_pow (p : ℕ) (a : ℤ) [hp : fact p.prime] :
140
128
(legendre_sym p a : zmod p) = (a ^ (p / 2 )) :=
141
129
begin
142
130
rw legendre_sym,
143
131
by_cases ha : (a : zmod p) = 0 ,
144
- { simp only [int.cast_coe_nat, if_pos, ha ,
145
- zero_pow (nat.div_pos (hp. 1 .two_le) (succ_pos 1 )), int.cast_zero] },
146
- cases hp. 1 .eq_two_or_odd with hp2 hp_odd ,
132
+ { simp only [ha, zero_pow (nat.div_pos (hp. 1 .two_le) (succ_pos 1 )), quadratic_char_zero ,
133
+ int.cast_zero], },
134
+ by_cases hp₁ : p = 2 ,
147
135
{ substI p,
148
136
generalize : (a : (zmod 2 )) = b, revert b, dec_trivial, },
149
- { haveI := fact.mk hp_odd,
150
- rw [if_neg ha],
151
- have : (-1 : zmod p) ≠ 1 , from (ne_neg_self p one_ne_zero).symm,
137
+ { have h₁ := quadratic_char_eq_pow_of_char_ne_two (by rwa ring_char_zmod_n p) ha,
138
+ rw card p at h₁,
139
+ rw h₁,
140
+ have h₂ := finite_field.neg_one_ne_one_of_char_ne_two (by rwa ring_char_zmod_n p),
152
141
cases pow_div_two_eq_neg_one_or_one p ha with h h,
153
142
{ rw [if_pos h, h, int.cast_one], },
154
- { rw [h, if_neg this , int.cast_neg, int.cast_one], } }
143
+ { rw [h, if_neg h₂ , int.cast_neg, int.cast_one], } }
155
144
end
156
145
157
- lemma legendre_sym_eq_one_or_neg_one (p : ℕ) (a : ℤ) (ha : (a : zmod p) ≠ 0 ) :
158
- legendre_sym p a = -1 ∨ legendre_sym p a = 1 :=
146
+ /-- If `p ∤ a`, then `legendre_sym p a` is `1` or `-1`. -/
147
+ lemma legendre_sym_eq_one_or_neg_one (p : ℕ) [fact p.prime] (a : ℤ) (ha : (a : zmod p) ≠ 0 ) :
148
+ legendre_sym p a = 1 ∨ legendre_sym p a = -1 :=
149
+ quadratic_char_dichotomy ha
150
+
151
+ /-- The Legendre symbol of `p` and `a` is zero iff `p ∣ a`. -/
152
+ lemma legendre_sym_eq_zero_iff (p : ℕ) [fact p.prime] (a : ℤ) :
153
+ legendre_sym p a = 0 ↔ (a : zmod p) = 0 :=
154
+ quadratic_char_eq_zero_iff a
155
+
156
+ @[simp] lemma legendre_sym_zero (p : ℕ) [fact p.prime] : legendre_sym p 0 = 0 :=
159
157
begin
160
- unfold legendre_sym,
161
- split_ifs;
162
- simp only [*, eq_self_iff_true, or_true, true_or] at *,
158
+ rw legendre_sym,
159
+ exact quadratic_char_zero,
163
160
end
164
161
165
- lemma legendre_sym_eq_zero_iff (p : ℕ) (a : ℤ) :
166
- legendre_sym p a = 0 ↔ (a : zmod p) = 0 :=
162
+ @[simp] lemma legendre_sym_one (p : ℕ) [fact p.prime] : legendre_sym p 1 = 1 :=
163
+ begin
164
+ rw [legendre_sym, (by norm_cast : ((1 : ℤ) : zmod p) = 1 )],
165
+ exact quadratic_char_one,
166
+ end
167
+
168
+ /-- The Legendre symbol is multiplicative in `a` for `p` fixed. -/
169
+ lemma legendre_sym_mul (p : ℕ) [fact p.prime] (a b : ℤ) :
170
+ legendre_sym p (a * b) = legendre_sym p a * legendre_sym p b :=
167
171
begin
168
- split,
169
- { classical, contrapose,
170
- assume ha, cases legendre_sym_eq_one_or_neg_one p a ha with h h,
171
- all_goals { rw h, norm_num } },
172
- { assume ha, rw [legendre_sym, if_pos ha] }
172
+ rw [legendre_sym, legendre_sym, legendre_sym],
173
+ push_cast,
174
+ exact quadratic_char_mul (a : zmod p) b,
173
175
end
174
176
177
+ /-- The Legendre symbol is a homomorphism of monoids with zero. -/
178
+ @[simps] def legendre_sym_hom (p : ℕ) [fact p.prime] : ℤ →*₀ ℤ :=
179
+ { to_fun := legendre_sym p,
180
+ map_zero' := legendre_sym_zero p,
181
+ map_one' := legendre_sym_one p,
182
+ map_mul' := legendre_sym_mul p }
183
+
184
+ /-- The square of the symbol is 1 if `p ∤ a`. -/
185
+ theorem legendre_sym_sq_one (p : ℕ) [fact p.prime] (a : ℤ) (ha : (a : zmod p) ≠ 0 ) :
186
+ (legendre_sym p a)^2 = 1 :=
187
+ quadratic_char_sq_one ha
188
+
189
+ /-- The Legendre symbol of `a^2` at `p` is 1 if `p ∤ a`. -/
190
+ theorem legendre_sym_sq_one' (p : ℕ) [fact p.prime] (a : ℤ) (ha : (a : zmod p) ≠ 0 ) :
191
+ legendre_sym p (a ^ 2 ) = 1 :=
192
+ begin
193
+ rw [legendre_sym],
194
+ push_cast,
195
+ exact quadratic_char_sq_one' ha,
196
+ end
197
+
198
+ /-- The Legendre symbol depends only on `a` mod `p`. -/
199
+ theorem legendre_sym_mod (p : ℕ) [fact p.prime] (a : ℤ) :
200
+ legendre_sym p a = legendre_sym p (a % p) :=
201
+ by simp only [legendre_sym, int_cast_mod]
202
+
203
+
175
204
/-- Gauss' lemma. The legendre symbol can be computed by considering the number of naturals less
176
205
than `p/2` such that `(a * x) % p > p / 2` -/
177
206
lemma gauss_lemma {a : ℤ} (hp : p ≠ 2 ) (ha0 : (a : zmod p) ≠ 0 ) :
@@ -188,14 +217,12 @@ begin
188
217
simp [*, ne_neg_self p one_ne_zero, (ne_neg_self p one_ne_zero).symm] at *
189
218
end
190
219
220
+ /-- When `p ∤ a`, then `legendre_sym p a = 1` iff `a` is a square mod `p`. -/
191
221
lemma legendre_sym_eq_one_iff {a : ℤ} (ha0 : (a : zmod p) ≠ 0 ) :
192
- legendre_sym p a = 1 ↔ (∃ b : zmod p, b ^ 2 = a) :=
193
- begin
194
- rw [euler_criterion p ha0, legendre_sym, if_neg ha0],
195
- split_ifs,
196
- { simp only [h, eq_self_iff_true] },
197
- { simp only [h, iff_false], tauto }
198
- end
222
+ legendre_sym p a = 1 ↔ is_square (a : zmod p) :=
223
+ quadratic_char_one_iff_is_square ha0
224
+
225
+ open_locale big_operators
199
226
200
227
lemma eisenstein_lemma (hp : p ≠ 2 ) {a : ℕ} (ha1 : a % 2 = 1 ) (ha0 : (a : zmod p) ≠ 0 ) :
201
228
legendre_sym p a = (-1 )^∑ x in Ico 1 (p / 2 ).succ, (x * a) / p :=
@@ -252,12 +279,12 @@ begin
252
279
end
253
280
254
281
lemma exists_sq_eq_two_iff (hp1 : p ≠ 2 ) :
255
- (∃ a : zmod p, a ^ 2 = 2 ) ↔ p % 8 = 1 ∨ p % 8 = 7 :=
256
- have hp2 : ((2 : ℤ) : zmod p) ≠ 0 ,
257
- from prime_ne_zero p 2 (λ h, by simpa [h] using hp1),
258
- have hpm4 : p % 4 = p % 8 % 4 , from (nat.mod_mul_left_mod p 2 4 ).symm,
259
- have hpm2 : p % 2 = p % 8 % 2 , from (nat.mod_mul_left_mod p 4 2 ).symm,
282
+ is_square (2 : zmod p) ↔ p % 8 = 1 ∨ p % 8 = 7 :=
260
283
begin
284
+ have hp2 : ((2 : ℤ) : zmod p) ≠ 0 ,
285
+ from prime_ne_zero p 2 (λ h, by simpa [h] using hp1),
286
+ have hpm4 : p % 4 = p % 8 % 4 , from (nat.mod_mul_left_mod p 2 4 ).symm,
287
+ have hpm2 : p % 2 = p % 8 % 2 , from (nat.mod_mul_left_mod p 4 2 ).symm,
261
288
rw [show (2 : zmod p) = (2 : ℤ), by simp, ← legendre_sym_eq_one_iff p hp2],
262
289
erw [legendre_sym_two p hp1, neg_one_pow_eq_one_iff_even (show (-1 : ℤ) ≠ 1 , from dec_trivial),
263
290
even_add, even_div, even_div],
@@ -270,39 +297,49 @@ begin
270
297
end
271
298
272
299
lemma exists_sq_eq_prime_iff_of_mod_four_eq_one (hp1 : p % 4 = 1 ) (hq1 : q ≠ 2 ) :
273
- (∃ a : zmod p, a ^ 2 = q ) ↔ ∃ b : zmod q, b ^ 2 = p :=
300
+ is_square (q : zmod p) ↔ is_square (p : zmod q) :=
274
301
if hpq : p = q then by substI hpq else
275
302
have h1 : ((p / 2 ) * (q / 2 )) % 2 = 0 ,
276
303
from (dvd_iff_mod_eq_zero _ _).1
277
304
(dvd_mul_of_dvd_left ((dvd_iff_mod_eq_zero _ _).2 $
278
305
by rw [← mod_mul_right_div_self, show 2 * 2 = 4 , from rfl, hp1]; refl) _),
279
306
begin
280
307
have hp_odd : p ≠ 2 := by { by_contra, simp [h] at hp1, norm_num at hp1, },
281
- have hpq0 : (p : zmod q) ≠ 0 := prime_ne_zero q p (ne.symm hpq),
282
- have hqp0 : (q : zmod p) ≠ 0 := prime_ne_zero p q hpq,
308
+ have hpq0 : ((p : ℤ) : zmod q) ≠ 0 := prime_ne_zero q p (ne.symm hpq),
309
+ have hqp0 : ((q : ℤ) : zmod p) ≠ 0 := prime_ne_zero p q hpq,
283
310
have := quadratic_reciprocity p q hp_odd hq1 hpq,
284
- rw [neg_one_pow_eq_pow_mod_two, h1, legendre_sym, legendre_sym, int.cast_coe_nat,
285
- int.cast_coe_nat, if_neg hqp0, if_neg hpq0] at this ,
286
- rw [euler_criterion q hpq0, euler_criterion p hqp0],
287
- split_ifs at this ; simp *; contradiction,
311
+ rw [neg_one_pow_eq_pow_mod_two, h1, pow_zero] at this ,
312
+ rw [(by norm_cast : (p : zmod q) = (p : ℤ)), (by norm_cast : (q : zmod p) = (q : ℤ)),
313
+ ← legendre_sym_eq_one_iff _ hpq0, ← legendre_sym_eq_one_iff _ hqp0],
314
+ cases (legendre_sym_eq_one_or_neg_one p q hqp0) with h h,
315
+ { simp only [h, eq_self_iff_true, true_iff, mul_one] at this ⊢,
316
+ exact this , },
317
+ { simp only [h, mul_neg, mul_one] at this ⊢,
318
+ rw eq_neg_of_eq_neg this.symm, },
288
319
end
289
320
290
321
lemma exists_sq_eq_prime_iff_of_mod_four_eq_three (hp3 : p % 4 = 3 )
291
- (hq3 : q % 4 = 3 ) (hpq : p ≠ q) : (∃ a : zmod p, a ^ 2 = q ) ↔ ¬∃ b : zmod q, b ^ 2 = p :=
322
+ (hq3 : q % 4 = 3 ) (hpq : p ≠ q) : is_square (q : zmod p) ↔ ¬ is_square (p : zmod q) :=
292
323
have h1 : ((p / 2 ) * (q / 2 )) % 2 = 1 ,
293
324
from nat.odd_mul_odd
294
325
(by rw [← mod_mul_right_div_self, show 2 * 2 = 4 , from rfl, hp3]; refl)
295
326
(by rw [← mod_mul_right_div_self, show 2 * 2 = 4 , from rfl, hq3]; refl),
296
327
begin
297
328
have hp_odd : p ≠ 2 := by { by_contra, simp [h] at hp3, norm_num at hp3, },
298
329
have hq_odd : q ≠ 2 := by { by_contra, simp [h] at hq3, norm_num at hq3, },
299
- have hpq0 : (p : zmod q) ≠ 0 := prime_ne_zero q p (ne.symm hpq),
300
- have hqp0 : (q : zmod p) ≠ 0 := prime_ne_zero p q hpq,
330
+ have hpq0 : ((p : ℤ) : zmod q) ≠ 0 := prime_ne_zero q p (ne.symm hpq),
331
+ have hqp0 : ((q : ℤ) : zmod p) ≠ 0 := prime_ne_zero p q hpq,
301
332
have := quadratic_reciprocity p q hp_odd hq_odd hpq,
302
- rw [neg_one_pow_eq_pow_mod_two, h1, legendre_sym, legendre_sym, int.cast_coe_nat,
303
- int.cast_coe_nat, if_neg hpq0, if_neg hqp0] at this ,
304
- rw [euler_criterion q hpq0, euler_criterion p hqp0],
305
- split_ifs at this ; simp *; contradiction
333
+ rw [neg_one_pow_eq_pow_mod_two, h1, pow_one] at this ,
334
+ rw [(by norm_cast : (p : zmod q) = (p : ℤ)), (by norm_cast : (q : zmod p) = (q : ℤ)),
335
+ ← legendre_sym_eq_one_iff _ hpq0, ← legendre_sym_eq_one_iff _ hqp0],
336
+ cases (legendre_sym_eq_one_or_neg_one q p hpq0) with h h,
337
+ { simp only [h, eq_self_iff_true, not_true, iff_false, one_mul] at this ⊢,
338
+ simp only [this ],
339
+ norm_num, },
340
+ { simp only [h, neg_mul, one_mul, neg_inj] at this ⊢,
341
+ simp only [this , eq_self_iff_true, true_iff],
342
+ norm_num, },
306
343
end
307
344
308
345
end zmod
0 commit comments