Class FiniteCyclicGroup `{G: Group}
      (g : GroupElement)(order : posnat)(groupLog : GroupElement -> GroupElement -> nat) := {
                                                                             
  generator : GroupElement -> Prop;
  g_generator : generator g;
  group_cyclic: forall (g a : GroupElement),
    generator g ->
    g^(groupLog g a) = a;
  groupLog_correct: forall g x,
    generator g ->
    modNat (groupLog g (g^x)) order = modNat x order;
  groupIdent : forall g,
    generator g -> 
    g^0 = ident;
  groupOrder : forall g,
    generator g ->
    g^order = g^0
    
}.Class FiniteCyclicGroup `{G: Group}
      (g : GroupElement)(order : posnat)(groupLog : GroupElement -> GroupElement -> nat) := {
                                                                             
  generator : GroupElement -> Prop;
  g_generator : generator g;
  group_cyclic: forall (g a : GroupElement),
    generator g ->
    g^(groupLog g a) = a;
  groupLog_correct: forall g x,
    generator g ->
    modNat (groupLog g (g^x)) order = modNat x order;
  groupIdent : forall g,
    generator g -> 
    g^0 = ident;
  groupOrder : forall g,
    generator g ->
    g^order = g^0
    
}.Class FiniteCyclicGroup `{G: Group}
      (g : GroupElement)(order : posnat)(groupLog : GroupElement -> GroupElement -> nat) := {
                                                                             
  generator : GroupElement -> Prop;
  g_generator : generator g;
  group_cyclic: forall (g a : GroupElement),
    generator g ->
    g^(groupLog g a) = a;
  groupLog_correct: forall g x,
    generator g ->
    modNat (groupLog g (g^x)) order = modNat x order;
  groupIdent : forall g,
    generator g -> 
    g^0 = ident;
  groupOrder : forall g,
    generator g ->
    g^order = g^0
    
}.Class FiniteCyclicGroup `{G: Group}
      (g : GroupElement)(order : posnat)(groupLog : GroupElement -> GroupElement -> nat) := {
                                                                             
  generator : GroupElement -> Prop;
  g_generator : generator g;
  group_cyclic: forall (g a : GroupElement),
    generator g ->
    g^(groupLog g a) = a;
  groupLog_correct: forall g x,
    generator g ->
    modNat (groupLog g (g^x)) order = modNat x order;
  groupIdent : forall g,
    generator g -> 
    g^0 = ident;
  groupOrder : forall g,
    generator g ->
    g^order = g^0
    
}.Class FiniteCyclicGroup `{G: Group}
      (g : GroupElement)(order : posnat)(groupLog : GroupElement -> GroupElement -> nat) := {
                                                                             
  generator : GroupElement -> Prop;
  g_generator : generator g;
  group_cyclic: forall (g a : GroupElement),
    generator g ->
    g^(groupLog g a) = a;
  groupLog_correct: forall g x,
    generator g ->
    modNat (groupLog g (g^x)) order = modNat x order;
  groupIdent : forall g,
    generator g -> 
    g^0 = ident;
  groupOrder : forall g,
    generator g ->
    g^order = g^0
    
}.Class FiniteCyclicGroup `{G: Group}
      (g : GroupElement)(order : posnat)(groupLog : GroupElement -> GroupElement -> nat) := {
                                                                             
  generator : GroupElement -> Prop;
  g_generator : generator g;
  group_cyclic: forall (g a : GroupElement),
    generator g ->
    g^(groupLog g a) = a;
  groupLog_correct: forall g x,
    generator g ->
    modNat (groupLog g (g^x)) order = modNat x order;
  groupIdent : forall g,
    generator g -> 
    g^0 = ident;
  groupOrder : forall g,
    generator g ->
    g^order = g^0
    
}.Class FiniteCyclicGroup `{G: Group}
      (g : GroupElement)(order : posnat)(groupLog : GroupElement -> GroupElement -> nat) := {
                                                                             
  generator : GroupElement -> Prop;
  g_generator : generator g;
  group_cyclic: forall (g a : GroupElement),
    generator g ->
    g^(groupLog g a) = a;
  groupLog_correct: forall g x,
    generator g ->
    modNat (groupLog g (g^x)) order = modNat x order;
  groupIdent : forall g,
    generator g -> 
    g^0 = ident;
  groupOrder : forall g,
    generator g ->
    g^order = g^0
    
}.

(* Specifications: *)
Lemma groupExp_eq_h : forall g c1 v, generator g -> v < order -> g^(c1 * order + v) = g^v.
Theorem groupExp_eq_if : forall g x y, generator g -> modNat x order = modNat y order -> g^x = g^y.
Theorem commutativity : forall x y, x * y = y * x.
Theorem groupExp_distrib : forall n x y, (x * y)^n = x^n * y^n.
Theorem groupExp_eq : forall g x y, generator g -> g^x = g^y -> modNat x order = modNat y order.
Theorem ident_l_unique : forall x y, x * y = y -> x = ident.
Theorem groupExp_mod : forall g n, generator g -> g^n = g^(modNat n order).