aboutsummaryrefslogtreecommitdiff
path: root/src/Util/AdditionChainExponentiation.v
blob: ca1394115501b3cf264f2202da371b6aa1e94d9c (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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
Require Import Coq.Lists.List Coq.Lists.SetoidList. Import ListNotations.
Require Import Crypto.Util.ListUtil.
Require Import Algebra. Import Monoid ScalarMult.
Require Import VerdiTactics.
Require Import Crypto.Util.Option.

Section AddChainExp.
  Function add_chain (is:list (nat*nat)) : list nat :=
    match is with
    | nil => nil
    | (i,j)::is' =>
      let chain' := add_chain is' in
      nth_default 1 chain' i + nth_default 1 chain' j::chain'
    end.

Example wikipedia_addition_chain : add_chain (rev [
(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 *)
) = [31; 30; 24; 12; 6; 3; 2]. reflexivity. Qed.

  Context {G eq op id} {monoid:@Algebra.monoid G eq op id}.
  Local Infix "=" := eq : type_scope.

  Function add_chain_exp (is : list (nat*nat)) (x : G) : list G :=
    match is with
    | nil => nil
    | (i,j)::is' =>
      let chain' := add_chain_exp is' x in
      op (nth_default x chain' i) (nth_default x chain' j) ::chain'
    end.

  Fixpoint scalarmult n (x : G) : G := match n with
    | O    => id
    | S n' => op x (scalarmult n' x)
    end.

  Lemma add_chain_exp_step : forall i j is x,
    (forall n, nth_default x (add_chain_exp is x) n = scalarmult (nth_default 1 (add_chain is) n) x) ->
    (eqlistA eq)
    (add_chain_exp ((i,j) :: is) x)
      (op (scalarmult (nth_default 1 (add_chain is) i) x)
         (scalarmult (nth_default 1 (add_chain is) j) x) :: add_chain_exp is x).
  Proof.
    intros.
    unfold add_chain_exp; fold add_chain_exp.
    apply eqlistA_cons; [ | reflexivity].
    f_equiv; auto.
  Qed.

  Lemma scalarmult_same : forall c x y, eq x y -> eq (scalarmult c x) (scalarmult c y).
  Proof.
    induction c; intros.
    + reflexivity.
    + simpl. f_equiv; auto.
  Qed.

  Lemma scalarmult_pow_add : forall a b x, scalarmult (a + b) x = op (scalarmult a x) (scalarmult b x).
  Proof.
    intros; eapply scalarmult_add_l.
    Grab Existential Variables.
    2:eauto.
    econstructor; try reflexivity.
    repeat intro; subst.
    auto using scalarmult_same.
  Qed.

  Lemma add_chain_exp_spec : forall is x,
    (forall n, nth_default x (add_chain_exp is x) n = scalarmult (nth_default 1 (add_chain is) n) x).
  Proof.
    induction is; intros.
    + simpl; rewrite !nth_default_nil. cbv.
      symmetry; apply right_identity.
    + destruct a.
      rewrite add_chain_exp_step by auto.
      unfold add_chain; fold add_chain.
      destruct n.
      - rewrite !nth_default_cons, scalarmult_pow_add. reflexivity.
      - rewrite !nth_default_cons_S; auto.
  Qed.

  Lemma add_chain_exp_answer : forall is x n, Logic.eq (head (add_chain is)) (Some n) ->
    option_eq eq (Some (scalarmult n x)) (head (add_chain_exp is x)).
  Proof.
    intros.
    change head with (fun {T} (xs : list T) => nth_error xs 0) in *.
    cbv beta in *.
    cbv [option_eq].
    destruct is; [ discriminate | ].
    destruct p.
    simpl in *.
    injection H; clear H; intro H.
    subst n.
    rewrite !add_chain_exp_spec.
    apply scalarmult_pow_add.
  Qed.

End AddChainExp.