aboutsummaryrefslogtreecommitdiff
path: root/src/Util/AdditionChainExponentiation.v
blob: f35c4e9ea8b7bdb7dd135335d678e1f09932a8f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Require Import Coq.Lists.List Coq.Lists.SetoidList. Import ListNotations.
Require Import Coq.Numbers.BinNums Coq.NArith.BinNat.
Require Import Crypto.Util.ListUtil.
Require Import Crypto.Algebra.Monoid Crypto.Algebra.ScalarMult.
Require Import Crypto.Util.Option.
Require Import Crypto.Util.Tactics.BreakMatch.

Section AddChainExp.
  Function fold_chain {T} (id:T) (op:T->T->T) (is:list (nat*nat)) (acc:list T) {struct is} : T :=
    match is with
    | nil =>
      match acc with
      | nil => id
      | ret::_ => ret
      end
    | (i,j)::is' =>
      let ijx := op (nth_default id acc i) (nth_default id acc j) in
      fold_chain id op is' (ijx::acc)
    end.

  Example wikipedia_addition_chain : fold_chain 0 plus [
  (0, 0); (* 2 = 1 + 1 *) (* the indices say how far back the chain to look *)
  (0, 1); (* 3 = 2 + 1 *)
  (0, 0); (* 6 = 3 + 3 *)
  (0, 0); (* 12 = 6 + 6 *)
  (0, 0); (* 24 = 12 + 12 *)
  (0, 2); (* 30 = 24 + 6 *)
  (0, 6)] (* 31 = 30 + 1 *)
  [1] = 31. reflexivity. Qed.

  Context {G eq op id} {monoid:@Algebra.Hierarchy.monoid G eq op id}.
  Context {scalarmult} {is_scalarmult:@ScalarMult.is_scalarmult G eq op id scalarmult}.
  Local Infix "=" := eq : type_scope.
  Local Open Scope N_scope.
  Local Notation "n * P" := (scalarmult (N.to_nat n) P) (only parsing).

  Lemma fold_chain_exp' : forall (x:G) is acc ref
      (H:forall i, nth_default id acc i = (nth_default 0 ref i) * x)
      (Hl:Logic.eq (length acc) (length ref)),
      fold_chain id op is acc = (fold_chain 0 N.add is ref) * x.
  Proof using Type*.
    intro x; induction is; intros acc ref H Hl; simpl @fold_chain.
    { repeat break_match; specialize (H 0%nat); rewrite ?nth_default_cons, ?nth_default_cons_S in H;
      solve [ simpl length in *; discriminate | apply H | rewrite scalarmult_0_l; reflexivity ]. }
    { repeat break_match. eapply IHis; intros; [|auto with distr_length]; [].
      match goal with
          [H:context [nth_default _ ?l _] |- context[nth_default _ (?h::?l) ?i] ]
          => destruct i; rewrite ?nth_default_cons, ?nth_default_cons_S;
             solve [ apply H | rewrite !H, <-scalarmult_add_l, Nnat.N2Nat.inj_add; reflexivity ]
        end. }
  Qed.

  Lemma fold_chain_exp x is: fold_chain id op is [x] = (fold_chain 0 N.add is [1]) * x.
  Proof using Type*.
    eapply fold_chain_exp'; trivial; intros i.
    destruct i as [|i]; try destruct i; rewrite ?nth_default_cons_S, ?nth_default_cons, ?nth_default_nil;
      rewrite ?scalarmult_1_l, ?scalarmult_0_l; reflexivity.
  Qed.
End AddChainExp.