Theory Cyclic_Group_Ext

theory Cyclic_Group_Ext imports
  CryptHOL.CryptHOL
  "HOL-Number_Theory.Cong"
begin

context cyclic_group begin

lemma generator_pow_order: "g [^] order G = 𝟭"
proof(cases "order G > 0")
  case True
  hence fin: "finite (carrier G)" by(simp add: order_gt_0_iff_finite)
  then have [symmetric]: "(λx. x  g) ` carrier G = carrier G"
    by(rule endo_inj_surj)(auto simp add: inj_on_multc)
  then have "carrier G = (λ n. g [^] Suc n) ` {..<order G}" 
    using fin by(simp add: carrier_conv_generator image_image)
  then obtain n where n: "𝟭 = g [^] Suc n" "n < order G" by auto
  have "n = order G - 1" using n inj_onD[OF inj_on_generator, of 0 "Suc n"] by fastforce
  with True n show ?thesis by auto
qed simp
                        
lemma pow_generator_mod: "g [^] (k mod order G) = g [^] k"
proof(cases "order G > 0")
  case True
  obtain n where n: "k = n * order G + k mod order G" by (metis div_mult_mod_eq)
  have "g [^] k = (g [^] order G) [^] n  g [^] (k mod order G)" 
    by(subst n)(simp add: nat_pow_mult nat_pow_pow mult_ac)
  then show ?thesis by(simp add: generator_pow_order)
qed simp

lemma int_nat_pow: 
  assumes "a  0" 
  shows "(g [^] (int (a ::nat))) [^] (b::int)  = g [^] (a*b)"
  using assms 
proof(cases "a > 0")
  case True 
  show ?thesis
    using int_pow_pow by blast
next case False
  have "(g [^] (int (a ::nat))) [^] (b::int) = 𝟭" using False by simp
  also have "g [^] (a*b) = 𝟭" using False by simp
  ultimately show ?thesis by simp
qed

lemma pow_generator_mod_int: "g [^] ((k :: int) mod order G) = g [^] k"
proof(cases "order G > 0")
  case True
  obtain n :: int where n: "k = order G * n + k mod order G" 
    by (metis div_mult_mod_eq mult.commute)
  then have "g [^] k = g [^] (order G * n)  g [^] (k mod order G)" 
    using int_pow_mult nat_pow_mult by (metis generator_closed)
  then have "g [^] k = (g [^] order G) [^] n  g [^] (k mod order G)"
    using int_nat_pow by (simp add: int_pow_int)
  then show ?thesis by(simp add: generator_pow_order)
qed simp

lemma pow_gen_mod_mult:
  shows"(g [^] (a::nat)  g [^] (b::nat)) [^] ((c::int)* int (d::nat)) = (g [^] a  g [^] b) [^] ((c*int d) mod (order G))"
proof-
  have "(g [^] (a::nat)  g [^] (b::nat))  carrier G" by simp
  then obtain n :: nat where n: "g [^] n = (g [^] (a::nat)  g [^] (b::nat))" 
    by (simp add: monoid.nat_pow_mult)
  also obtain r where r: "r = c*int d" by simp
  have "(g [^] (a::nat)  g [^] (b::nat)) [^] ((c::int)*int (d::nat)) = (g [^] n) [^] r" using n r by simp
  moreover have"... = (g [^] n) [^] (r mod (order G))" using pow_generator_mod_int pow_generator_mod 
    by (metis int_nat_pow int_pow_int mod_mult_right_eq zero_le)
  moreover have "... =  (g [^] a  g [^] b) [^] ((c*int d) mod (order G))" using r n by simp
  ultimately show ?thesis by simp
qed

lemma pow_generator_eq_iff_cong:
  "finite (carrier G)  g [^] x = g [^] y  [x = y] (mod order G)"
  by(subst (1 2) pow_generator_mod[symmetric])(auto simp add: cong_def order_gt_0_iff_finite intro: inj_onD[OF inj_on_generator])

