(* The record of operations *)

Structure fparams: Type := {
 K:> Set;               (* the scalar type *)
 v0: K;                (* 0 *)
 v1: K;                (* 1 *)
 eqK: K -> K -> bool;  (* = as a boolean function *)
 oppK: K -> K;         (* - unary *)
 addK : K -> K -> K;   (* + *)
 multK : K -> K -> K;  (* * *)
 invK : K -> K         (* 1/x *)
}.(* The record of operations *)

Structure fparams: Type := {
 K:> Set;               (* the scalar type *)
 v0: K;                (* 0 *)
 v1: K;                (* 1 *)
 eqK: K -> K -> bool;  (* = as a boolean function *)
 oppK: K -> K;         (* - unary *)
 addK : K -> K -> K;   (* + *)
 multK : K -> K -> K;  (* * *)
 invK : K -> K         (* 1/x *)
}.(* The record of operations *)

Structure fparams: Type := {
 K:> Set;               (* the scalar type *)
 v0: K;                (* 0 *)
 v1: K;                (* 1 *)
 eqK: K -> K -> bool;  (* = as a boolean function *)
 oppK: K -> K;         (* - unary *)
 addK : K -> K -> K;   (* + *)
 multK : K -> K -> K;  (* * *)
 invK : K -> K         (* 1/x *)
}.(* The record of operations *)

Structure fparams: Type := {
 K:> Set;               (* the scalar type *)
 v0: K;                (* 0 *)
 v1: K;                (* 1 *)
 eqK: K -> K -> bool;  (* = as a boolean function *)
 oppK: K -> K;         (* - unary *)
 addK : K -> K -> K;   (* + *)
 multK : K -> K -> K;  (* * *)
 invK : K -> K         (* 1/x *)
}.(* The record of operations *)

Structure fparams: Type := {
 K:> Set;               (* the scalar type *)
 v0: K;                (* 0 *)
 v1: K;                (* 1 *)
 eqK: K -> K -> bool;  (* = as a boolean function *)
 oppK: K -> K;         (* - unary *)
 addK : K -> K -> K;   (* + *)
 multK : K -> K -> K;  (* * *)
 invK : K -> K         (* 1/x *)
}.(* The record of operations *)

Structure fparams: Type := {
 K:> Set;               (* the scalar type *)
 v0: K;                (* 0 *)
 v1: K;                (* 1 *)
 eqK: K -> K -> bool;  (* = as a boolean function *)
 oppK: K -> K;         (* - unary *)
 addK : K -> K -> K;   (* + *)
 multK : K -> K -> K;  (* * *)
 invK : K -> K         (* 1/x *)
}.(* The record of operations *)

Structure fparams: Type := {
 K:> Set;               (* the scalar type *)
 v0: K;                (* 0 *)
 v1: K;                (* 1 *)
 eqK: K -> K -> bool;  (* = as a boolean function *)
 oppK: K -> K;         (* - unary *)
 addK : K -> K -> K;   (* + *)
 multK : K -> K -> K;  (* * *)
 invK : K -> K         (* 1/x *)
}.(* The record of operations *)

Structure fparams: Type := {
 K:> Set;               (* the scalar type *)
 v0: K;                (* 0 *)
 v1: K;                (* 1 *)
 eqK: K -> K -> bool;  (* = as a boolean function *)
 oppK: K -> K;         (* - unary *)
 addK : K -> K -> K;   (* + *)
 multK : K -> K -> K;  (* * *)
 invK : K -> K         (* 1/x *)
}.(* The record of operations *)

