From Coq Require Import BinNums.
From Coq Require Import Morphisms.
Require Import Crypto.Spec.WeierstrassCurve Crypto.Curves.Weierstrass.Affine.
Require Import Crypto.Algebra.Field Crypto.Algebra.Hierarchy.
Require Import Crypto.Util.Decidable Crypto.Util.Tactics.DestructHead Crypto.Util.Tactics.BreakMatch.
From Coq Require Import BinPos.

Module W.
  Section W.
    Context {F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv} {a b:F}
            {field:@Algebra.Hierarchy.field F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv}
            {Feq_dec:DecidableRel Feq}.
    Local Infix "=" := Feq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope.
    Local Notation "0" := Fzero.  Local Notation "1" := Fone.
    Local Infix "+" := Fadd. Local Infix "-" := Fsub. Local Infix "*" := Fmul.
    Local Notation "4" := (1+1+1+1). Local Notation "27" := (4*4 + 4+4 +1+1+1).

    Local Ltac Algebra_split :=
      repeat match goal with
             | |- Proper _ _ => cbv [Proper respectful]; intros
             | |- Equivalence _ => split; [intros ? | intros ??? | intros ????? ]
             | |- monoid => split
             | |- group => split
             | |- commutative_group => split
             | |- is_associative => split; intros ???
             | |- is_commutative => split; intros ??
             | |- is_left_inverse => split; intros ?
             | |- is_right_inverse => split; intros ?
             | |- is_left_identity => split; intros ?
             | |- is_right_identity => split; intros ?
             end.

    Global Instance commutative_group
           char_ge_3
           {char_ge_12:@Ring.char_ge F Feq Fzero Fone Fopp Fadd Fsub Fmul 12%positive} (* FIXME: shouldn't need we need 4, not 12? *)
           {discriminant_nonzero:id(4*a*a*a + 27*b*b <> 0)}
      : commutative_group(eq:=W.eq(a:=a)(b:=b))(op:=W.add(char_ge_3:=char_ge_3))(id:=W.zero)(inv:=W.opp).
    Proof using Type.
      Time
        cbv [W.opp W.eq W.zero W.add W.coordinates proj1_sig];
          repeat match goal with
                 | _ => progress Algebra_split
                 | H: _ /\ _ |- _ => destruct H
                 | |- _ /\ _ => split
                 | _ => progress break_match
                 | _ => progress break_match_hyps
                 end; try contradiction; trivial.
      Time par: abstract (fsatz || (cbv [id] in *; fsatz)).
    Time Qed.
  End W.
End W.
