/-- The (additive) monoid equivalence between `ZMod k`
and the powers of a primitive root of unity `ζ`. -/
def zmodEquivZPowers (h : IsPrimitiveRoot ζ k) : ZMod k ≃+ Additive (Subgroup.zpowers ζ) :=
  AddEquiv.ofBijective
    (AddMonoidHom.liftOfRightInverse (Int.castAddHom <| ZMod k) _ ZMod.int_cast_rightInverse
      ⟨{  toFun := fun i => Additive.ofMul (⟨_, i, rfl⟩ : Subgroup.zpowers ζ)
          map_zero' := by simp only [zpow_zero]; rfl
          map_add' := by intro i j; simp only [zpow_add]; rfl }, fun i hi => by
        simp only [AddMonoidHom.mem_ker, CharP.int_cast_eq_zero_iff (ZMod k) k, AddMonoidHom.coe_mk,
          Int.coe_castAddHom] at hi ⊢
        obtain ⟨i, rfl⟩ := hi
        simp [zpow_mul, h.pow_eq_one, one_zpow, zpow_ofNat]⟩)
    (by
      constructor
      · rw [injective_iff_map_eq_zero]
        intro i hi
        rw [Subtype.ext_iff] at hi
        have := (h.zpow_eq_one_iff_dvd _).mp hi
        rw [← (CharP.int_cast_eq_zero_iff (ZMod k) k _).mpr this, eq_comm]
        exact ZMod.int_cast_rightInverse i
      · rintro ⟨ξ, i, rfl⟩
        refine' ⟨Int.castAddHom (ZMod k) i, _⟩
        rw [AddMonoidHom.liftOfRightInverse_comp_apply]
        

Proof state:
case right.mk.intro
M : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝³ : CommMonoid M
inst✝² : CommMonoid N
inst✝¹ : DivisionCommMonoid G
k l : ℕ
inst✝ : CommRing R
ζ : Rˣ
h✝ h : IsPrimitiveRoot ζ k
i : ℤ
⊢ ↑{
          val :=
            {
              toZeroHom :=
                {
                  toFun := fun i =>
                    Additive.ofMul
                      { val := (fun x => ζ ^ x) i, property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) },
                  map_zero' :=
                    (_ :
                      (fun i =>
                            Additive.ofMul
                              { val := (fun x => ζ ^ x) i,
                                property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) })
                          0 =
                        0) },
              map_add' :=
                (_ :
                  ∀ (i j : ℤ),
                    ZeroHom.toFun
                        {
                          toFun := fun i =>
                            Additive.ofMul
                              { val := (fun x => ζ ^ x) i,
                                property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) },
                          map_zero' :=
                            (_ :
                              (fun i =>
                                    Additive.ofMul
                                      { val := (fun x => ζ ^ x) i,
                                        property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) })
                                  0 =
                                0) }
                        (i + j) =
                      ZeroHom.toFun
                          {
                            toFun := fun i =>
                              Additive.ofMul
                                { val := (fun x => ζ ^ x) i,
                                  property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) },
                            map_zero' :=
                              (_ :
                                (fun i =>
                                      Additive.ofMul
                                        { val := (fun x => ζ ^ x) i,
                                          property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) })
                                    0 =
                                  0) }
                          i +
                        ZeroHom.toFun
                          {
                            toFun := fun i =>
                              Additive.ofMul
                                { val := (fun x => ζ ^ x) i,
                                  property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) },
                            map_zero' :=
                              (_ :
                                (fun i =>
                                      Additive.ofMul
                                        { val := (fun x => ζ ^ x) i,
                                          property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) })
                                    0 =
                                  0) }
                          j) },
          property :=
            (_ :
              ∀ i ∈ AddMonoidHom.ker (Int.castAddHom (ZMod k)),
                i ∈
                  AddMonoidHom.ker
                    {
                      toZeroHom :=
                        {
                          toFun := fun i =>
                            Additive.ofMul
                              { val := (fun x => ζ ^ x) i,
                                property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) },
                          map_zero' :=
                            (_ :
                              (fun i =>
                                    Additive.ofMul
                                      { val := (fun x => ζ ^ x) i,
                                        property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) })
                                  0 =
                                0) },
                      map_add' :=
                        (_ :
                          ∀ (i j : ℤ),
                            ZeroHom.toFun
                                {
                                  toFun := fun i =>
                                    Additive.ofMul
                                      { val := (fun x => ζ ^ x) i,
                                        property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) },
                                  map_zero' :=
                                    (_ :
                                      (fun i =>
                                            Additive.ofMul
                                              { val := (fun x => ζ ^ x) i,
                                                property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) })
                                          0 =
                                        0) }
                                (i + j) =
                              ZeroHom.toFun
                                  {
                                    toFun := fun i =>
                                      Additive.ofMul
                                        { val := (fun x => ζ ^ x) i,
                                          property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) },
                                    map_zero' :=
                                      (_ :
                                        (fun i =>
                                              Additive.ofMul
                                                { val := (fun x => ζ ^ x) i,
                                                  property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) })
                                            0 =
                                          0) }
                                  i +
                                ZeroHom.toFun
                                  {
                                    toFun := fun i =>
                                      Additive.ofMul
                                        { val := (fun x => ζ ^ x) i,
                                          property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) },
                                    map_zero' :=
                                      (_ :
                                        (fun i =>
                                              Additive.ofMul
                                                { val := (fun x => ζ ^ x) i,
                                                  property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) })
                                            0 =
                                          0) }
                                  j) }) }
      i =
    { val := (fun x => ζ ^ x) i, property := (_ : ∃ y, (fun x => ζ ^ x) y = (fun x => ζ ^ x) i) }

Next tactic:
rfl