Theory Primitives

theory Primitives

imports Pairing  
begin

section ‹Mathematical Primitives›

text ‹We define the mathematical primitives used throughout our formalization as well as some
useful lemmas (mostly identities).›
locale math_primitives = pairing Gp  GT p e
  for Gp :: "('a, 'b) cyclic_group_scheme" (structure)
  and GT:: "('c, 'd) cyclic_group_scheme"  (structure)
  and p::int
  and e::"'a ⇒ 'a ⇒ 'c"
+ 
fixes "type_q" :: "('q :: prime_card) itself"
and max_deg::nat
assumes
p_gr_two: "p > 2" and
d_pos: "max_deg > 0" and
CARD_q: "int (CARD('q)) = p" and
d_l_p: "max_deg < p"
begin

abbreviation pow_mod_ring (infixr "^ı" 75)
  where "x ^ı y ≡  x [^]ı (to_int_mod_ring (y::'q mod_ring))"

abbreviation div_in_grp (infixr "÷ı" 70)
  where "x ÷ı y ≡ x ⊗ı invı y"

subsubsection ‹mod\_ring operations on pow of Gp›

lemma carrier_pow_mod_order_Gp: 
  assumes "g ∈ carrier Gp"
  shows "g [^]⇘Gp⇙ x = g [^]⇘Gp⇙ (x mod p)"
proof -
  have "p=(order Gp)" by (simp add: CARD_Gp)
  also have "g [^]⇘Gp⇙ x = g [^]⇘Gp⇙ (x mod order Gp)"
  proof -
    have "g [^]⇘Gp⇙ x ∈ carrier Gp" by (simp add: assms)
    let ?d = "x div (order Gp)"
    have "g [^]⇘Gp⇙ x = g [^]⇘Gp⇙ (?d * order Gp + x mod order Gp)" 
      using div_mult_mod_eq by presburger
    also have "…= g [^]⇘Gp⇙ (?d * order Gp) ⊗⇘Gp⇙  g [^]⇘Gp⇙ (x mod order Gp)"
      using Gp.int_pow_mult assms by blast
    also have "…=𝟭⇘Gp⇙ ⊗⇘Gp⇙ g [^]⇘Gp⇙ (x mod order Gp)"
      by (metis Gp.int_pow_closed Gp.int_pow_pow Gp.pow_order_eq_1 assms int_pow_int)
    finally show "g [^]⇘Gp⇙ x = g [^]⇘Gp⇙ (x mod order Gp)"
      using assms by fastforce
  qed
  finally show "g [^]⇘Gp⇙ x = g [^]⇘Gp⇙ (x mod p)" .
qed

lemma pow_mod_order_Gp: "g⇘Gp⇙ [^]⇘Gp⇙ x = g⇘Gp⇙ [^]⇘Gp⇙ (x mod p)"
  using carrier_pow_mod_order_Gp by blast

lemma mod_ring_pow_mult_inv_Gp[symmetric]:" (g⇘Gp⇙ [^]⇘Gp⇙ (to_int_mod_ring (a::'q mod_ring))) ⊗⇘Gp⇙ inv⇘Gp⇙ (g⇘Gp⇙ [^]⇘Gp⇙ (to_int_mod_ring b)) 
  =  g⇘Gp⇙ [^]⇘Gp⇙ (to_int_mod_ring (a-b))"
