aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--_CoqProject1
-rw-r--r--src/Galois/BaseSystem.v459
-rw-r--r--src/Galois/ModularBaseSystem.v195
-rw-r--r--src/Util/ListUtil.v45
4 files changed, 671 insertions, 29 deletions
diff --git a/_CoqProject b/_CoqProject
index 016c1a00b..0e56c1ee2 100644
--- a/_CoqProject
+++ b/_CoqProject
@@ -10,6 +10,7 @@ src/Galois/GaloisExamples.v
src/Galois/AbstractGaloisField.v
src/Galois/ComputationalGaloisField.v
src/Galois/BaseSystem.v
+src/Galois/ModularBaseSystem.v
src/Curves/PointFormats.v
src/Assembly/WordBounds.v
src/Curves/Curve25519.v
diff --git a/src/Galois/BaseSystem.v b/src/Galois/BaseSystem.v
index 77428e549..345929475 100644
--- a/src/Galois/BaseSystem.v
+++ b/src/Galois/BaseSystem.v
@@ -40,7 +40,14 @@ Module BaseSystem (Import B:BaseCoefs).
Definition decode' bs u := fold_right accumulate 0 (combine u bs).
Definition decode := decode' base.
Hint Unfold accumulate.
-
+
+ Lemma decode_truncate : forall us, decode us = decode (firstn (length base) us).
+ Proof.
+ intros.
+ unfold decode, decode'.
+ rewrite combine_truncate_l; auto.
+ Qed.
+
Fixpoint add (us vs:digits) : digits :=
match us,vs with
| u::us', v::vs' => u+v :: add us' vs'
@@ -59,6 +66,13 @@ Module BaseSystem (Import B:BaseCoefs).
auto.
Qed.
+ Lemma decode_base_nil : forall us, decode' nil us = 0.
+ Proof.
+ intros.
+ unfold decode'.
+ rewrite combine_truncate_l; auto.
+ Qed.
+
(* mul_geomseq is a valid multiplication algorithm if b_i = b_1^i *)
Fixpoint mul_geomseq (us vs:digits) : digits :=
match us,vs with
@@ -73,6 +87,54 @@ Module BaseSystem (Import B:BaseCoefs).
induction bs; destruct vs; auto; simpl; try rewrite IHbs; ring.
Qed.
+ Lemma decode'_cons : forall x1 x2 xs1 xs2,
+ decode' (x1 :: xs1) (x2 :: xs2) = x1 * x2 + decode' xs1 xs2.
+ Proof.
+ unfold decode'; boring.
+ Qed.
+
+ Hint Rewrite decode'_cons.
+
+ Lemma mul_each_base : forall us bs c,
+ decode' bs (mul_each c us) = decode' (mul_each c bs) us.
+ Proof.
+ induction us; intros; simpl; auto.
+ destruct bs.
+ apply decode_base_nil.
+ unfold mul_each; boring.
+ replace (z * (c * a)) with (c * z * a) by ring; f_equal.
+ unfold mul_each in IHus.
+ apply IHus.
+ Qed.
+
+ Lemma base_app : forall us low high,
+ decode' (low ++ high) us = decode' low (firstn (length low) us) + decode' high (skipn (length low) us).
+ Proof.
+ induction us; intros. {
+ rewrite firstn_nil.
+ rewrite skipn_nil.
+ do 3 rewrite decode_nil; auto.
+ } {
+ destruct low; auto.
+ replace (skipn (length (z :: low)) (a :: us)) with (skipn (length (low)) (us)) by auto.
+ simpl.
+ do 2 rewrite decode'_cons.
+ rewrite IHus.
+ ring.
+ }
+ Qed.
+
+ Lemma base_mul_app : forall low c us,
+ decode' (low ++ mul_each c low) us = decode' low (firstn (length low) us) +
+ c * decode' low (skipn (length low) us).
+ Proof.
+ intros.
+ rewrite base_app; f_equal.
+ rewrite <- mul_each_rep.
+ symmetry; apply mul_each_base.
+ Qed.
+
+
Definition crosscoef i j : Z :=
let b := nth_default 0 base in
(b(i) * b(j)) / b(i+j)%nat.
@@ -86,16 +148,6 @@ Module BaseSystem (Import B:BaseCoefs).
induction n; simpl; auto.
Qed.
- Ltac boring :=
- simpl; intuition;
- repeat match goal with
- | [ H : _ |- _ ] => rewrite H; clear H
- | _ => progress autounfold in *
- | _ => progress try autorewrite with core
- | _ => progress simpl in *
- | _ => progress intuition
- end; ring || eauto.
-
Lemma app_zeros_zeros : forall n m, zeros n ++ zeros m = zeros (n + m).
Proof.
induction n; boring.
@@ -139,14 +191,6 @@ Module BaseSystem (Import B:BaseCoefs).
Hint Extern 1 (@eq Z _ _) => ring.
- Lemma decode'_cons : forall x1 x2 xs1 xs2,
- decode' (x1 :: xs1) (x2 :: xs2) = x1 * x2 + decode' xs1 xs2.
- Proof.
- unfold decode'; boring.
- Qed.
-
- Hint Rewrite decode'_cons.
-
Lemma decode_single : forall n bs x,
decode' bs (zeros n ++ x :: nil) = nth_default 0 bs n * x.
Proof.
@@ -165,6 +209,11 @@ Module BaseSystem (Import B:BaseCoefs).
induction xs; destruct bs; boring.
Qed.
+ Lemma mul_bi'_zeros : forall n m, mul_bi' n (zeros m) = zeros m.
+ induction m; intros; auto.
+ simpl; f_equal; apply IHm.
+ Qed.
+
Lemma mul_bi_single : forall m n x,
(n + m < length base)%nat ->
decode (n .* (zeros m ++ x :: nil)) = nth_default 0 base m * x * nth_default 0 base n.
@@ -185,12 +234,14 @@ Module BaseSystem (Import B:BaseCoefs).
auto.
} {
simpl; ssimpl_list; simpl.
- replace (mul_bi' n (rev (zeros m) ++ 0 :: nil)) with (zeros (S m)) by admit.
- intros; simpl; ssimpl_list; simpl.
+ rewrite rev_zeros.
+ rewrite zeros_app0.
+ rewrite mul_bi'_zeros.
+ simpl; ssimpl_list; simpl.
rewrite length_zeros.
rewrite app_cons_app_app.
rewrite rev_zeros.
- intros; simpl; ssimpl_list; simpl.
+ simpl; ssimpl_list; simpl.
rewrite zeros_app0.
rewrite app_assoc.
rewrite app_zeros_zeros.
@@ -198,7 +249,7 @@ Module BaseSystem (Import B:BaseCoefs).
unfold crosscoef; simpl; ring_simplify.
rewrite NPeano.Nat.add_1_r.
rewrite base_good by auto.
- rewrite Z_div_mult.
+ rewrite Z_div_mult by (apply base_positive; rewrite nth_default_eq; apply nth_In; auto).
rewrite <- Z.mul_assoc.
rewrite <- Z.mul_comm.
rewrite <- Z.mul_assoc.
@@ -207,11 +258,7 @@ Module BaseSystem (Import B:BaseCoefs).
rewrite Z.mul_cancel_l by auto.
rewrite <- base_good by auto.
ring.
-
- apply base_positive.
- rewrite nth_default_eq.
- apply nth_In; auto.
- }
+ }
Qed.
Lemma set_higher' : forall vs x, vs++x::nil = vs .+ (zeros (length vs) ++ x :: nil).
@@ -233,10 +280,347 @@ Module BaseSystem (Import B:BaseCoefs).
simpl; f_equal; auto.
Qed.
+ Lemma mul_bi'_n_nil : forall n, mul_bi' n nil = nil.
+ Proof.
+ intros.
+ unfold mul_bi; auto.
+ Qed.
+
+ Lemma add_nil_l : forall us, nil .+ us = us.
+ induction us; auto.
+ Qed.
+
+ Lemma add_nil_r : forall us, us .+ nil = us.
+ induction us; auto.
+ Qed.
+
+ Lemma add_first_terms : forall us vs a b,
+ (a :: us) .+ (b :: vs) = (a + b) :: (us .+ vs).
+ auto.
+ Qed.
+
+ Lemma mul_bi'_cons : forall n x us,
+ mul_bi' n (x :: us) = x * crosscoef n (length us) :: mul_bi' n us.
+ Proof.
+ unfold mul_bi'; auto.
+ Qed.
+
+ Lemma cons_length : forall A (xs : list A) a, length (a :: xs) = S (length xs).
+ Proof.
+ auto.
+ Qed.
+
+ Lemma add_same_length : forall us vs l, (length us = l) -> (length vs = l) ->
+ length (us .+ vs) = l.
+ Proof.
+ induction us; intros. {
+ rewrite add_nil_l.
+ apply H0.
+ } {
+ destruct vs. {
+ rewrite add_nil_r; apply H.
+ } {
+ rewrite add_first_terms.
+ rewrite cons_length.
+ rewrite (IHus vs (pred l)).
+ apply NPeano.Nat.succ_pred_pos.
+ replace l with (length (a :: us)) by (apply H).
+ rewrite cons_length; simpl.
+ apply gt_Sn_O.
+ replace l with (length (a :: us)) by (apply H).
+ rewrite cons_length; simpl; auto.
+ replace l with (length (z :: vs)) by (apply H).
+ rewrite cons_length; simpl; auto.
+ }
+ }
+ Qed.
+
+ Lemma length0_nil : forall A (xs : list A), length xs = 0%nat -> xs = nil.
+ Proof.
+ induction xs; intros; auto.
+ elimtype False.
+ assert (0 <> length (a :: xs))%nat.
+ rewrite cons_length.
+ apply O_S.
+ contradiction H0.
+ rewrite H; auto.
+ Qed.
+
+ Lemma add_app_same_length : forall l us vs a b,
+ (length us = l) -> (length vs = l) ->
+ (us ++ a :: nil) .+ (vs ++ b :: nil) = (us .+ vs) ++ (a + b) :: nil.
+ Proof.
+ induction l; intros. {
+ assert (us = nil) by (apply length0_nil; apply H).
+ assert (vs = nil) by (apply length0_nil; apply H0).
+ rewrite H1; rewrite app_nil_l.
+ rewrite H2; rewrite app_nil_l.
+ rewrite add_nil_l.
+ rewrite app_nil_l.
+ auto.
+ } {
+ destruct us. {
+ rewrite app_nil_l.
+ rewrite add_nil_l.
+ destruct vs. {
+ rewrite app_nil_l.
+ rewrite app_nil_l.
+ auto.
+ } {
+ elimtype False.
+ replace (length nil) with (0%nat) in H by auto.
+ assert (0 <> S l)%nat.
+ apply O_S.
+ contradiction H1.
+ }
+ } {
+ destruct vs. {
+ elimtype False.
+ replace (length nil) with (0%nat) in H0 by auto.
+ assert (0 <> S l)%nat.
+ apply O_S.
+ contradiction H1.
+ } {
+ rewrite add_first_terms.
+ rewrite <- app_comm_cons.
+ rewrite <- app_comm_cons.
+ rewrite add_first_terms.
+ rewrite <- app_comm_cons.
+ rewrite IHl; f_equal.
+ assert (length (z :: us) = S (length us)) by (apply cons_length).
+ assert (S (length us) = S l) by auto.
+ auto.
+ assert (length (z0 :: vs) = S (length vs)) by (apply cons_length).
+ assert (S (length vs) = S l) by auto.
+ auto.
+ }
+ }
+ }
+ Qed.
+
+ Lemma mul_bi'_add : forall us n vs l, (length us = l) -> (length vs = l) ->
+ mul_bi' n (rev (us .+ vs)) =
+ mul_bi' n (rev us) .+ mul_bi' n (rev vs).
+ Proof.
+ induction us using rev_ind; intros. {
+ rewrite add_nil_l.
+ rewrite mul_bi'_n_nil.
+ rewrite add_nil_l; auto.
+ } {
+ destruct vs using rev_ind. {
+ rewrite add_nil_r.
+ rewrite mul_bi'_n_nil.
+ rewrite add_nil_r; auto.
+ } {
+ simpl in *.
+ simpl_list.
+ rewrite (add_app_same_length (pred l) us vs x x0); auto.
+ rewrite rev_unit.
+ rewrite mul_bi'_cons.
+ rewrite mul_bi'_cons.
+ rewrite mul_bi'_cons.
+ rewrite add_first_terms.
+ rewrite rev_length.
+ rewrite rev_length.
+ rewrite rev_length.
+ assert (length us = pred l).
+ replace l with (length (us ++ x :: nil)) by (apply H).
+ rewrite app_length; simpl; omega.
+ assert (length vs = pred l).
+ replace l with (length (vs ++ x0 :: nil)) by (apply H0).
+ rewrite app_length; simpl; omega.
+ rewrite (IHus n vs (pred l)).
+ replace (length us) with (pred l) by (apply H).
+ replace (length vs) with (pred l) by (apply H).
+ rewrite (add_same_length us vs (pred l)).
+ f_equal; ring.
+ apply H1. apply H2. apply H1. apply H2.
+ assert (length (us ++ x :: nil) = S (length us)).
+ rewrite app_length.
+ replace (length (x :: nil)) with 1%nat by auto; omega.
+ assert (S (length us) = l).
+ rewrite <- H1. apply H.
+ replace l with (S (length us)) by apply H2. auto.
+ assert (length (vs ++ x0 :: nil) = S (length vs)).
+ rewrite app_length.
+ replace (length (x0 :: nil)) with 1%nat by auto; omega.
+ assert (S (length vs) = l).
+ rewrite <- H1. apply H0.
+ replace l with (S (length vs)) by apply H2. auto.
+ }
+ }
+ Qed.
+
+ Lemma zeros_cons0 : forall n, 0 :: zeros n = zeros (S n).
+ auto.
+ Qed.
+
+ Lemma add_leading_zeros : forall n us vs,
+ (zeros n ++ us) .+ (zeros n ++ vs) = zeros n ++ (us .+ vs).
+ induction n; intros; auto.
+ rewrite <- zeros_cons0; simpl.
+ rewrite IHn; auto.
+ Qed.
+
+ Lemma rev_add_rev : forall us vs l, (length us = l) -> (length vs = l) ->
+ (rev us) .+ (rev vs) = rev (us .+ vs).
+ Proof.
+ induction us; intros. {
+ rewrite add_nil_l.
+ rewrite add_nil_l; auto.
+ } {
+ destruct vs. {
+ elimtype False.
+ replace (length nil) with 0%nat in H0 by auto.
+ rewrite cons_length in H.
+ assert (0 <> l)%nat by (rewrite <- H; apply O_S).
+ contradiction.
+ } {
+ rewrite add_first_terms.
+ simpl.
+ assert (length us = pred l).
+ rewrite cons_length in H.
+ rewrite <- H; auto.
+ assert (length vs = pred l).
+ rewrite cons_length in H0.
+ rewrite <- H0; auto.
+ rewrite (add_app_same_length (pred l) _ _ _ _); try (rewrite rev_length; auto).
+ rewrite (IHus vs (pred l)); auto.
+ }
+ }
+ Qed.
+
+ Lemma mul_bi'_length : forall us n, length (mul_bi' n us) = length us.
+ Proof.
+ induction us; intros; auto.
+ rewrite mul_bi'_cons.
+ rewrite cons_length.
+ rewrite cons_length.
+ replace (length (mul_bi' n us)) with (length us); auto.
+ Qed.
+
+ Lemma add_comm : forall us vs, us .+ vs = vs .+ us.
+ Proof.
+ induction us; intros. {
+ rewrite add_nil_l.
+ rewrite add_nil_r.
+ auto.
+ } {
+ destruct vs. {
+ rewrite add_nil_l.
+ rewrite add_nil_r; auto.
+ } {
+ rewrite add_first_terms.
+ rewrite add_first_terms.
+ rewrite IHus; f_equal; omega.
+ }
+ }
+ Qed.
+
+ Lemma mul_bi_add_same_length : forall n us vs l, (length us = l) -> (length vs = l) ->
+ mul_bi n (us .+ vs) = mul_bi n us .+ mul_bi n vs.
+ Proof.
+ intros.
+ unfold mul_bi; simpl.
+ rewrite add_leading_zeros.
+ rewrite (mul_bi'_add us n vs l); auto.
+ rewrite (rev_add_rev _ _ l).
+ rewrite add_comm; f_equal.
+ rewrite mul_bi'_length; rewrite rev_length.
+ apply H.
+ rewrite mul_bi'_length; rewrite rev_length.
+ apply H0.
+ Qed.
+
+ Lemma add_zeros_same_length : forall us, us .+ (zeros (length us)) = us.
+ Proof.
+ induction us; auto; simpl.
+ rewrite IHus; f_equal; ring.
+ Qed.
+
+ Lemma add_trailing_zeros : forall us vs, (length us >= length vs)%nat ->
+ us .+ vs = us .+ (vs ++ (zeros (length us - length vs))).
+ Proof.
+ induction us; intros. {
+ rewrite add_nil_l.
+ rewrite add_nil_l.
+ simpl in *.
+ assert (length vs = 0%nat) by omega.
+ simpl_list; auto.
+ } {
+ destruct vs. {
+ rewrite add_nil_r.
+ rewrite app_nil_l.
+ simpl.
+ f_equal; try ring.
+ symmetry.
+ apply add_zeros_same_length.
+ } {
+ rewrite add_first_terms; simpl.
+ f_equal.
+ apply IHus.
+ rewrite cons_length in H.
+ rewrite cons_length in H.
+ intuition.
+ }
+ }
+ Qed.
+
+ Lemma mul_bi_length : forall us n, length (mul_bi n us) = (length us + n)%nat.
+ Proof.
+ induction us; intros; simpl. {
+ unfold mul_bi; simpl; simpl_list.
+ apply length_zeros.
+ } {
+ unfold mul_bi; simpl; simpl_list.
+ rewrite length_zeros.
+ rewrite mul_bi'_length; simpl_list; simpl.
+ omega.
+ }
+ Qed.
+
+ Lemma mul_bi_trailing_zeros : forall m n us, mul_bi n us ++ zeros m = mul_bi n (us ++ zeros m).
+ Proof.
+ unfold mul_bi.
+ induction m; intros; simpl_list; auto.
+ rewrite <- zeros_app0.
+ rewrite app_assoc.
+ rewrite IHm; clear IHm.
+ simpl.
+ repeat (rewrite rev_app_distr).
+ simpl.
+ repeat (rewrite rev_zeros).
+ rewrite app_assoc.
+ auto.
+ Qed.
+
+ Lemma mul_bi_add_longer : forall n us vs, (length us >= length vs)%nat ->
+ mul_bi n (us .+ vs) = mul_bi n us .+ mul_bi n vs.
+ Proof.
+ intros.
+ rewrite add_trailing_zeros by auto.
+ rewrite (add_trailing_zeros (mul_bi n us) (mul_bi n vs)) by (repeat (rewrite mul_bi_length); omega).
+ erewrite mul_bi_add_same_length by (eauto; simpl_list; rewrite length_zeros; omega).
+ f_equal.
+ rewrite mul_bi_trailing_zeros.
+ repeat (rewrite mul_bi_length).
+ f_equal. f_equal. f_equal.
+ omega.
+ Qed.
+
Lemma mul_bi_add : forall n us vs,
n .* (us .+ vs) = n .* us .+ n .* vs.
Proof.
- Admitted.
+ intros.
+ destruct (le_ge_dec (length us) (length vs)). {
+ assert (length vs >= length us)%nat by auto.
+ rewrite add_comm.
+ replace (mul_bi n us .+ mul_bi n vs) with (mul_bi n vs .+ mul_bi n us) by (apply add_comm).
+ apply (mul_bi_add_longer n vs us); auto.
+ } {
+ apply mul_bi_add_longer; auto.
+ }
+ Qed.
Lemma mul_bi_rep : forall i vs,
(i + length vs < length base)%nat ->
@@ -306,11 +690,15 @@ Module BaseSystem (Import B:BaseCoefs).
Proof.
exact mul'_rep.
Qed.
+
+(* Print Assumptions mul_rep. *)
+
End BaseSystem.
Module Type PolynomialBaseParams.
Parameter b1 : positive. (* the value at which the polynomial is evaluated *)
Parameter baseLength : nat. (* 1 + degree of the polynomial *)
+ Axiom baseLengthNonzero : NPeano.ltb 0 baseLength = true.
End PolynomialBaseParams.
Module PolynomialBaseCoefs (Import P:PolynomialBaseParams) <: BaseCoefs.
@@ -318,6 +706,16 @@ Module PolynomialBaseCoefs (Import P:PolynomialBaseParams) <: BaseCoefs.
Definition bi i := (Zpos b1)^(Z.of_nat i).
Definition base := map bi (seq 0 baseLength).
+ Lemma b0_1 : nth_default 0 base 0 = 1.
+ unfold base, bi, nth_default.
+ case_eq baseLength; intros. {
+ assert ((0 < baseLength)%nat) by
+ (rewrite <-NPeano.ltb_lt; apply baseLengthNonzero).
+ subst; omega.
+ }
+ auto.
+ Qed.
+
Lemma base_positive : forall b, In b base -> b > 0.
Proof.
unfold base.
@@ -349,6 +747,9 @@ End PolynomialBaseCoefs.
Module BasePoly2Degree32Params <: PolynomialBaseParams.
Definition b1 := 2%positive.
Definition baseLength := 32%nat.
+ Lemma baseLengthNonzero : NPeano.ltb 0 baseLength = true.
+ compute; reflexivity.
+ Qed.
End BasePoly2Degree32Params.
Import ListNotations.
diff --git a/src/Galois/ModularBaseSystem.v b/src/Galois/ModularBaseSystem.v
new file mode 100644
index 000000000..de5c40f1b
--- /dev/null
+++ b/src/Galois/ModularBaseSystem.v
@@ -0,0 +1,195 @@
+Require Import Zpower ZArith.
+Require Import List.
+Require Import Crypto.Galois.BaseSystem Crypto.Galois.GaloisTheory.
+Require Import Util.ListUtil.
+Open Scope Z_scope.
+
+Module Type PseudoMersenneBaseParams (Import B:BaseCoefs) (Import M:Modulus).
+ (* TODO: do we actually want B and M "up there" in the type parameters? I was
+ * imagining writing something like "Paramter Module M : Modulus". *)
+
+ Parameter k : Z.
+ Parameter c : Z.
+ Axiom modulus_pseudomersenne : primeToZ modulus = 2^k - c.
+
+ Axiom base_matches_modulus :
+ forall i j,
+ (i < length base)%nat ->
+ (j < length base)%nat ->
+ (i+j >= length base)%nat->
+ let b := nth_default 0 base in
+ let r := (b i * b j) / (2^k * b (i+j-length base)%nat) in
+ b i * b j = r * 2^k * b (i+j-length base)%nat.
+
+ Axiom b0_1 : nth_default 0 base 1 = 1.
+
+ (* Probably implied by modulus_pseudomersenne. *)
+ Axiom k_pos : 0 <= k.
+
+End PseudoMersenneBaseParams.
+
+Module Type GFrep (Import M:Modulus).
+ Module Import GF := GaloisTheory M.
+ (* TODO: could GF notation be in Galois, not GaloisTheory *)
+ Parameter T : Type.
+ Parameter fromGF : GF -> T.
+ Parameter toGF : T -> GF.
+
+ Parameter rep : T -> GF -> Prop.
+ Local Notation "u '~=' x" := (rep u x) (at level 70).
+ Axiom fromGF_rep : forall x, fromGF x ~= x.
+ Axiom rep_toGF : forall u x, u ~= x -> toGF u = x.
+
+ Parameter add : T -> T -> T.
+ Axiom add_rep : forall u v x y, u ~= x -> v ~= y -> add u v ~= (x+y)%GF.
+
+ Parameter sub : T -> T -> T.
+ Axiom sub_rep : forall u v x y, u ~= x -> v ~= y -> sub u v ~= (x-y)%GF.
+ (* TBD: sub may need to be in BaseSystem as well *)
+
+ Parameter mul : T -> T -> T.
+ Axiom mul_rep : forall u v x y, u ~= x -> v ~= y -> mul u v ~= (x*y)%GF.
+
+ Parameter square : T -> T.
+ Axiom square_rep : forall u x, u ~= x -> square u ~= (x^2)%GF.
+ (* we will want a non-trivial implementation later, currently square x = mul x x *)
+End GFrep.
+
+Module GFPseudoMersenneBase (BC:BaseCoefs) (M:Modulus) (P:PseudoMersenneBaseParams BC M) (* TODO(jadep): "<: GFrep M" *).
+ Module Import GF := GaloisTheory M.
+ Module EC <: BaseCoefs.
+ Definition base := BC.base ++ (map (Z.mul (2^(P.k))) BC.base).
+
+ Lemma base_positive : forall b, In b base -> b > 0.
+ Proof.
+ unfold base. intros.
+ rewrite in_app_iff in H.
+ destruct H. {
+ apply BC.base_positive; auto.
+ } {
+ specialize BC.base_positive.
+ induction BC.base; intros. {
+ simpl in H; intuition.
+ } {
+ simpl in H.
+ destruct H; subst.
+ replace 0 with (2 ^ P.k * 0) by auto.
+ apply (Zmult_gt_compat_l a 0 (2 ^ P.k)).
+ rewrite Z.gt_lt_iff.
+ apply Z.pow_pos_nonneg; intuition.
+ apply P.k_pos.
+ apply H0; left; auto.
+ apply IHl; auto.
+ intros. apply H0; auto. right; auto.
+ }
+ }
+ Qed.
+
+ Lemma base_good :
+ forall i j, (i+j < length base)%nat ->
+ let b := nth_default 0 base in
+ let r := (b i * b j) / b (i+j)%nat in
+ b i * b j = r * b (i+j)%nat.
+ Admitted.
+
+ End EC.
+
+ Module E := BaseSystem EC.
+ Module B := BaseSystem BC.
+
+ (* TODO: move to ListUtil *)
+ Lemma firstn_app : forall {A} n (xs ys : list A), (n <= length xs)%nat ->
+ firstn n xs = firstn n (xs ++ ys).
+ Proof.
+ induction n; destruct xs; destruct ys; simpl_list; boring; try omega.
+ rewrite (IHn xs (a0 :: ys)) by omega; auto.
+ Qed.
+
+ Lemma decode_short : forall (us : B.digits),
+ (length us <= length BC.base)%nat -> B.decode us = E.decode us.
+ Proof.
+ intros.
+ unfold B.decode, B.decode', E.decode, E.decode'.
+ rewrite combine_truncate_r.
+ rewrite (combine_truncate_r us EC.base).
+ f_equal; f_equal.
+ unfold EC.base.
+ rewrite (firstn_app _ _ (map (Z.mul (2 ^ P.k)) BC.base)); auto.
+ Qed.
+
+
+ Lemma mul_rep_extended : forall (us vs : B.digits),
+ (length us <= length BC.base)%nat ->
+ (length vs <= length BC.base)%nat ->
+ B.decode us * B.decode vs = E.decode (E.mul us vs).
+ Proof.
+ intros.
+ rewrite E.mul_rep by (unfold EC.base; simpl_list; omega).
+ f_equal; rewrite decode_short; auto.
+ Qed.
+
+ (* Converts from length of E.base to length of B.base by reduction modulo M.*)
+ Definition reduce (us : E.digits) : B.digits :=
+ let high := skipn (length BC.base) us in
+ let low := firstn (length BC.base) us in
+ let wrap := map (Z.mul P.c) high in
+ B.add low wrap.
+
+ Lemma Prime_nonzero: forall (p : Prime), primeToZ p <> 0.
+ Proof.
+ unfold Prime. intros.
+ destruct p.
+ simpl. intro.
+ subst.
+ apply Znumtheory.not_prime_0; auto.
+ Qed.
+
+ Lemma mod_mult_plus: forall a b c, (b <> 0) -> (a * b + c) mod b = c mod b.
+ Proof.
+ intros.
+ rewrite Zplus_mod.
+ rewrite Z.mod_mul; auto; simpl.
+ rewrite Zmod_mod; auto.
+ Qed.
+
+ (* a = r + s(2^k) = r + s(2^k - c + c) = r + s(2^k - c) + cs = r + cs *)
+ Lemma pseudomersenne_add: forall x y, (x + ((2^P.k) * y)) mod modulus = (x + (P.c * y)) mod modulus.
+ Proof.
+ intros.
+ replace (2^P.k) with (((2^P.k) - P.c) + P.c) by auto.
+ rewrite Z.mul_add_distr_r.
+ rewrite Zplus_mod.
+ rewrite <- P.modulus_pseudomersenne.
+ rewrite Z.mul_comm.
+ rewrite mod_mult_plus; try apply Prime_nonzero.
+ rewrite <- Zplus_mod; auto.
+ Qed.
+
+ Lemma extended_shiftadd: forall (us : E.digits), E.decode us =
+ B.decode (firstn (length BC.base) us) +
+ (2^P.k * B.decode (skipn (length BC.base) us)).
+ Proof.
+ intros.
+ unfold B.decode, E.decode; rewrite <- B.mul_each_rep.
+ replace B.decode' with E.decode' by auto.
+ unfold EC.base.
+ replace (map (Z.mul (2 ^ P.k)) BC.base) with (E.mul_each (2 ^ P.k) BC.base) by auto.
+ rewrite E.base_mul_app.
+ rewrite <- E.mul_each_rep; auto.
+ Qed.
+
+ Lemma reduce_rep : forall us, B.decode (reduce us) mod modulus = (E.decode us) mod modulus.
+ Proof.
+ intros.
+ rewrite extended_shiftadd.
+ rewrite pseudomersenne_add.
+ unfold reduce.
+ remember (firstn (length BC.base) us) as low.
+ remember (skipn (length BC.base) us) as high.
+ unfold B.decode.
+ rewrite B.add_rep.
+ replace (map (Z.mul P.c) high) with (B.mul_each P.c high) by auto.
+ rewrite B.mul_each_rep; auto.
+ Qed.
+
+End GFPseudoMersenneBase.
diff --git a/src/Util/ListUtil.v b/src/Util/ListUtil.v
index 1eb9c5075..e8be33dac 100644
--- a/src/Util/ListUtil.v
+++ b/src/Util/ListUtil.v
@@ -2,6 +2,16 @@ Require Import List.
Require Import Omega.
Require Import Arith.Peano_dec.
+Ltac boring :=
+ simpl; intuition;
+ repeat match goal with
+ | [ H : _ |- _ ] => rewrite H; clear H
+ | _ => progress autounfold in *
+ | _ => progress try autorewrite with core
+ | _ => progress simpl in *
+ | _ => progress intuition
+ end; eauto.
+
Ltac nth_tac' :=
intros; simpl in *; unfold error,value in *; repeat progress (match goal with
| [ H: ?x = Some _ |- context[match ?x with Some _ => ?a | None => ?a end ] ] => destruct x
@@ -132,3 +142,38 @@ Proof.
induction i; destruct xs; nth_tac; right.
rewrite <- seq_shift; apply in_map; eapply IHi; eauto.
Qed.
+
+Lemma combine_truncate_r : forall {A} (xs ys : list A),
+ combine xs ys = combine xs (firstn (length xs) ys).
+Proof.
+ induction xs; destruct ys; boring.
+Qed.
+
+Lemma combine_truncate_l : forall {A} (xs ys : list A),
+ combine xs ys = combine (firstn (length ys) xs) ys.
+Proof.
+ induction xs; destruct ys; boring.
+Qed.
+
+Lemma firstn_nil : forall {A} n, firstn n nil = @nil A.
+Proof.
+ destruct n; auto.
+Qed.
+
+Lemma skipn_nil : forall {A} n, skipn n nil = @nil A.
+Proof.
+ destruct n; auto.
+Qed.
+
+Lemma firstn_app : forall A (l l': list A), firstn (length l) (l ++ l') = l.
+Proof.
+ intros.
+ induction l; simpl; auto.
+ f_equal; auto.
+Qed.
+
+Lemma skipn_app : forall A (l l': list A), skipn (length l) (l ++ l') = l'.
+Proof.
+ intros.
+ induction l; simpl; auto.
+Qed.