diff options
-rw-r--r-- | .gitignore | 11 | ||||
-rw-r--r-- | .mailmap | 3 | ||||
-rw-r--r-- | .travis.yml | 17 | ||||
-rw-r--r-- | _CoqProject | 2 | ||||
-rw-r--r-- | src/Algebra.v | 329 | ||||
-rw-r--r-- | src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v | 25 | ||||
-rw-r--r-- | src/CompleteEdwardsCurve/ExtendedCoordinates.v | 14 | ||||
-rw-r--r-- | src/CompleteEdwardsCurve/Pre.v | 2 | ||||
-rw-r--r-- | src/Experiments/DerivationsOptionRectLetInEncoding.v | 59 | ||||
-rw-r--r-- | src/Experiments/EdDSARefinement.v | 96 | ||||
-rw-r--r-- | src/Experiments/SpecEd25519.v | 8 | ||||
-rw-r--r-- | src/Spec/EdDSA.v | 25 | ||||
-rw-r--r-- | src/Tactics/Nsatz.v | 3 | ||||
-rw-r--r-- | src/Util/Decidable.v | 35 | ||||
-rw-r--r-- | src/Util/Option.v | 62 | ||||
-rw-r--r-- | src/Util/Sum.v | 16 | ||||
-rw-r--r-- | src/Util/Tactics.v | 28 | ||||
-rw-r--r-- | src/Util/Tuple.v | 15 |
18 files changed, 618 insertions, 132 deletions
diff --git a/.gitignore b/.gitignore index 9028c237e..f88b441c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,10 @@ -bedrock -fiat +.#* *~ *# -*.vo +*.aux *.d *.glob -*.aux -*.vio -Makefile.coq Makefile.bak +Makefile.coq +*.vio +*.vo @@ -8,8 +8,9 @@ Andres Erbsen <andreser@mit.edu> Andres Erbsen <andres Jade Philipoom <jadep@mit.edu> Jade Philipoom <jadep@mit.edu> Jade Philipoom <jadep@mit.edu> jadep <jade.philipoom@gmail.com> Jade Philipoom <jadep@mit.edu> jadep <jadep@mit.edu> -Jason Gross <jgross@mit.edu> Jason Gross <jgross@mit.edu> Jason Gross <jgross@mit.edu> Jason Gross <jagro@google.com> +Jason Gross <jgross@mit.edu> Jason Gross <jasongross9@gmail.com> +Jason Gross <jgross@mit.edu> Jason Gross <jgross@mit.edu> Robert Sloan <varomodt@gmail.com> Robert Sloan <rsloan@sumologic.com> Robert Sloan <varomodt@gmail.com> Robert Sloan <varomodt@dhcp-18-189-26-21.dyn.MIT.EDU> Robert Sloan <varomodt@gmail.com> Robert Sloan <varomodt@dhcp-18-189-51-40.dyn.MIT.EDU> diff --git a/.travis.yml b/.travis.yml index 1092e385a..5412f31a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,19 @@ language: generic sudo: required -dist: trusty -env: - matrix: - - COQ_VERSION="8.4" COQPRIME="coqprime-8.4" - - COQ_VERSION="8.5" COQPRIME="coqprime" +matrix: + include: + - dist: trusty + env: COQ_VERSION="8.5pl1" COQ_PACKAGE="coq-8.5pl1" COQPRIME="coqprime" PPA="ppa:jgross-h/many-coq-versions" + - dist: trusty + env: COQ_VERSION="8.5" COQ_PACKAGE="coq-8.5" COQPRIME="coqprime" PPA="ppa:jgross-h/many-coq-versions" + - dist: trusty + env: COQ_VERSION="8.4" COQ_PACKAGE="coq" COQPRIME="coqprime-8.4" PPA="" before_install: - - if [ "$COQ_VERSION" == "8.5" ]; then sudo add-apt-repository ppa:jgross-h/coq-backports -y; fi + - if [ ! -z "$PPA" ]; then sudo add-apt-repository "$PPA" -y; fi - sudo apt-get update -q - - sudo apt-get install coq -y + - sudo apt-get install "$COQ_PACKAGE" -y script: make COQPATH="$(pwd)/$COQPRIME" TIMED=1 -j2 diff --git a/_CoqProject b/_CoqProject index afad38124..904d716b8 100644 --- a/_CoqProject +++ b/_CoqProject @@ -29,6 +29,7 @@ src/Encoding/EncodingTheorems.v src/Encoding/ModularWordEncodingPre.v src/Encoding/ModularWordEncodingTheorems.v src/Experiments/DerivationsOptionRectLetInEncoding.v +src/Experiments/EdDSARefinement.v src/Experiments/GenericFieldPow.v src/Experiments/SpecEd25519.v src/ModularArithmetic/ExtendedBaseVector.v @@ -58,6 +59,7 @@ src/Util/ListUtil.v src/Util/NatUtil.v src/Util/Notations.v src/Util/NumTheoryUtil.v +src/Util/Option.v src/Util/Sum.v src/Util/Tactics.v src/Util/Tuple.v diff --git a/src/Algebra.v b/src/Algebra.v index 15e0bcd38..ef8e2850a 100644 --- a/src/Algebra.v +++ b/src/Algebra.v @@ -1,12 +1,26 @@ Require Import Coq.Classes.Morphisms. Require Coq.Setoids.Setoid. Require Import Crypto.Util.Tactics Crypto.Tactics.Nsatz. +Require Import Crypto.Util.Decidable. +Require Import Crypto.Util.Notations. +Require Coq.Numbers.Natural.Peano.NPeano. Local Close Scope nat_scope. Local Close Scope type_scope. Local Close Scope core_scope. +Module Import ModuloCoq8485. + Import NPeano Nat. + Infix "mod" := modulo (at level 40, no associativity). +End ModuloCoq8485. + +Notation is_eq_dec := (DecidableRel _) (only parsing). +Notation "@ 'is_eq_dec' T R" := (DecidableRel (R:T->T->Prop)) + (at level 10, T at level 8, R at level 8, only parsing). +Notation eq_dec x y := (@dec (_ x y) _) (only parsing). +Notation "x =? y" := (eq_dec x y) : type_scope. + Section Algebra. Context {T:Type} {eq:T->T->Prop}. Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. - Class is_eq_dec := { eq_dec : forall x y : T, {x=y} + {x<>y} }. + Local Notation is_eq_dec := (@is_eq_dec T eq). Section SingleOperation. Context {op:T->T->T}. @@ -206,7 +220,7 @@ Module Group. Proof. eauto using Monoid.cancel_right, right_inverse. Qed. Lemma inv_inv x : inv(inv(x)) = x. Proof. eauto using Monoid.inv_inv, left_inverse. Qed. - Lemma inv_op x y : (inv y*inv x)*(x*y) =id. + Lemma inv_op_ext x y : (inv y*inv x)*(x*y) =id. Proof. eauto using Monoid.inv_op, left_inverse. Qed. Lemma inv_unique x ix : ix * x = id -> ix = inv x. @@ -217,6 +231,14 @@ Module Group. - rewrite Hix, left_identity; reflexivity. Qed. + Lemma inv_op x y : inv (x*y) = inv y*inv x. + Proof. + symmetry. etransitivity. + 2:eapply inv_unique. + 2:eapply inv_op_ext. + reflexivity. + Qed. + Lemma inv_id : inv id = id. Proof. symmetry. eapply inv_unique, left_identity. Qed. @@ -277,8 +299,8 @@ Module Group. Admitted. End Homomorphism. - Section SurjectiveHomomorphism. - Lemma surjective_homomorphism_group + Section GroupByHomomorphism. + Lemma surjective_homomorphism_from_group {G EQ OP ID INV} {groupG:@group G EQ OP ID INV} {H eq op id inv} {Equivalence_eq: @Equivalence H eq} {eq_dec: forall x y, {eq x y} + {~ eq x y}} @@ -286,9 +308,9 @@ Module Group. {Proper_inv:Proper(eq==>eq)inv} {phi iph} {Proper_phi:Proper(EQ==>eq)phi} {Proper_iph:Proper(eq==>EQ)iph} {surj:forall h, phi (iph h) = h} - {phi_op : forall a b, phi (OP a b) = op (phi a) (phi b)} - {phi_inv : forall a, phi (INV a) = inv (phi a)} - {phi_id : phi ID = id} + {phi_op : forall a b, eq (phi (OP a b)) (op (phi a) (phi b))} + {phi_inv : forall a, eq (phi (INV a)) (inv (phi a))} + {phi_id : eq (phi ID) id} : @group H eq op id inv. Proof. repeat split; eauto with core typeclass_instances; intros; @@ -303,7 +325,78 @@ Module Group. repeat rewrite <-?phi_op, <-?phi_inv, <-?phi_id; f_equiv; auto using associative, left_identity, right_identity, left_inverse, right_inverse. Qed. - End SurjectiveHomomorphism. + + Lemma isomorphism_to_subgroup_group + {G EQ OP ID INV} + {Equivalence_EQ: @Equivalence G EQ} {eq_dec: forall x y, {EQ x y} + {~ EQ x y}} + {Proper_OP:Proper(EQ==>EQ==>EQ)OP} + {Proper_INV:Proper(EQ==>EQ)INV} + {H eq op id inv} {groupG:@group H eq op id inv} + {phi} + {eq_phi_EQ: forall x y, eq (phi x) (phi y) -> EQ x y} + {phi_op : forall a b, eq (phi (OP a b)) (op (phi a) (phi b))} + {phi_inv : forall a, eq (phi (INV a)) (inv (phi a))} + {phi_id : eq (phi ID) id} + : @group G EQ OP ID INV. + Proof. + repeat split; eauto with core typeclass_instances; intros; + eapply eq_phi_EQ; + repeat rewrite ?phi_op, ?phi_inv, ?phi_id; + auto using associative, left_identity, right_identity, left_inverse, right_inverse. + Qed. + End GroupByHomomorphism. + + Section ScalarMult. + Context {G eq add zero opp} `{@group G eq add zero opp}. + Context {mul:nat->G->G}. + Local Infix "=" := eq : type_scope. Local Infix "=" := eq. + Local Infix "+" := add. Local Infix "*" := mul. + Class is_scalarmult := + { + scalarmult_0_l : forall P, 0 * P = zero; + scalarmult_S_l : forall n P, S n * P = P + n * P; + + scalarmult_Proper : Proper (Logic.eq==>eq==>eq) mul + }. + Global Existing Instance scalarmult_Proper. + Context `{is_scalarmult}. + + Lemma scalarmult_1_l : forall P, 1*P = P. + Proof. intros. rewrite scalarmult_S_l, scalarmult_0_l, right_identity; reflexivity. Qed. + + Lemma scalarmult_add_l : forall (n m:nat) (P:G), ((n + m)%nat * P = n * P + m * P). + Proof. + induction n; intros; + rewrite ?scalarmult_0_l, ?scalarmult_S_l, ?plus_Sn_m, ?plus_O_n, ?scalarmult_S_l, ?left_identity, <-?associative, <-?IHn; reflexivity. + Qed. + + Lemma scalarmult_zero_r : forall m, m * zero = zero. + Proof. induction m; rewrite ?scalarmult_S_l, ?scalarmult_0_l, ?left_identity, ?IHm; try reflexivity. Qed. + + Lemma scalarmult_assoc : forall (n m : nat) P, n * (m * P) = (m * n)%nat * P. + Proof. + induction n; intros. + { rewrite <-mult_n_O, !scalarmult_0_l. reflexivity. } + { rewrite scalarmult_S_l, <-mult_n_Sm, <-Plus.plus_comm, scalarmult_add_l. apply cancel_left, IHn. } + Qed. + + Lemma opp_mul : forall n P, opp (n * P) = n * (opp P). + induction n; intros. + { rewrite !scalarmult_0_l, inv_id; reflexivity. } + { rewrite <-NPeano.Nat.add_1_l, Plus.plus_comm at 1. + rewrite scalarmult_add_l, scalarmult_1_l, inv_op, scalarmult_S_l, cancel_left; eauto. } + Qed. + + Lemma scalarmult_times_order : forall l B, l*B = zero -> forall n, (l * n) * B = zero. + Proof. intros ? ? Hl ?. rewrite <-scalarmult_assoc, Hl, scalarmult_zero_r. reflexivity. Qed. + + Lemma scalarmult_mod_order : forall l B, l <> 0%nat -> l*B = zero -> forall n, n mod l * B = n * B. + Proof. + intros ? ? Hnz Hmod ?. + rewrite (NPeano.Nat.div_mod n l Hnz) at 2. + rewrite scalarmult_add_l, scalarmult_times_order, left_identity by auto. reflexivity. + Qed. + End ScalarMult. End Group. Require Coq.nsatz.Nsatz. @@ -551,6 +644,16 @@ Ltac guess_field := | [H: not (?eq _ _) |- _] => constr:(_:field (eq:=eq)) end. +Ltac field_nonzero_mul_split := + repeat match goal with + | [ H : ?R (?mul ?x ?y) ?zero |- _ ] + => apply IntegralDomain.mul_nonzero_nonzero_cases in H; destruct H + | [ |- not (?R (?mul ?x ?y) ?zero) ] + => apply IntegralDomain.mul_nonzero_nonzero_iff; split + | [ H : not (?R (?mul ?x ?y) ?zero) |- _ ] + => apply IntegralDomain.mul_nonzero_nonzero_iff in H; destruct H + end. + Ltac common_denominator := let fld := guess_field in lazymatch type of fld with @@ -575,6 +678,137 @@ Ltac common_denominator_all := common_denominator; repeat match goal with [H: _ |- _ _ _ ] => progress common_denominator_in H end. +(** Now we have more conservative versions that don't simplify non-division structure. *) +Ltac deduplicate_nonfraction_pieces mul := + repeat match goal with + | [ x0 := ?v, x1 := context[?v] |- _ ] + => progress change v with x0 in x1 + | [ x := mul ?a ?b |- _ ] + => not is_var a; + let a' := fresh x in + pose a as a'; change a with a' in x + | [ x := mul ?a ?b |- _ ] + => not is_var b; + let b' := fresh x in + pose b as b'; change b with b' in x + | [ x0 := ?v, x1 := ?v |- _ ] + => change x1 with x0 in *; clear x1 + | [ x := ?v |- _ ] + => is_var v; subst x + | [ x0 := mul ?a ?b, x1 := mul ?a ?b' |- _ ] + => subst x0 x1 + | [ x0 := mul ?a ?b, x1 := mul ?a' ?b |- _ ] + => subst x0 x1 + end. + +Ltac set_nonfraction_pieces_on T eq zero opp add sub mul inv div nonzero_tac cont := + idtac; + let one_arg_recr := + fun op v + => set_nonfraction_pieces_on + v eq zero opp add sub mul inv div nonzero_tac + ltac:(fun x => cont (op x)) in + let two_arg_recr := + fun op v0 v1 + => set_nonfraction_pieces_on + v0 eq zero opp add sub mul inv div nonzero_tac + ltac:(fun x + => + set_nonfraction_pieces_on + v1 eq zero opp add sub mul inv div nonzero_tac + ltac:(fun y => cont (op x y))) in + lazymatch T with + | eq ?x ?y => two_arg_recr eq x y + | appcontext[div] + => lazymatch T with + | div ?numerator ?denominator + => let d := fresh "d" in + pose denominator as d; + assert (~eq d zero); + [ subst d; nonzero_tac + | set_nonfraction_pieces_on + numerator eq zero opp add sub mul inv div nonzero_tac + ltac:(fun numerator' + => cont (div numerator' d)) ] + | opp ?x => one_arg_recr opp x + | inv ?x => one_arg_recr inv x + | add ?x ?y => two_arg_recr add x y + | sub ?x ?y => two_arg_recr sub x y + | mul ?x ?y => two_arg_recr mul x y + | div ?x ?y => two_arg_recr div x y + | _ => idtac + end + | _ => let x := fresh "x" in + pose T as x; + cont x + end. +Ltac set_nonfraction_pieces_in_by H nonzero_tac := + idtac; + let fld := guess_field in + lazymatch type of fld with + | @field ?T ?eq ?zero ?one ?opp ?add ?sub ?mul ?inv ?div + => let T := type of H in + set_nonfraction_pieces_on + T eq zero opp add sub mul inv div nonzero_tac + ltac:(fun T' => change T' in H); + deduplicate_nonfraction_pieces mul + end. +Ltac set_nonfraction_pieces_by nonzero_tac := + idtac; + let fld := guess_field in + lazymatch type of fld with + | @field ?T ?eq ?zero ?one ?opp ?add ?sub ?mul ?inv ?div + => let T := get_goal in + set_nonfraction_pieces_on + T eq zero opp add sub mul inv div nonzero_tac + ltac:(fun T' => change T'); + deduplicate_nonfraction_pieces mul + end. +Ltac set_nonfraction_pieces_in H := + set_nonfraction_pieces_in_by H ltac:(try (intro; field_nonzero_mul_split; try tauto)). +Ltac set_nonfraction_pieces := + set_nonfraction_pieces_by ltac:(try (intro; field_nonzero_mul_split; tauto)). +Ltac conservative_common_denominator_in H := + idtac; + let fld := guess_field in + let div := lazymatch type of fld with + | @field ?T ?eq ?zero ?one ?opp ?add ?sub ?mul ?inv ?div + => div + end in + lazymatch type of H with + | appcontext[div] + => set_nonfraction_pieces_in H; + [ .. + | common_denominator_in H; + [ repeat split; try assumption.. + | ] ]; + repeat match goal with H := _ |- _ => subst H end + | ?T => fail 0 "no division in" H ":" T + end. +Ltac conservative_common_denominator := + idtac; + let fld := guess_field in + let div := lazymatch type of fld with + | @field ?T ?eq ?zero ?one ?opp ?add ?sub ?mul ?inv ?div + => div + end in + lazymatch goal with + | |- appcontext[div] + => set_nonfraction_pieces; + [ .. + | common_denominator; + [ repeat split; try assumption.. + | ] ]; + repeat match goal with H := _ |- _ => subst H end + | |- ?G + => fail 0 "no division in goal" G + end. + +Ltac conservative_common_denominator_all := + try conservative_common_denominator; + [ .. + | repeat match goal with [H: _ |- _ ] => progress conservative_common_denominator_in H; [] end ]. + Inductive field_simplify_done {T} : T -> Type := Field_simplify_done : forall H, field_simplify_done H. @@ -592,6 +826,21 @@ Ltac field_simplify_eq_hyps := Ltac field_simplify_eq_all := field_simplify_eq_hyps; try field_simplify_eq. +(** Clear duplicate hypotheses, and hypotheses of the form [R x x] for a reflexive relation [R] *) +Ltac clear_algebraic_duplicates_step R := + match goal with + | [ H : R ?x ?x |- _ ] + => clear H + end. +Ltac clear_algebraic_duplicates_guarded R := + let test_reflexive := constr:(_ : Reflexive R) in + repeat clear_algebraic_duplicates_step R. +Ltac clear_algebraic_duplicates := + clear_duplicates; + repeat match goal with + | [ H : ?R ?x ?x |- _ ] => clear_algebraic_duplicates_guarded R + end. + (*** Inequalities over fields *) Ltac assert_expr_by_nsatz H ty := let H' := fresh in @@ -647,6 +896,16 @@ Ltac neq01 := |apply one_neq_zero |apply Group.opp_one_neq_zero]. +Ltac conservative_field_algebra := + intros; + conservative_common_denominator_all; + try (nsatz; dropRingSyntax); + repeat (apply conj); + try solve + [neq01 + |trivial + |apply Ring.opp_nonzero_nonzero;trivial]. + Ltac field_algebra := intros; common_denominator_all; @@ -675,8 +934,62 @@ Section ExtraLemmas. Proof. intros; setoid_subst z; eauto using only_two_square_roots'. Qed. + + Lemma only_two_square_roots'_choice x y : x * x = y * y -> x = y \/ x = opp y. + Proof. + intro H. + destruct (eq_dec x y); [ left; assumption | right ]. + destruct (eq_dec x (opp y)); [ assumption | exfalso ]. + eapply only_two_square_roots'; eassumption. + Qed. + + Lemma only_two_square_roots_choice x y z : x * x = z -> y * y = z -> x = y \/ x = opp y. + Proof. + intros; setoid_subst z; eauto using only_two_square_roots'_choice. + Qed. End ExtraLemmas. +(** We look for hypotheses of the form [x^2 = y^2] and [x^2 = z] together with [y^2 = z], and prove that [x = y] or [x = opp y] *) +Ltac pose_proof_only_two_square_roots x y H := + not constr_eq x y; + match goal with + | [ H' : ?eq (?mul x x) (?mul y y) |- _ ] + => pose proof (only_two_square_roots'_choice x y H') as H + | [ H0 : ?eq (?mul x x) ?z, H1 : ?eq (?mul y y) ?z |- _ ] + => pose proof (only_two_square_roots_choice x y z H0 H1) as H + end. +Ltac reduce_only_two_square_roots x y := + let H := fresh in + pose_proof_only_two_square_roots x y H; + destruct H; + try setoid_subst y. +Ltac pre_clean_only_two_square_roots := + clear_algebraic_duplicates. +(** Remove duplicates; solve goals by contradiction, and, if goals still remain, substitute the square roots *) +Ltac post_clean_only_two_square_roots x y := + clear_algebraic_duplicates; + try (unfold not in *; + match goal with + | [ H : (?T -> False)%type, H' : ?T |- _ ] => exfalso; apply H; exact H' + | [ H : (?R ?x ?x -> False)%type |- _ ] => exfalso; apply H; reflexivity + end); + try setoid_subst x; try setoid_subst y. +Ltac only_two_square_roots_step := + match goal with + | [ H : not (?eq ?x (?opp ?y)) |- _ ] + (* this one comes first, because it the procedure is asymmetric + with respect to [x] and [y], and this order is more likely to + lead to solving goals by contradiction. *) + => is_var x; is_var y; reduce_only_two_square_roots x y; post_clean_only_two_square_roots x y + | [ H : ?eq (?mul ?x ?x) (?mul ?y ?y) |- _ ] + => reduce_only_two_square_roots x y; post_clean_only_two_square_roots x y + | [ H : ?eq (?mul ?x ?x) ?z, H' : ?eq (?mul ?y ?y) ?z |- _ ] + => reduce_only_two_square_roots x y; post_clean_only_two_square_roots x y + end. +Ltac only_two_square_roots := + pre_clean_only_two_square_roots; + repeat only_two_square_roots_step. + Section Example. Context {F zero one opp add sub mul inv div} `{F_field:field F eq zero one opp add sub mul inv div}. Local Infix "+" := add. Local Infix "*" := mul. Local Infix "-" := sub. Local Infix "/" := div. diff --git a/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v b/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v index 476592b36..0afc07c5d 100644 --- a/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v +++ b/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v @@ -119,7 +119,7 @@ Module E. | |- _ => split | |- Feq _ _ => field_algebra | |- _ <> 0 => expand_opp; solve [nsatz_nonzero|eauto 6] - | |- {_}+{_} => eauto 15 using decide_and, @eq_dec with typeclass_instances + | |- Decidable.Decidable _ => solve [ typeclasses eauto ] end. Ltac bash := repeat bash_step. @@ -138,25 +138,14 @@ Module E. match goal with | |- _ <> 0 => admit end. Admitted. - (* TODO: move to [Group] and [AbelianGroup] as appropriate *) - Lemma mul_0_l : forall P, (0 * P = zero)%E. - Proof. intros; reflexivity. Qed. - Lemma mul_S_l : forall n P, (S n * P = P + n * P)%E. - Proof. intros; reflexivity. Qed. - Lemma mul_add_l : forall (n m:nat) (P:point), ((n + m)%nat * P = n * P + m * P)%E. + Global Instance Proper_mul : Proper (Logic.eq==>eq==>eq) mul. Proof. - induction n; intros; - rewrite ?plus_Sn_m, ?plus_O_n, ?mul_S_l, ?left_identity, <-?associative, <-?IHn; reflexivity. + intros n m Hnm P Q HPQ. rewrite <-Hnm; clear Hnm m. + induction n; simpl; rewrite ?IHn, ?HPQ; reflexivity. Qed. - Lemma mul_assoc : forall (n m : nat) P, (n * (m * P) = (n * m)%nat * P)%E. - Proof. - induction n; intros; [reflexivity|]. - rewrite ?mul_S_l, ?Mult.mult_succ_l, ?mul_add_l, ?IHn, commutative; reflexivity. - Qed. - Lemma mul_zero_r : forall m, (m * E.zero = E.zero)%E. - Proof. induction m; rewrite ?mul_S_l, ?left_identity, ?IHm; try reflexivity. Qed. - Lemma opp_mul : forall n P, (opp (n * P) = n * (opp P))%E. - Admitted. + + Global Instance mul_is_scalarmult : @is_scalarmult point eq add zero mul. + Proof. split; intros; reflexivity || typeclasses eauto. Qed. Section PointCompression. Local Notation "x ^ 2" := (x*x). diff --git a/src/CompleteEdwardsCurve/ExtendedCoordinates.v b/src/CompleteEdwardsCurve/ExtendedCoordinates.v index deeb795b1..364d7f9ec 100644 --- a/src/CompleteEdwardsCurve/ExtendedCoordinates.v +++ b/src/CompleteEdwardsCurve/ExtendedCoordinates.v @@ -63,6 +63,8 @@ Module Extended. (let '(X,Y,Z,T) := coordinates P in ((X/Z), (Y/Z))) _. Definition eq (P Q:point) := E.eq (to_twisted P) (to_twisted Q). + Global Instance DecidableRel_eq : Decidable.DecidableRel eq. + Proof. typeclasses eauto. Qed. Local Hint Unfold from_twisted to_twisted eq : bash. @@ -148,6 +150,18 @@ Module Extended. Lemma homomorphism_from_twisted : @Group.is_homomorphism Epoint E.eq E.add point eq add from_twisted. Proof. split; trivial using Proper_from_twisted, add_from_twisted. Qed. + Definition zero : point := from_twisted E.zero. + Definition opp P : point := from_twisted (E.opp (to_twisted P)). + Lemma extended_group : @group point eq add zero opp. + Proof. + eapply @isomorphism_to_subgroup_group; eauto with typeclass_instances core. + - apply DecidableRel_eq. + - unfold opp. repeat intro. match goal with [H:_|-_] => rewrite H; reflexivity end. + - intros. apply to_twisted_add. + - unfold opp; intros; rewrite to_twisted_from_twisted; reflexivity. + - unfold zero; intros; rewrite to_twisted_from_twisted; reflexivity. + Qed. + (* TODO: decide whether we still need those, then port *) (* Lemma unifiedAddM1_0_r : forall P, unifiedAddM1 P (mkExtendedPoint E.zero) === P. diff --git a/src/CompleteEdwardsCurve/Pre.v b/src/CompleteEdwardsCurve/Pre.v index be8ca24a2..be423c05c 100644 --- a/src/CompleteEdwardsCurve/Pre.v +++ b/src/CompleteEdwardsCurve/Pre.v @@ -41,7 +41,7 @@ Section Pre. => apply d_nonsquare with (sqrt_d:= (f (sqrt_a * x1) (d * x1 * x2 * y1 * y2 * y1)) /(f (sqrt_a * x2) y2 * x1 * y1 )) | _ => apply a_nonzero - end; field_algebra; auto using Ring.opp_nonzero_nonzero; intro; nsatz_contradict. + end; field_algebra; auto using Ring.opp_nonzero_nonzero; nsatz_contradict. Qed. Lemma edwardsAddCompletePlus x1 y1 x2 y2 : diff --git a/src/Experiments/DerivationsOptionRectLetInEncoding.v b/src/Experiments/DerivationsOptionRectLetInEncoding.v index e5b74085e..c0b6be25b 100644 --- a/src/Experiments/DerivationsOptionRectLetInEncoding.v +++ b/src/Experiments/DerivationsOptionRectLetInEncoding.v @@ -150,63 +150,6 @@ Proof. end. Qed. -Global Instance option_rect_Proper_nd {A T} - : Proper ((pointwise_relation _ eq) ==> eq ==> eq ==> eq) (@option_rect A (fun _ => T)). -Proof. - intros ?? H ??? [|]??; subst; simpl; congruence. -Qed. - -Global Instance option_rect_Proper_nd' {A T} - : Proper ((pointwise_relation _ eq) ==> eq ==> forall_relation (fun _ => eq)) (@option_rect A (fun _ => T)). -Proof. - intros ?? H ??? [|]; subst; simpl; congruence. -Qed. - -Hint Extern 1 (Proper _ (@option_rect ?A (fun _ => ?T))) => exact (@option_rect_Proper_nd' A T) : typeclass_instances. - -Lemma option_rect_option_map : forall {A B C} (f:A->B) some none v, - option_rect (fun _ => C) (fun x => some (f x)) none v = option_rect (fun _ => C) some none (option_map f v). -Proof. - destruct v; reflexivity. -Qed. - -Lemma option_rect_function {A B C S' N' v} f - : f (option_rect (fun _ : option A => option B) S' N' v) - = option_rect (fun _ : option A => C) (fun x => f (S' x)) (f N') v. -Proof. destruct v; reflexivity. Qed. -Local Ltac commute_option_rect_Let_In := (* pull let binders out side of option_rect pattern matching *) - idtac; - lazymatch goal with - | [ |- ?LHS = option_rect ?P ?S ?N (Let_In ?x ?f) ] - => (* we want to just do a [change] here, but unification is stupid, so we have to tell it what to unfold in what order *) - cut (LHS = Let_In x (fun y => option_rect P S N (f y))); cbv beta; - [ set_evars; - let H := fresh in - intro H; - rewrite H; - clear; - abstract (cbv [Let_In]; reflexivity) - | ] - end. - -(** TODO: possibly move me, remove local *) -Local Ltac replace_option_match_with_option_rect := - idtac; - lazymatch goal with - | [ |- _ = ?RHS :> ?T ] - => lazymatch RHS with - | match ?a with None => ?N | Some x => @?S x end - => replace RHS with (option_rect (fun _ => T) S N a) by (destruct a; reflexivity) - end - end. -Local Ltac simpl_option_rect := (* deal with [option_rect _ _ _ None] and [option_rect _ _ _ (Some _)] *) - repeat match goal with - | [ |- context[option_rect ?P ?S ?N None] ] - => change (option_rect P S N None) with N - | [ |- context[option_rect ?P ?S ?N (Some ?x) ] ] - => change (option_rect P S N (Some x)) with (S x); cbv beta - end. - Definition COMPILETIME {T} (x:T) : T := x. Lemma N_to_nat_le_mono : forall a b, (a <= b)%N -> (N.to_nat a <= N.to_nat b)%nat. @@ -348,4 +291,4 @@ End with_unqualified_modulo2. Lemma F_eqb_iff {q} : forall x y : F q, F_eqb x y = true <-> x = y. Proof. split; eauto using F_eqb_eq, F_eqb_complete. -Qed. +Qed.
\ No newline at end of file diff --git a/src/Experiments/EdDSARefinement.v b/src/Experiments/EdDSARefinement.v new file mode 100644 index 000000000..cf9083061 --- /dev/null +++ b/src/Experiments/EdDSARefinement.v @@ -0,0 +1,96 @@ +Require Import Crypto.Spec.EdDSA Bedrock.Word. +Require Import Coq.Classes.Morphisms. +Require Import Crypto.Algebra. Import Group. +Require Import Util.Decidable Util.Option Util.Tactics. +Require Import Omega. + +Module Import NotationsFor8485. + Import NPeano Nat. + Infix "mod" := modulo (at level 40). +End NotationsFor8485. + +Section EdDSA. + Context `{prm:EdDSA}. + Context {eq_dec:DecidableRel Eeq}. + Local Infix "==" := Eeq (at level 69, no associativity). + Local Notation valid := (@valid E Eeq Eadd EscalarMult b H l B Eenc Senc). + Local Infix "*" := EscalarMult. Local Infix "+" := Eadd. Local Infix "++" := combine. + Local Notation "P - Q" := (P + Eopp Q). + + Context {Proper_Eenc : Proper (Eeq==>Logic.eq) Eenc}. + Context {Proper_Eopp : Proper (Eeq==>Eeq) Eopp}. + Context {Proper_Eadd : Proper (Eeq==>Eeq==>Eeq) Eadd}. + + Context {decE:word b-> option E}. + Context {decS:word b-> option nat}. + + Context {decE_canonical: forall x s, decE x = Some s -> x = Eenc s }. + Context {decS_canonical: forall x s, decS x = Some s -> x = Senc s }. + + Context {decS_Senc: forall x, decS (Senc x) = Some x}. + Context {decE_Eenc: forall x, decE (Eenc x) = Some x}. (* FIXME: equivalence relation *) + + Lemma solve_for_R : forall s B R n A, s * B == R + n * A <-> R == s*B - n*A. + Proof. + intros; split; + intro Heq; rewrite Heq; clear Heq. + { rewrite <-associative, right_inverse, right_identity; reflexivity. } + { rewrite <-associative, left_inverse, right_identity; reflexivity. } + Qed. + + Definition verify {mlen} (message:word mlen) (pk:word b) (sig:word (b+b)) : bool := + option_rect (fun _ => bool) (fun S : nat => + option_rect (fun _ => bool) (fun A : E => + weqb + (split1 b b sig) + (Eenc (S * B - (wordToNat (H (b + (b + mlen)) (split1 b b sig ++ pk ++ message))) mod l * A)) + ) false (decE pk) + ) false (decS (split2 b b sig)) + . + + Lemma verify_correct mlen (message:word mlen) (pk:word b) (sig:word (b+b)) : + verify message pk sig = true <-> valid message pk sig. + Proof. + cbv [verify option_rect option_map]. + split. + { + repeat match goal with + | |- false = true -> _ => let H:=fresh "H" in intro H; discriminate H + | [H: _ |- _ ] => apply decS_canonical in H + | [H: _ |- _ ] => apply decE_canonical in H + | _ => rewrite weqb_true_iff + | _ => break_match + end. + intro. + subst. + rewrite <-combine_split. + rewrite Heqo. + rewrite H0. + constructor. + rewrite <-H0. + rewrite solve_for_R. + reflexivity. + } + { + intros [? ? ? ? Hvalid]. + rewrite solve_for_R in Hvalid. + rewrite split1_combine. + rewrite split2_combine. + rewrite decS_Senc. + rewrite decE_Eenc. + rewrite weqb_true_iff. + f_equiv. exact Hvalid. + } + Qed. + + Lemma sign_valid : forall A_ sk {n} (M:word n), A_ = public sk -> valid M A_ (sign A_ sk M). + Proof. + cbv [sign public]. intros. subst. split. + rewrite scalarmult_mod_order, scalarmult_add_l, cancel_left, scalarmult_mod_order, NPeano.Nat.mul_comm, scalarmult_assoc; + try solve [ reflexivity + | pose proof EdDSA_l_odd; omega + | apply EdDSA_l_order_B + | rewrite scalarmult_assoc, mult_comm, <-scalarmult_assoc, + EdDSA_l_order_B, scalarmult_zero_r; reflexivity ]. + Qed. +End EdDSA. diff --git a/src/Experiments/SpecEd25519.v b/src/Experiments/SpecEd25519.v index 4e30313d9..659a0ec66 100644 --- a/src/Experiments/SpecEd25519.v +++ b/src/Experiments/SpecEd25519.v @@ -149,11 +149,11 @@ Local Infix "*" := (E.mul(H0:=curve25519params)). Axiom H : forall n : nat, word n -> word (b + b). Axiom B : point. (* TODO: B = decodePoint (y=4/5, x="positive") *) Axiom B_nonzero : B <> zero. -Axiom l_order_B : l * B = zero. -Axiom point_encoding : canonical encoding of point as word b. -Axiom scalar_encoding : canonical encoding of {n : nat | n < l} as word b. +Axiom l_order_B : E.eq (l * B) zero. +Axiom Eenc : point -> word b. +Axiom Senc : nat -> word b. -Global Instance Ed25519 : @EdDSA point E.eq add zero E.opp E.mul b H c n l B point_encoding scalar_encoding := +Global Instance Ed25519 : @EdDSA point E.eq add zero E.opp E.mul b H c n l B Eenc Senc := { EdDSA_c_valid := c_valid; EdDSA_n_ge_c := n_ge_c; diff --git a/src/Spec/EdDSA.v b/src/Spec/EdDSA.v index c28ff0482..03a723e10 100644 --- a/src/Spec/EdDSA.v +++ b/src/Spec/EdDSA.v @@ -1,4 +1,3 @@ -Require Import Crypto.Spec.Encoding. Require Bedrock.Word Crypto.Util.WordUtil. Require Coq.ZArith.Znumtheory Coq.ZArith.BinInt. Require Coq.Numbers.Natural.Peano.NPeano. @@ -33,11 +32,12 @@ Section EdDSA. {B : E} (* base point *) - {PointEncoding : canonical encoding of E as Word.word b} (* wire format *) - {FlEncoding : canonical encoding of { n | n < l } as Word.word b} + {Eenc : E -> Word.word b} (* normative encoding of elliptic cuve points *) + {Senc : nat -> Word.word b} (* normative encoding of scalars *) := { EdDSA_group:@Algebra.group E Eeq Eadd Ezero Eopp; + EdDSA_scalarmult:@Algebra.Group.is_scalarmult E Eeq Eadd Ezero EscalarMult; EdDSA_c_valid : c = 2 \/ c = 3; @@ -48,13 +48,14 @@ Section EdDSA. EdDSA_l_prime : Znumtheory.prime (BinInt.Z.of_nat l); EdDSA_l_odd : l > 2; - EdDSA_l_order_B : EscalarMult l B = Ezero + EdDSA_l_order_B : Eeq (EscalarMult l B) Ezero }. Global Existing Instance EdDSA_group. + Global Existing Instance EdDSA_scalarmult. Context `{prm:EdDSA}. - Local Infix "=" := Eeq. + Local Infix "=" := Eeq : type_scope. Local Coercion Word.wordToNat : Word.word >-> nat. Local Notation secretkey := (Word.word b) (only parsing). Local Notation publickey := (Word.word b) (only parsing). @@ -75,18 +76,18 @@ Section EdDSA. Local Infix "*" := EscalarMult. Definition prngKey (sk:secretkey) : Word.word b := Word.split2 b b (H sk). - Definition public (sk:secretkey) : publickey := enc (curveKey sk*B). + Definition public (sk:secretkey) : publickey := Eenc (curveKey sk*B). Program Definition sign (A_:publickey) sk {n} (M : Word.word n) := let r : nat := H (prngKey sk ++ M) in (* secret nonce *) let R : E := r * B in (* commitment to nonce *) let s : nat := curveKey sk in (* secret scalar *) - let S : {n|n<l} := exist _ ((r + H (enc R ++ public sk ++ M) * s) mod l) _ in - enc R ++ enc S. + let S : nat := (r + H (Eenc R ++ A_ ++ M) * s) mod l in + Eenc R ++ Senc S. (* For a [n]-bit [message] from public key [A_], validity of a signature [R_ ++ S_] *) Inductive valid {n:nat} : Word.word n -> publickey -> signature -> Prop := - ValidityRule : forall (message:Word.word n) (A:E) (R:E) (S:nat) S_lt_l, - S * B = R + (H (enc R ++ enc A ++ message) mod l) * A - -> valid message (enc A) (enc R ++ enc (exist _ S S_lt_l)). -End EdDSA. + ValidityRule : forall (message:Word.word n) (A:E) (R:E) (S:nat), + S * B = R + (H (Eenc R ++ Eenc A ++ message) mod l) * A + -> valid message (Eenc A) (Eenc R ++ Senc S). +End EdDSA.
\ No newline at end of file diff --git a/src/Tactics/Nsatz.v b/src/Tactics/Nsatz.v index 84d472e54..04f35c200 100644 --- a/src/Tactics/Nsatz.v +++ b/src/Tactics/Nsatz.v @@ -85,7 +85,8 @@ Ltac nsatz_clear_duplicates_for_bug_4851 domain := Ltac nsatz_nonzero := try solve [apply Integral_domain.integral_domain_one_zero |apply Integral_domain.integral_domain_minus_one_zero - |trivial]. + |trivial + |assumption]. Ltac nsatz_domain_sugar_power domain sugar power := let nparams := constr:(BinInt.Zneg BinPos.xH) in (* some symbols can be "parameters", treated as coefficients *) diff --git a/src/Util/Decidable.v b/src/Util/Decidable.v index 726b52b6b..c2094c765 100644 --- a/src/Util/Decidable.v +++ b/src/Util/Decidable.v @@ -14,7 +14,7 @@ Ltac destruct_decidable_step := end. Ltac destruct_decidable := repeat destruct_decidable_step. -Local Ltac pre_decide := +Ltac pre_decide := repeat (intros || destruct_decidable || subst @@ -22,34 +22,34 @@ Local Ltac pre_decide := || unfold Decidable in * || hnf ). -Local Ltac solve_decidable_transparent_with tac := +Ltac solve_decidable_transparent_with tac := pre_decide; try solve [ left; abstract tac | right; abstract tac | decide equality; eauto with nocore ]. -Local Ltac solve_decidable_transparent := solve_decidable_transparent_with firstorder. +Ltac solve_decidable_transparent := solve_decidable_transparent_with firstorder. Local Hint Extern 0 => solve [ solve_decidable_transparent ] : typeclass_instances. -Global Instance dec_True : Decidable True := left I. -Global Instance dec_False : Decidable False := right (fun x => x). -Global Instance dec_or {A B} `{Decidable A, Decidable B} : Decidable (A \/ B). exact _. Defined. -Global Instance dec_and {A B} `{Decidable A, Decidable B} : Decidable (A /\ B). exact _. Defined. -Global Instance dec_impl {A B} `{Decidable (B \/ ~A)} : Decidable (A -> B) | 3. exact _. Defined. -Global Instance dec_impl_simple {A B} `{Decidable A, Decidable B} : Decidable (A -> B). exact _. Defined. -Global Instance dec_iff {A B} `{Decidable A, Decidable B} : Decidable (A <-> B). exact _. Defined. +Global Instance dec_True : Decidable True | 10 := left I. +Global Instance dec_False : Decidable False | 10 := right (fun x => x). +Global Instance dec_or {A B} `{Decidable A, Decidable B} : Decidable (A \/ B) | 10. exact _. Defined. +Global Instance dec_and {A B} `{Decidable A, Decidable B} : Decidable (A /\ B) | 10. exact _. Defined. +Global Instance dec_impl {A B} `{Decidable (B \/ ~A)} : Decidable (A -> B) | 10. exact _. Defined. +Global Instance dec_impl_simple {A B} `{Decidable A, Decidable B} : Decidable (A -> B) | 10. exact _. Defined. +Global Instance dec_iff {A B} `{Decidable A, Decidable B} : Decidable (A <-> B) | 10. exact _. Defined. Lemma dec_not {A} `{Decidable A} : Decidable (~A). Proof. solve_decidable_transparent. Defined. (** Disallow infinite loops of dec_not *) Hint Extern 0 (Decidable (~?A)) => apply (@dec_not A) : typeclass_instances. -Global Instance dec_eq_unit : DecidableRel (@eq unit). exact _. Defined. -Global Instance dec_eq_bool : DecidableRel (@eq bool). exact _. Defined. -Global Instance dec_eq_Empty_set : DecidableRel (@eq Empty_set). exact _. Defined. -Global Instance dec_eq_nat : DecidableRel (@eq nat). exact _. Defined. -Global Instance dec_eq_prod {A B} `{DecidableRel (@eq A), DecidableRel (@eq B)} : DecidableRel (@eq (A * B)). exact _. Defined. -Global Instance dec_eq_sum {A B} `{DecidableRel (@eq A), DecidableRel (@eq B)} : DecidableRel (@eq (A + B)). exact _. Defined. +Global Instance dec_eq_unit : DecidableRel (@eq unit) | 10. exact _. Defined. +Global Instance dec_eq_bool : DecidableRel (@eq bool) | 10. exact _. Defined. +Global Instance dec_eq_Empty_set : DecidableRel (@eq Empty_set) | 10. exact _. Defined. +Global Instance dec_eq_nat : DecidableRel (@eq nat) | 10. exact _. Defined. +Global Instance dec_eq_prod {A B} `{DecidableRel (@eq A), DecidableRel (@eq B)} : DecidableRel (@eq (A * B)) | 10. exact _. Defined. +Global Instance dec_eq_sum {A B} `{DecidableRel (@eq A), DecidableRel (@eq B)} : DecidableRel (@eq (A + B)) | 10. exact _. Defined. Lemma Decidable_respects_iff A B (H : A <-> B) : (Decidable A -> Decidable B) * (Decidable B -> Decidable A). Proof. solve_decidable_transparent. Defined. @@ -59,3 +59,6 @@ Proof. solve_decidable_transparent. Defined. Lemma Decidable_iff_to_flip_impl A B (H : A <-> B) : Decidable B -> Decidable A. Proof. solve_decidable_transparent. Defined. + +(** For dubious compatibility with [eauto using]. *) +Hint Extern 2 (Decidable _) => progress unfold Decidable : typeclass_instances core. diff --git a/src/Util/Option.v b/src/Util/Option.v new file mode 100644 index 000000000..db4b69dde --- /dev/null +++ b/src/Util/Option.v @@ -0,0 +1,62 @@ +Require Import Coq.Classes.Morphisms. + +Global Instance option_rect_Proper_nd {A T} + : Proper ((pointwise_relation _ eq) ==> eq ==> eq ==> eq) (@option_rect A (fun _ => T)). +Proof. + intros ?? H ??? [|]??; subst; simpl; congruence. +Qed. + +Global Instance option_rect_Proper_nd' {A T} + : Proper ((pointwise_relation _ eq) ==> eq ==> forall_relation (fun _ => eq)) (@option_rect A (fun _ => T)). +Proof. + intros ?? H ??? [|]; subst; simpl; congruence. +Qed. + +Hint Extern 1 (Proper _ (@option_rect ?A (fun _ => ?T))) => exact (@option_rect_Proper_nd' A T) : typeclass_instances. + +Lemma option_rect_option_map : forall {A B C} (f:A->B) some none v, + option_rect (fun _ => C) (fun x => some (f x)) none v = option_rect (fun _ => C) some none (option_map f v). +Proof. + destruct v; reflexivity. +Qed. + +Lemma option_rect_function {A B C S' N' v} f + : f (option_rect (fun _ : option A => option B) S' N' v) + = option_rect (fun _ : option A => C) (fun x => f (S' x)) (f N') v. +Proof. destruct v; reflexivity. Qed. + +(* +Ltac commute_option_rect_Let_In := (* pull let binders out side of option_rect pattern matching *) + idtac; + lazymatch goal with + | [ |- ?LHS = option_rect ?P ?S ?N (Let_In ?x ?f) ] + => (* we want to just do a [change] here, but unification is stupid, so we have to tell it what to unfold in what order *) + cut (LHS = Let_In x (fun y => option_rect P S N (f y))); cbv beta; + [ set_evars; + let H := fresh in + intro H; + rewrite H; + clear; + abstract (cbv [Let_In]; reflexivity) + | ] + end. +*) + +(** TODO: possibly move me, remove local *) +Ltac replace_option_match_with_option_rect := + idtac; + lazymatch goal with + | [ |- _ = ?RHS :> ?T ] + => lazymatch RHS with + | match ?a with None => ?N | Some x => @?S x end + => replace RHS with (option_rect (fun _ => T) S N a) by (destruct a; reflexivity) + end + end. + +Ltac simpl_option_rect := (* deal with [option_rect _ _ _ None] and [option_rect _ _ _ (Some _)] *) + repeat match goal with + | [ |- context[option_rect ?P ?S ?N None] ] + => change (option_rect P S N None) with N + | [ |- context[option_rect ?P ?S ?N (Some ?x) ] ] + => change (option_rect P S N (Some x)) with (S x); cbv beta + end. diff --git a/src/Util/Sum.v b/src/Util/Sum.v index 2f03639b2..1ee8ea69a 100644 --- a/src/Util/Sum.v +++ b/src/Util/Sum.v @@ -1,5 +1,6 @@ Require Import Coq.Classes.Morphisms. Require Import Relation_Definitions. +Require Import Crypto.Util.Decidable. Definition sumwise {A B} (RA:relation A) (RB : relation B) : relation (A + B) := fun x y => match x, y with @@ -16,3 +17,18 @@ Proof. Qed. Arguments sumwise {A B} _ _ _ _. + +Ltac congruence_sum_step := + match goal with + | [ H : inl _ = inr _ |- _ ] => solve [ inversion H ] + | [ H : inr _ = inl _ |- _ ] => solve [ inversion H ] + | [ H : inl _ = inl _ |- _ ] => inversion H; clear H + | [ H : inr _ = inr _ |- _ ] => inversion H; clear H + end. +Ltac congruence_sum := repeat congruence_sum_step. + +Local Hint Extern 0 => solve [ solve_decidable_transparent ] : typeclass_instances. +Global Instance dec_sumwise {A B RA RB} {HA : DecidableRel RA} {HB : DecidableRel RB} : DecidableRel (@sumwise A B RA RB) | 10. +Proof. + intros [x|x] [y|y]; exact _. +Qed. diff --git a/src/Util/Tactics.v b/src/Util/Tactics.v index e8876fee2..fea7dfe16 100644 --- a/src/Util/Tactics.v +++ b/src/Util/Tactics.v @@ -56,13 +56,34 @@ Ltac break_match_step only_when := | [ |- appcontext[match ?e with _ => _ end] ] => only_when e; destruct e eqn:? end. +Ltac break_match_hyps_step only_when := + match goal with + | [ H : appcontext[match ?e with _ => _ end] |- _ ] + => only_when e; is_var e; destruct e + | [ H : appcontext[match ?e with _ => _ end] |- _ ] + => only_when e; + match type of e with + | sumbool _ _ => destruct e + end + | [ H : appcontext[if ?e then _ else _] |- _ ] + => only_when e; destruct e eqn:? + | [ H : appcontext[match ?e with _ => _ end] |- _ ] + => only_when e; destruct e eqn:? + end. Ltac break_match := repeat break_match_step ltac:(fun _ => idtac). +Ltac break_match_hyps := repeat break_match_hyps_step ltac:(fun _ => idtac). Ltac break_match_when_head_step T := break_match_step ltac:(fun e => let T' := type of e in let T' := head T' in constr_eq T T'). +Ltac break_match_hyps_when_head_step T := + break_match_hyps_step + ltac:(fun e => let T' := type of e in + let T' := head T' in + constr_eq T T'). Ltac break_match_when_head T := repeat break_match_when_head_step T. +Ltac break_match_hyps_when_head T := repeat break_match_hyps_when_head_step T. Ltac free_in x y := idtac; @@ -111,3 +132,10 @@ Ltac destruct_trivial_step := | [ H : True |- _ ] => clear H || destruct H end. Ltac destruct_trivial := repeat destruct_trivial_step. + +Ltac clear_duplicates_step := + match goal with + | [ H : ?T, H' : ?T |- _ ] => clear H' + | [ H := ?T, H' := ?T |- _ ] => clear H' + end. +Ltac clear_duplicates := repeat clear_duplicates_step. diff --git a/src/Util/Tuple.v b/src/Util/Tuple.v index 6802a86c3..d08c52c82 100644 --- a/src/Util/Tuple.v +++ b/src/Util/Tuple.v @@ -1,5 +1,6 @@ Require Import Coq.Classes.Morphisms. Require Import Relation_Definitions. +Require Import Crypto.Util.Decidable. Fixpoint tuple' T n : Type := match n with @@ -79,3 +80,17 @@ Qed. Arguments fieldwise' {A B n} _ _ _. Arguments fieldwise {A B n} _ _ _. + +Local Hint Extern 0 => solve [ solve_decidable_transparent ] : typeclass_instances. +Global Instance dec_fieldwise' {A RA} {HA : DecidableRel RA} {n} : DecidableRel (@fieldwise' A A n RA) | 10. +Proof. + induction n; simpl @fieldwise'. + { exact _. } + { intros ??. + exact _. } +Qed. + +Global Instance dec_fieldwise {A RA} {HA : DecidableRel RA} {n} : DecidableRel (@fieldwise A A n RA) | 10. +Proof. + destruct n; unfold fieldwise; exact _. +Qed. |