Structure fparams: Type := {
 K:> Set;               (* the scalar type *)
 v0: K;                (* 0 *)
 v1: K;                (* 1 *)
 eqK: K -> K -> bool;  (* = as a boolean function *)
 oppK: K -> K;         (* - unary *)
 addK : K -> K -> K;   (* + *)
 multK : K -> K -> K;  (* * *)
 invK : K -> K         (* 1/x *)
}.Notation "x ?= y" := (eqK _ x y) (at level 70) : field_scope.Notation "x + y" := (addK _ x y) : field_scope.Notation "- x" := (oppK _ x) : field_scope.Notation "x ^-1" := (invK _ x) (at level 25) : field_scope.Notation "x * y" := (multK _ x y) : field_scope.Notation "0" := (v0 _) : field_scope.Notation "1" := (v1 _) : field_scope.(* Properties associated with a params *)
Structure fparamsProp: Type := {
 eqK_dec: forall x y: p, if x ?= y then x = y else x <> y;        
          (* Boolean equality *)
 addK_assoc: forall x y z: p, (x + y) + z = x + (y + z);
          (* Associativity for + *)
 addK_com: forall x y: p, x + y = y + x;
          (* Commutativity for + *)
 addK0l: forall x: p, 0 + x = x;
          (* Left neutral  for + *)
 oppKr: forall x: p, x + - x = 0;
          (* Right opposite  for + *)
 multK_assoc: forall x y z: p, (x * y) * z = x * (y * z);
          (* Associativity for * *)
 multK_com: forall x y: p, x * y = y * x;
          (* Commutativity for * *)
 multK1l: forall x: p, 1 * x = x;
          (* Left neutral element for * *)
 add_multKl: forall x y z: p, (x + y) * z = x * z + y * z;
          (* Left distributivity of + over * *)
 one_diff_zero: 1 <> 0 :> p;
          (* Inverse *)
 invKl: forall x: p, x <> 0 -> x * x^-1 = 1
}.(* Properties associated with a params *)
Structure fparamsProp: Type := {
 eqK_dec: forall x y: p, if x ?= y then x = y else x <> y;        
          (* Boolean equality *)
 addK_assoc: forall x y z: p, (x + y) + z = x + (y + z);
          (* Associativity for + *)
 addK_com: forall x y: p, x + y = y + x;
          (* Commutativity for + *)
 addK0l: forall x: p, 0 + x = x;
          (* Left neutral  for + *)
 oppKr: forall x: p, x + - x = 0;
          (* Right opposite  for + *)
 multK_assoc: forall x y z: p, (x * y) * z = x * (y * z);
          (* Associativity for * *)
 multK_com: forall x y: p, x * y = y * x;
          (* Commutativity for * *)
 multK1l: forall x: p, 1 * x = x;
          (* Left neutral element for * *)
 add_multKl: forall x y z: p, (x + y) * z = x * z + y * z;
          (* Left distributivity of + over * *)
 one_diff_zero: 1 <> 0 :> p;
          (* Inverse *)
 invKl: forall x: p, x <> 0 -> x * x^-1 = 1
}.(* Properties associated with a params *)
Structure fparamsProp: Type := {
 eqK_dec: forall x y: p, if x ?= y then x = y else x <> y;        
          (* Boolean equality *)
 addK_assoc: forall x y z: p, (x + y) + z = x + (y + z);
          (* Associativity for + *)
 addK_com: forall x y: p, x + y = y + x;
          (* Commutativity for + *)
 addK0l: forall x: p, 0 + x = x;
          (* Left neutral  for + *)
 oppKr: forall x: p, x + - x = 0;
          (* Right opposite  for + *)
 multK_assoc: forall x y z: p, (x * y) * z = x * (y * z);
          (* Associativity for * *)
 multK_com: forall x y: p, x * y = y * x;
          (* Commutativity for * *)
 multK1l: forall x: p, 1 * x = x;
          (* Left neutral element for * *)
 add_multKl: forall x y z: p, (x + y) * z = x * z + y * z;
          (* Left distributivity of + over * *)
 one_diff_zero: 1 <> 0 :> p;
          (* Inverse *)
 invKl: forall x: p, x <> 0 -> x * x^-1 = 1
}.(* Properties associated with a params *)
Structure fparamsProp: Type := {
 eqK_dec: forall x y: p, if x ?= y then x = y else x <> y;        
          (* Boolean equality *)
 addK_assoc: forall x y z: p, (x + y) + z = x + (y + z);
          (* Associativity for + *)
 addK_com: forall x y: p, x + y = y + x;
          (* Commutativity for + *)
 addK0l: forall x: p, 0 + x = x;
          (* Left neutral  for + *)
 oppKr: forall x: p, x + - x = 0;
          (* Right opposite  for + *)
 multK_assoc: forall x y z: p, (x * y) * z = x * (y * z);
          (* Associativity for * *)
 multK_com: forall x y: p, x * y = y * x;
          (* Commutativity for * *)
 multK1l: forall x: p, 1 * x = x;
          (* Left neutral element for * *)
 add_multKl: forall x y z: p, (x + y) * z = x * z + y * z;
          (* Left distributivity of + over * *)
 one_diff_zero: 1 <> 0 :> p;
          (* Inverse *)
 invKl: forall x: p, x <> 0 -> x * x^-1 = 1
}.(* Properties associated with a params *)
Structure fparamsProp: Type := {
 eqK_dec: forall x y: p, if x ?= y then x = y else x <> y;        
          (* Boolean equality *)
 addK_assoc: forall x y z: p, (x + y) + z = x + (y + z);
          (* Associativity for + *)
 addK_com: forall x y: p, x + y = y + x;
          (* Commutativity for + *)
 addK0l: forall x: p, 0 + x = x;
          (* Left neutral  for + *)
 oppKr: forall x: p, x + - x = 0;
          (* Right opposite  for + *)
 multK_assoc: forall x y z: p, (x * y) * z = x * (y * z);
          (* Associativity for * *)
 multK_com: forall x y: p, x * y = y * x;
          (* Commutativity for * *)
 multK1l: forall x: p, 1 * x = x;
          (* Left neutral element for * *)
 add_multKl: forall x y z: p, (x + y) * z = x * z + y * z;
          (* Left distributivity of + over * *)
 one_diff_zero: 1 <> 0 :> p;
          (* Inverse *)
 invKl: forall x: p, x <> 0 -> x * x^-1 = 1
}.(* Properties associated with a params *)
Structure fparamsProp: Type := {
 eqK_dec: forall x y: p, if x ?= y then x = y else x <> y;        
          (* Boolean equality *)
 addK_assoc: forall x y z: p, (x + y) + z = x + (y + z);
          (* Associativity for + *)
 addK_com: forall x y: p, x + y = y + x;
          (* Commutativity for + *)
 addK0l: forall x: p, 0 + x = x;
          (* Left neutral  for + *)
 oppKr: forall x: p, x + - x = 0;
          (* Right opposite  for + *)
 multK_assoc: forall x y z: p, (x * y) * z = x * (y * z);
          (* Associativity for * *)
 multK_com: forall x y: p, x * y = y * x;
          (* Commutativity for * *)
 multK1l: forall x: p, 1 * x = x;
          (* Left neutral element for * *)
 add_multKl: forall x y z: p, (x + y) * z = x * z + y * z;
          (* Left distributivity of + over * *)
 one_diff_zero: 1 <> 0 :> p;
          (* Inverse *)
 invKl: forall x: p, x <> 0 -> x * x^-1 = 1
}.(* Properties associated with a params *)
Structure fparamsProp: Type := {
 eqK_dec: forall x y: p, if x ?= y then x = y else x <> y;        
          (* Boolean equality *)
 addK_assoc: forall x y z: p, (x + y) + z = x + (y + z);
          (* Associativity for + *)
 addK_com: forall x y: p, x + y = y + x;
          (* Commutativity for + *)
 addK0l: forall x: p, 0 + x = x;
          (* Left neutral  for + *)
 oppKr: forall x: p, x + - x = 0;
          (* Right opposite  for + *)
 multK_assoc: forall x y z: p, (x * y) * z = x * (y * z);
          (* Associativity for * *)
 multK_com: forall x y: p, x * y = y * x;
          (* Commutativity for * *)
 multK1l: forall x: p, 1 * x = x;
          (* Left neutral element for * *)
 add_multKl: forall x y z: p, (x + y) * z = x * z + y * z;
          (* Left distributivity of + over * *)
 one_diff_zero: 1 <> 0 :> p;
          (* Inverse *)
 invKl: forall x: p, x <> 0 -> x * x^-1 = 1
}.(* Properties associated with a params *)
Structure fparamsProp: Type := {
 eqK_dec: forall x y: p, if x ?= y then x = y else x <> y;        
          (* Boolean equality *)
 addK_assoc: forall x y z: p, (x + y) + z = x + (y + z);
          (* Associativity for + *)
 addK_com: forall x y: p, x + y = y + x;
          (* Commutativity for + *)
 addK0l: forall x: p, 0 + x = x;
          (* Left neutral  for + *)
 oppKr: forall x: p, x + - x = 0;
          (* Right opposite  for + *)
 multK_assoc: forall x y z: p, (x * y) * z = x * (y * z);
          (* Associativity for * *)
 multK_com: forall x y: p, x * y = y * x;
          (* Commutativity for * *)
 multK1l: forall x: p, 1 * x = x;
          (* Left neutral element for * *)
 add_multKl: forall x y z: p, (x + y) * z = x * z + y * z;
          (* Left distributivity of + over * *)
 one_diff_zero: 1 <> 0 :> p;
          (* Inverse *)
 invKl: forall x: p, x <> 0 -> x * x^-1 = 1
}.(* Properties associated with a params *)
Structure fparamsProp: Type := {
 eqK_dec: forall x y: p, if x ?= y then x = y else x <> y;        
          (* Boolean equality *)
 addK_assoc: forall x y z: p, (x + y) + z = x + (y + z);
          (* Associativity for + *)
 addK_com: forall x y: p, x + y = y + x;
          (* Commutativity for + *)
 addK0l: forall x: p, 0 + x = x;
          (* Left neutral  for + *)
 oppKr: forall x: p, x + - x = 0;
          (* Right opposite  for + *)
 multK_assoc: forall x y z: p, (x * y) * z = x * (y * z);
          (* Associativity for * *)
 multK_com: forall x y: p, x * y = y * x;
          (* Commutativity for * *)
 multK1l: forall x: p, 1 * x = x;
          (* Left neutral element for * *)
 add_multKl: forall x y z: p, (x + y) * z = x * z + y * z;
          (* Left distributivity of + over * *)
 one_diff_zero: 1 <> 0 :> p;
          (* Inverse *)
 invKl: forall x: p, x <> 0 -> x * x^-1 = 1
}.(* Properties associated with a params *)
Structure fparamsProp: Type := {
 eqK_dec: forall x y: p, if x ?= y then x = y else x <> y;        
          (* Boolean equality *)
 addK_assoc: forall x y z: p, (x + y) + z = x + (y + z);
          (* Associativity for + *)
 addK_com: forall x y: p, x + y = y + x;
          (* Commutativity for + *)
 addK0l: forall x: p, 0 + x = x;
          (* Left neutral  for + *)
 oppKr: forall x: p, x + - x = 0;
          (* Right opposite  for + *)
 multK_assoc: forall x y z: p, (x * y) * z = x * (y * z);
          (* Associativity for * *)
 multK_com: forall x y: p, x * y = y * x;
          (* Commutativity for * *)
 multK1l: forall x: p, 1 * x = x;
          (* Left neutral element for * *)
 add_multKl: forall x y z: p, (x + y) * z = x * z + y * z;
          (* Left distributivity of + over * *)
 one_diff_zero: 1 <> 0 :> p;
          (* Inverse *)
 invKl: forall x: p, x <> 0 -> x * x^-1 = 1
}.(* Properties associated with a params *)
Structure fparamsProp: Type := {
 eqK_dec: forall x y: p, if x ?= y then x = y else x <> y;        
          (* Boolean equality *)
 addK_assoc: forall x y z: p, (x + y) + z = x + (y + z);
          (* Associativity for + *)
 addK_com: forall x y: p, x + y = y + x;
          (* Commutativity for + *)
 addK0l: forall x: p, 0 + x = x;
          (* Left neutral  for + *)
 oppKr: forall x: p, x + - x = 0;
          (* Right opposite  for + *)
 multK_assoc: forall x y z: p, (x * y) * z = x * (y * z);
          (* Associativity for * *)
 multK_com: forall x y: p, x * y = y * x;
          (* Commutativity for * *)
 multK1l: forall x: p, 1 * x = x;
          (* Left neutral element for * *)
 add_multKl: forall x y z: p, (x + y) * z = x * z + y * z;
          (* Left distributivity of + over * *)
 one_diff_zero: 1 <> 0 :> p;
          (* Inverse *)
 invKl: forall x: p, x <> 0 -> x * x^-1 = 1
}.(* Properties associated with a params *)
Structure fparamsProp: Type := {
 eqK_dec: forall x y: p, if x ?= y then x = y else x <> y;        
          (* Boolean equality *)
 addK_assoc: forall x y z: p, (x + y) + z = x + (y + z);
          (* Associativity for + *)
 addK_com: forall x y: p, x + y = y + x;
          (* Commutativity for + *)
 addK0l: forall x: p, 0 + x = x;
          (* Left neutral  for + *)
 oppKr: forall x: p, x + - x = 0;
          (* Right opposite  for + *)
 multK_assoc: forall x y z: p, (x * y) * z = x * (y * z);
          (* Associativity for * *)
 multK_com: forall x y: p, x * y = y * x;
          (* Commutativity for * *)
 multK1l: forall x: p, 1 * x = x;
          (* Left neutral element for * *)
 add_multKl: forall x y z: p, (x + y) * z = x * z + y * z;
          (* Left distributivity of + over * *)
 one_diff_zero: 1 <> 0 :> p;
          (* Inverse *)
 invKl: forall x: p, x <> 0 -> x * x^-1 = 1
}.Fixpoint expK  (k: p) (n:nat) {struct n}: p := 
  match n with O => 1 | (S n1) => k * expK k n1 end.Notation "x ^ k" := (expK _ x%f k) : field_scope.Implicit Types x y z: p.

Lemma expK_add n1 n2 a: a ^ (n1 + n2) = a ^n1 * a ^ n2.