Zulip Chat Archive
Stream: Is there code for X?
Topic: Coercions in integer exponents
Ashley Blacquiere (Dec 11 2024 at 04:05):
I'm trying to port parts of cryptolib to Lean 4, specifically the proof of bijection between ZMod q and a the subgroup generated by a generator g raised to a power of ZMod q. This is what I have so far:
import Mathlib
variable {G: Type*} [Fintype G] [Group G] [DecidableEq G] [IsCyclic G]
variable (q : ℕ) [Fact (Nat.Prime q)]
variable (G_card_q : Fintype.card G = q)
variable (g : G) (g_gen_G : ∀ (x : G), x ∈ Subgroup.zpowers g)
include G_card_q
include g_gen_G
lemma exp_bij : Function.Bijective fun (z : ZMod q) => g^z.val := by
apply (Fintype.bijective_iff_surjective_and_card _).mpr
have h_prime : q.Prime := Fact.out
have h_card : g ^ q = 1 := by
rw [←G_card_q]
apply pow_card_eq_one
simp [h_card, G_card_q]
intro y
obtain ⟨k, hk⟩ := g_gen_G y
use k
have h_pow : g^((k : ZMod q).val) = y := by
subst hk G_card_q
simp_all only [pow_card_eq_one, zpow_mod_card]
sorry
exact h_pow
I'm stuck at the sorry where the goal state is g ^ (↑k).val = g ^ k
, but I can't figure out how to either compare the exponents directly (I thought of using docs#zpow_eq_zpow_iff_modEq) or to otherwise manage the coercion. I've tried Loogle, Moogle and LeanSearch, but can't find a solution...
Kim Morrison (Dec 11 2024 at 04:28):
Looking at your sorry, I started writing ZMod.val_intCast
, which seemed to be the missing lemma, only to find it already exists but seemingly says the wrong thing.
It is:
ZMod.val_intCast {n : ℕ} (a : ℤ) [NeZero n] : ↑(a : ZMod n).val = a % ↑n
i.e. it says something not about (a : ZMod n).val
, but the coercion of that back to \Int
. Not very helpful!
I think it should probably instead say
theorem val_intCast {n : ℕ} (a : ℤ) [NeZero n] : (a : ZMod n).val = Int.natMod a n
and probably also be a simp
lemma.
Kim Morrison (Dec 11 2024 at 04:40):
i.e. something like
@[simp] theorem intCast_natMod (a b : Int) [NeZero b] : (a.natMod b : Int) = a % b := by
simpa [Int.natMod] using Int.emod_nonneg _ (NeZero.ne b)
@[simp] theorem ZMod.val_intCast' {n : ℕ} (a : ℤ) [NeZero n] : (a : ZMod n).val = Int.natMod a n := by
apply Int.ofNat.inj
simp only [Int.ofNat_eq_coe]
rw [ZMod.val_intCast]
simp
Kim Morrison (Dec 11 2024 at 04:40):
There's a lot of API around natMod
missing too, I'm not sure when/who added it.
Kim Morrison (Dec 11 2024 at 04:42):
Also natMod
has terrible behaviour at e.g. Int.natMod (-37) 0 = 0
, where I think 37
would be more consistent with other division-by-zero behaviour.
Kim Morrison (Dec 11 2024 at 04:43):
Hmm, I guess that is equally terrible. It seems all theorems about natMod
are probably going to need a b \ne 0
hypothesis.
Kim Morrison (Dec 11 2024 at 04:55):
In any case, you'll want
theorem Int.natMod_eq_sub (x w : Int) (h : w ≠ 0) : Int.natMod x w = x - w * (x / w) := by
plausible
Bhavik Mehta (Dec 13 2024 at 12:28):
Kim Morrison said:
There's a lot of API around
natMod
missing too, I'm not sure when/who added it.
I decided to figure this out out of curiosity - looks like it was added here: https://github.com/leanprover-community/lean/commit/e705d8949002481a118003ea5bee2098226dbd22#diff-28df10e2dbc2fa18af1293c5145788c9983f7e892038b18717a1a80862e976b9R444
Last updated: May 02 2025 at 03:31 UTC