proof -
  have "(g⇘Gp⇙ [^]⇘Gp⇙ (to_int_mod_ring (a::'q mod_ring))) ⊗⇘Gp⇙ inv⇘Gp⇙ (g⇘Gp⇙ [^]⇘Gp⇙ (to_int_mod_ring b)) 
        = (g⇘Gp⇙ [^]⇘Gp⇙ (to_int_mod_ring (a::'q mod_ring))) ⊗⇘Gp⇙ (g⇘Gp⇙ [^]⇘Gp⇙ (- to_int_mod_ring b))"
    by (simp add: Gp.int_pow_neg)
  also have "…=(g⇘Gp⇙ [^]⇘Gp⇙ ((to_int_mod_ring a + -to_int_mod_ring b) mod CARD ('q)))"
    using pow_mod_order_Gp CARD_q Gp.generator_closed Gp.int_pow_mult by presburger
  also have "…=(g⇘Gp⇙ [^]⇘Gp⇙ ((to_int_mod_ring a - to_int_mod_ring b) mod CARD ('q)))"
    by fastforce
  also have "…=  g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring (a - b)"
    by (simp add: minus_mod_ring.rep_eq to_int_mod_ring.rep_eq)
  finally show "g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring a ⊗⇘Gp⇙ inv⇘Gp⇙ (g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring b) = g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring (a - b)" .
qed

lemma mod_ring_pow_mult_Gp[symmetric]:" (g⇘Gp⇙ [^]⇘Gp⇙ (to_int_mod_ring (a::'q mod_ring))) ⊗⇘Gp⇙ (g⇘Gp⇙ [^]⇘Gp⇙ (to_int_mod_ring b)) 
  =  g⇘Gp⇙ [^]⇘Gp⇙ (to_int_mod_ring (a+b))"
proof -
  have "g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring a ⊗⇘Gp⇙ g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring b =  g⇘Gp⇙ [^]⇘Gp⇙ (to_int_mod_ring a + to_int_mod_ring b)"
    by (simp add: Gp.int_pow_mult)
  also have "…=  g⇘Gp⇙ [^]⇘Gp⇙ ((to_int_mod_ring a + to_int_mod_ring b) mod (CARD ('q)))" 
    using pow_mod_order_Gp CARD_q by blast
  also have "…=  g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring (a + b)"
    by (simp add: plus_mod_ring.rep_eq to_int_mod_ring.rep_eq)
  finally show "g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring a ⊗⇘Gp⇙ g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring b = g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring (a + b)" .
qed

lemma mod_ring_pow_pow_Gp[symmetric]: "(g⇘Gp⇙ [^]⇘Gp⇙ (to_int_mod_ring (a::'q mod_ring))) [^]⇘Gp⇙ (to_int_mod_ring (b::'q mod_ring)) 
                       = g⇘Gp⇙[^]⇘Gp⇙ (to_int_mod_ring (a*b::'q mod_ring))"
proof -
  have "(g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring a) [^]⇘Gp⇙ to_int_mod_ring b = (g⇘Gp⇙ [^]⇘Gp⇙ (to_int_mod_ring a * to_int_mod_ring b))"
    using Gp.int_pow_pow by auto
  also have "… = (g⇘Gp⇙ [^]⇘Gp⇙ ((to_int_mod_ring a * to_int_mod_ring b) mod CARD ('q)))"
    using CARD_q pow_mod_order_Gp by blast
  also have "…=  g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring (a * b)"
    by (simp add: times_mod_ring.rep_eq to_int_mod_ring.rep_eq)
  finally show "(g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring a) [^]⇘Gp⇙ to_int_mod_ring b 
               = g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring (a * b)" .
qed

lemma to_int_mod_ring_ge_0: "to_int_mod_ring x ≥ 0" 
  using range_to_int_mod_ring by fastforce

lemma pow_on_eq_card: "(g⇘Gp⇙ ^⇘Gp⇙ x = g⇘Gp⇙ ^⇘Gp⇙ y) = (x=y)"
proof 
  assume assm: "g ^⇘Gp⇙ x = g ^⇘Gp⇙ y"
  then have "g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring x = g⇘Gp⇙ [^]⇘Gp⇙ to_int_mod_ring y"
    using assm by blast
  then have "g⇘Gp⇙ [^]⇘Gp⇙ nat (to_int_mod_ring x) = g⇘Gp⇙ [^]⇘Gp⇙ nat (to_int_mod_ring y)" 
    using to_int_mod_ring_ge_0[of "x"] to_int_mod_ring_ge_0[of "y"] by fastforce
  then have "[nat (to_int_mod_ring x) = nat (to_int_mod_ring y)] (mod order Gp)"
    using Gp.pow_generator_eq_iff_cong Gp.finite_carrier by fast
  then have "[to_int_mod_ring x = to_int_mod_ring y] (mod order Gp)" 
    using to_int_mod_ring_ge_0[of "x"] to_int_mod_ring_ge_0[of "y"]
    by (metis cong_int_iff int_nat_eq)
  then have "[to_int_mod_ring x = to_int_mod_ring y] (mod p)" 
    using CARD_Gp by fast
  then have "to_int_mod_ring x = to_int_mod_ring y"
    by (metis Rep_mod_ring_mod to_int_mod_ring.rep_eq unique_euclidean_semiring_class.cong_def 
        CARD_q)
  then show "x = y" by force
next 
  assume "x = y"
  then show "g ^⇘Gp⇙ x = g ^⇘Gp⇙ y" by fast
qed

lemma g_pow_to_int_mod_ring_of_int_mod_ring: " g ^⇘Gp⇙ of_int_mod_ring x =  g [^] x"
proof -
  have "g ^⇘Gp⇙ of_int_mod_ring x =  g [^] (x mod p)"
    by (simp add: CARD_q of_int_mod_ring.rep_eq to_int_mod_ring.rep_eq)
  also have "…= g [^] x" using CARD_Gp Gp.pow_generator_mod_int by presburger
  finally show ?thesis .
qed

lemma g_pow_to_int_mod_ring_of_int_mod_ring_pow_t: "g ^⇘Gp⇙ of_int_mod_ring x ^ (t::nat) =  g [^] x ^ t"
  by (metis g_pow_to_int_mod_ring_of_int_mod_ring of_int_of_int_mod_ring of_int_power)

lemma carrier_inj_on_multc: "c ≠ 0 ⟹ inj_on (λx. x ^⇘Gp⇙ c) (carrier Gp)"
proof 
  fix x y
  assume c: "c ≠ 0"
  assume x: " x ∈ carrier Gp"
  assume y: " y ∈ carrier Gp"
  assume asm: "x ^ c = y ^ c"
  obtain x_pow where x_pow: "g ^⇘Gp⇙ x_pow = x"
    using x 
    by (metis Gp.generatorE g_pow_to_int_mod_ring_of_int_mod_ring int_pow_int)
  obtain y_pow where y_pow: "g ^⇘Gp⇙ y_pow = y"
    using y 
    by (metis Gp.generatorE g_pow_to_int_mod_ring_of_int_mod_ring int_pow_int)
  then have "(g ^⇘Gp⇙ x_pow) ^⇘Gp⇙ c = (g ^⇘Gp⇙ y_pow) ^⇘Gp⇙ c"
    using asm x_pow y_pow by blast
  then have "(g ^⇘Gp⇙ (x_pow*c))= (g ^⇘Gp⇙ (y_pow*c))"
    using mod_ring_pow_pow_Gp by presburger
  then have "x_pow * c = y_pow*c"
    using pow_on_eq_card by force
  then have "x_pow = y_pow"
    using c by simp
  then show "x=y"
    using x_pow y_pow by blast
qed

subsubsection‹mod\_ring operations on pow of GT›

lemma pow_mod_order_GT: "g ∈ carrier GT ⟹ g [^]⇘GT⇙ x = g [^]⇘GT⇙ (x mod p)" 
proof -
  assume asmpt: "g ∈ carrier GT"
  have "p=(order GT)" by (simp add: CARD_GT)
  also have "g[^]⇘GT⇙ x = g [^]⇘GT⇙ (x mod order GT)"
  proof -
    have "g [^]⇘GT⇙ x ∈ carrier GT" using asmpt by simp
    let ?d = "x div (order GT)"
    have "g [^]⇘GT⇙ x = g [^]⇘GT⇙ (?d * order GT + x mod order GT)" 
      using div_mult_mod_eq by presburger
    also have "…=g [^]⇘GT⇙ (?d * order GT) ⊗⇘GT⇙  g [^]⇘GT⇙ (x mod order GT)"
      using GT.int_pow_mult asmpt by fast
    also have "…=𝟭⇘GT⇙ ⊗⇘GT⇙ g [^]⇘GT⇙ (x mod order GT)"
      by (metis GT.int_pow_one GT.int_pow_pow GT.pow_order_eq_1 int_pow_int mult.commute asmpt)
    finally show "g [^]⇘GT⇙ x = g [^]⇘GT⇙ (x mod order GT)"
      using asmpt by fastforce
  qed
  finally show "g [^]⇘GT⇙ x = g [^]⇘GT⇙ (x mod p)" .
qed


lemma mod_ring_pow_mult_GT[symmetric]:" x ∈ carrier GT ⟹ (x [^]⇘GT⇙ (to_int_mod_ring (a::'q mod_ring))) ⊗⇘GT⇙ (x [^]⇘GT⇙ (to_int_mod_ring b)) 
  =  x [^]⇘GT⇙ (to_int_mod_ring (a+b))"
proof -
  assume asmpt: "x ∈ carrier GT"
  have "x [^]⇘GT⇙ to_int_mod_ring a ⊗⇘GT⇙ x [^]⇘GT⇙ to_int_mod_ring b =  x [^]⇘GT⇙ (to_int_mod_ring a + to_int_mod_ring b)"
    by (simp add: GT.int_pow_mult asmpt)
  also have "…=  x [^]⇘GT⇙ ((to_int_mod_ring a + to_int_mod_ring b) mod (CARD ('q)))" 
    using pow_mod_order_GT CARD_q asmpt by blast
  also have "…=  x [^]⇘GT⇙ to_int_mod_ring (a + b)"
    by (simp add: plus_mod_ring.rep_eq to_int_mod_ring.rep_eq)
  finally show "x [^]⇘GT⇙ to_int_mod_ring a ⊗⇘GT⇙ x [^]⇘GT⇙ to_int_mod_ring b = x [^]⇘GT⇙ to_int_mod_ring (a + b)" .
qed

subsubsection ‹bilinearity operations for mod\_ring elements›

lemma e_bilinear[simp]: "P ∈ carrier Gp ∧ Q ∈ carrier Gp ⟹ 
   e (P [^]⇘Gp⇙ (to_int_mod_ring (a::'q mod_ring))) (Q [^]⇘Gp⇙ (to_int_mod_ring b)) 
= (e P Q) [^]⇘GT⇙ (to_int_mod_ring (a*b))"
proof -
  assume asm: "P ∈ carrier Gp ∧ Q ∈ carrier Gp"
  then have "e (P [^] to_int_mod_ring a) (Q [^] to_int_mod_ring b) = e P Q [^]⇘GT⇙ (to_int_mod_ring a * to_int_mod_ring b)"
    by simp
   also have "… = (e P Q [^]⇘GT⇙ ((to_int_mod_ring a * to_int_mod_ring b) mod CARD ('q)))"
     using CARD_q pow_mod_order_GT asm e_symmetric by blast
   also have "…= e P Q [^]⇘GT⇙ to_int_mod_ring (a * b)"
     by (simp add: times_mod_ring.rep_eq to_int_mod_ring.rep_eq)
   finally  show "e (P [^] to_int_mod_ring a) (Q [^] to_int_mod_ring b) = e P Q [^]⇘GT⇙ to_int_mod_ring (a * b)"
     .
qed

lemma e_linear_in_fst: 
  assumes "P ∈ carrier Gp ∧ Q ∈ carrier Gp"
  shows "e (P [^]⇘Gp⇙ (to_int_mod_ring (a::'q mod_ring))) (Q) = (e P Q) [^]⇘GT⇙ (to_int_mod_ring a)"
proof -
  have "e (P [^]⇘Gp⇙ to_int_mod_ring a) Q = e (P [^]⇘Gp⇙ to_int_mod_ring a) (Q [^]⇘Gp⇙ to_int_mod_ring (1::'q mod_ring))" using assms by simp
  also have "... = (e P Q) [^]⇘GT⇙ (to_int_mod_ring (a*(1::'q mod_ring)))" using assms e_bilinear by fast
  also have "…=(e P Q) [^]⇘GT⇙ (to_int_mod_ring a)" by simp
  finally show "e (P [^]⇘Gp⇙ (to_int_mod_ring a)) Q = (e P Q) [^]⇘GT⇙ (to_int_mod_ring a)" .
qed

lemma e_linear_in_snd: 
assumes "P ∈ carrier Gp ∧ Q ∈ carrier Gp"
shows "e (P) (Q [^]⇘Gp⇙ (to_int_mod_ring (a::'q mod_ring))) = (e P Q) [^]⇘GT⇙ (to_int_mod_ring a)"
proof -
have "e P (Q [^]⇘Gp⇙ to_int_mod_ring a) = e (P [^]⇘Gp⇙ to_int_mod_ring (1::'q mod_ring)) (Q [^]⇘Gp⇙ to_int_mod_ring a)" using assms by simp
  also have "... = (e P Q) [^]⇘GT⇙ (to_int_mod_ring ((1::'q mod_ring)*a))" using assms e_bilinear by fast
  also have "…=(e P Q) [^]⇘GT⇙ (to_int_mod_ring a)" by simp
  finally show "e P (Q [^]⇘Gp⇙ to_int_mod_ring a) = e P Q [^]⇘GT⇙ to_int_mod_ring a" .
qed

lemma addition_in_exponents_on_e[simp]: 
  assumes "x ∈ carrier Gp ∧ y ∈ carrier Gp "
  shows "(e x y) ^⇘GT⇙ a ⊗⇘GT⇙ (e x y) ^⇘GT⇙ b = (e x y) ^⇘GT⇙ (a+b)"
  using assms
  by (metis PiE e_symmetric mod_ring_pow_mult_GT)

lemma e_from_generators_ne_1: "e g⇘Gp⇙ g⇘Gp⇙ ≠ 𝟭⇘GT⇙"
proof 
  assume asm: "e g⇘Gp⇙ g⇘Gp⇙ = 𝟭⇘GT⇙"
  have "∀P Q. P ∈ carrier Gp ∧ Q ∈ carrier Gp ⟶ e P Q = 𝟭⇘GT⇙" 
  proof(intro allI)
    fix P Q
    show "P ∈ carrier Gp ∧ Q ∈ carrier Gp ⟶ e P Q = 𝟭⇘GT⇙ "
    proof 
      assume "P ∈ carrier Gp ∧ Q ∈ carrier Gp"
      then obtain p q::int where "g⇘Gp⇙ [^]⇘Gp⇙ p = P ∧ g⇘Gp⇙ [^]⇘Gp⇙ q = Q"
        by (metis Gp.generatorE int_pow_int)
      then have "e P Q = e (g⇘Gp⇙ [^]⇘Gp⇙ p) (g⇘Gp⇙ [^]⇘Gp⇙ q)"
        by blast
      also have "… = e g⇘Gp⇙ g⇘Gp⇙ [^]⇘GT⇙ (p*q)"
        by force
      also have "… =  𝟭⇘GT⇙ [^]⇘GT⇙ (p*q)"
        using asm by argo
      also have "… =  𝟭⇘GT⇙"
        by fastforce
      finally show "e P Q = 𝟭⇘GT⇙" .
    qed
  qed
  then show "False" using e_non_degeneracy by blast
qed

lemma pow_on_eq_card_GT[simp]: "(g⇘GT⇙ ^⇘GT⇙ x = g⇘GT⇙ ^⇘GT⇙ y) = (x=y)"
proof
  assume assm: "g⇘GT⇙ ^⇘GT⇙ x = g⇘GT⇙ ^⇘GT⇙ y"
  then have "g⇘GT⇙ [^]⇘GT⇙ to_int_mod_ring x = g⇘GT⇙ [^]⇘GT⇙ to_int_mod_ring y"
    using assm by blast
  then have "g⇘GT⇙ [^]⇘GT⇙ nat (to_int_mod_ring x) = g⇘GT⇙ [^]⇘GT⇙ nat (to_int_mod_ring y)" 
    using to_int_mod_ring_ge_0[of "x"] to_int_mod_ring_ge_0[of "y"] by fastforce
  then have "[nat (to_int_mod_ring x) = nat (to_int_mod_ring y)] (mod order GT)"
    using GT.pow_generator_eq_iff_cong GT.finite_carrier by fast
  then have "[to_int_mod_ring x = to_int_mod_ring y] (mod order GT)" 
    using to_int_mod_ring_ge_0[of "x"] to_int_mod_ring_ge_0[of "y"]
    by (metis cong_int_iff int_nat_eq)
  then have "[to_int_mod_ring x = to_int_mod_ring y] (mod p)" 
    using CARD_GT by fast
  then have "to_int_mod_ring x = to_int_mod_ring y"
    by (metis arith_simps(49) to_int_mod_ring_add to_int_mod_ring_hom.hom_0_iff
        unique_euclidean_semiring_class.cong_def CARD_q)
  then show "x = y" by force
next 
  assume "x = y"
  then show "g⇘GT⇙ ^⇘GT⇙ x = g⇘GT⇙ ^⇘GT⇙ y" by fast
qed

lemma pow_on_eq_card_GT_carrier_ext'[simp]: 
  "((e g⇘Gp⇙ g⇘Gp⇙))^⇘GT⇙ x = ((e g⇘Gp⇙ g⇘Gp⇙))^⇘GT⇙ y ⟷ x=y"
proof 
  assume g_pow_x_eq_g_pow_y: "e g g ^⇘GT⇙ x = e g g ^⇘GT⇙ y"
  obtain g_exp::nat where "e g g = g⇘GT⇙ [^]⇘GT⇙ g_exp"
    using GT.generatorE e_g_g_in_carrier_GT by blast
  then have g_exp: "e g g = g⇘GT⇙ ^⇘GT⇙ (of_int_mod_ring (int g_exp))"
    by (metis CARD_GT GT.pow_generator_mod_int math_primitives.CARD_q math_primitives_axioms int_pow_int of_int_mod_ring.rep_eq to_int_mod_ring.rep_eq)
  let ?g_exp = "of_int_mod_ring (int g_exp)"
  have "(e g g)^⇘GT⇙ x =  g⇘GT⇙ ^⇘GT⇙ (of_int_mod_ring (int g_exp) * x)"
    using g_exp
    by (metis CARD_GT GT.generator_closed GT.int_pow_pow GT.pow_generator_mod_int math_primitives.CARD_q math_primitives_axioms times_mod_ring.rep_eq to_int_mod_ring.rep_eq)
  moreover have "(e g g)^⇘GT⇙ y = g⇘GT⇙ ^⇘GT⇙ (of_int_mod_ring (int g_exp) * y)"
    using g_exp
    by (metis CARD_GT GT.generator_closed GT.int_pow_pow GT.pow_generator_mod_int math_primitives.CARD_q math_primitives_axioms times_mod_ring.rep_eq to_int_mod_ring.rep_eq)
  ultimately show "x =y"
    using g_pow_x_eq_g_pow_y pow_on_eq_card_GT e_from_generators_ne_1 g_exp by force
next 
    assume "x = y"
    then show "(e g⇘Gp⇙ g⇘Gp⇙) ^⇘GT⇙ x = (e g⇘Gp⇙ g⇘Gp⇙) ^⇘GT⇙ y" 
      by blast
  qed

end

end