lemma cyclic_group_commute: 
  assumes "a  carrier G" "b  carrier G" 
  shows "a  b = b  a"
(is "?lhs = ?rhs")
proof-
  obtain n :: nat where n: "a = g [^] n" using generatorE assms by auto
  also  obtain k :: nat where k: "b = g [^] k" using generatorE assms by auto
  ultimately have "?lhs =  g [^] n  g [^] k" by simp
  then have "... = g [^] (n + k)" by(simp add: nat_pow_mult)
  then have "... = g [^] (k + n)" by(simp add: add.commute)
  then show ?thesis by(simp add: nat_pow_mult n k)
qed

lemma cyclic_group_assoc: 
  assumes "a  carrier G" "b  carrier G" "c  carrier G"
  shows "(a  b)  c = a  (b  c)"
(is "?lhs = ?rhs")
proof-
  obtain n :: nat where n: "a = g [^] n" using generatorE assms by auto
  obtain k :: nat where k: "b = g [^] k" using generatorE assms by auto
  obtain j :: nat where j: "c = g [^] j" using generatorE assms by auto 
  have "?lhs = (g [^] n  g [^] k)  g [^] j" using n k j by simp
  then have "... = g [^] (n + (k + j))" by(simp add: nat_pow_mult add.assoc)
  then show ?thesis by(simp add: nat_pow_mult n k j)
qed
 
lemma l_cancel_inv: 
  assumes "h  carrier G" 
  shows "(g [^] (a :: nat)  inv (g [^] a))  h = h"
(is "?lhs = ?rhs")
proof-
  have "?lhs = (g [^] int a  inv (g [^] int a))  h" by simp
  then have "... = (g [^] int a  (g [^] (- a)))  h" using int_pow_neg[symmetric] by simp
  then have "... = g [^] (int a - a)   h" by(simp add: int_pow_mult)
  then have "... = g [^] ((0:: int))  h" by simp
  then show ?thesis by (simp add: assms)
qed

lemma inverse_split: 
  assumes "a  carrier G" and "b  carrier G"
  shows "inv (a  b) = inv a  inv b"
  by (simp add:  assms comm_group.inv_mult cyclic_group_commute group_comm_groupI)

lemma inverse_pow_pow:
  assumes "a  carrier G"
  shows "inv (a [^] (r::nat)) = (inv a) [^] r"
proof -
  have "a [^] r  carrier G"
    using assms by blast
  then show ?thesis
    by (simp add: assms nat_pow_inv)
qed

lemma l_neq_1_exp_neq_0:
  assumes "l  carrier G" 
    and "l  𝟭" 
    and "l = g [^] (t::nat)" 
  shows "t  0"
proof(rule ccontr)
  assume "¬ (t  0)"
  hence "t = 0" by simp
  hence "g [^] t = 𝟭" by simp
  then show "False" using assms by simp
qed

lemma order_gt_1_gen_not_1:
  assumes "order G > 1"
  shows "g  𝟭"
proof(rule ccontr)
  assume "¬ g  𝟭"
  hence "g = 𝟭" by simp
  hence g_pow_eq_1: "g [^] n = 𝟭" for n :: nat by simp
  hence "range (λn :: nat. g [^] n) = {𝟭}" by auto
  hence "carrier G  {𝟭}" using generator by auto
  hence "order G < 1" 
    by (metis One_nat_def assms g_pow_eq_1 inj_onD inj_on_generator lessThan_iff not_gr_zero zero_less_Suc)
  with assms show "False" by simp
qed

lemma power_swap: "((g [^] (α0::nat)) [^] (r::nat)) = ((g [^] r) [^] α0)"
(is "?lhs = ?rhs")
proof-
  have "?lhs = g [^] (α0 * r)" 
    using nat_pow_pow mult.commute by auto
  hence "... = g [^] (r * α0)" 
    by(metis mult.commute)
  thus ?thesis using nat_pow_pow by auto
qed

end 

end