Skip to content

Commit 4cd8fc2

Browse files
authoredApr 1, 2024··
merge Group.Scalarmult into MontgomeryLadder, use in x25519_base (#1843)
1 parent 9378552 commit 4cd8fc2

14 files changed

+302
-679
lines changed
 

‎src/Bedrock/End2End/X25519/Field25519.v

+3-11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
Require Import Crypto.Spec.Curve25519.
12
Require Import Coq.Strings.String. Local Open Scope string_scope.
23
Require Import Coq.Lists.List.
34
Require Import Coq.ZArith.ZArith.
@@ -38,17 +39,8 @@ Section Field.
3839
Instance translation_parameters_ok : Types.ok.
3940
Proof using ext_spec_ok. constructor; try exact _; apply prefix_name_gen_unique. Qed.
4041

41-
(* Define Curve25519 field *)
42-
Instance field_parameters : FieldParameters.
43-
Proof using Type.
44-
let M := (eval vm_compute in (Z.to_pos (UnsaturatedSolinas.m s c))) in
45-
(* curve 'A' parameter *)
46-
let a := constr:(F.of_Z M 486662) in
47-
let prefix := constr:("fe25519_"%string) in
48-
eapply
49-
(field_parameters_prefixed
50-
M ((a - F.of_Z _ 2) / F.of_Z _ 4)%F prefix).
51-
Defined.
42+
Instance field_parameters : FieldParameters :=
43+
field_parameters_prefixed Curve25519.p Curve25519.M.a24 "fe25519_"%string.
5244

5345
(* Call fiat-crypto pipeline on all field operations *)
5446
Instance fe25519_ops : unsaturated_solinas_ops (ext_spec:=ext_spec) n s c.

‎src/Bedrock/End2End/X25519/GarageDoor.v

+20-5
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,25 @@ Local Open Scope string_scope.
4040
Import Syntax Syntax.Coercions NotationsCustomEntry.
4141
Import ListNotations.
4242
Import Coq.Init.Byte.
43+
Import Tuple LittleEndianList.
44+
Local Coercion F.to_Z : F >-> Z.
4345

4446
Definition garageowner : list byte :=
4547
[x7b; x06; x18; x0c; x54; x0c; xca; x9f; xa3; x16; x0b; x2f; x2b; x69; x89; x63; x77; x4c; xc1; xef; xdc; x04; x91; x46; x76; x8b; xb2; xbf; x43; x0e; x34; x34].
4648

49+
Definition garageowner_P : Curve25519.M.point.
50+
refine (
51+
let x := F.of_Z _ (le_combine garageowner) in
52+
let y2 := (x*x*x + Curve25519.M.a*x*x +x)%F in
53+
let sqrtm1 := (F.pow (F.of_Z _ 2) ((N.pos p-1)/4)) in
54+
let y := F.sqrt_5mod8 sqrtm1 y2 in
55+
exist _ (inl (x, y)) _).
56+
Decidable.vm_decide.
57+
Defined.
58+
59+
Lemma garageowner_P_correct : le_split 32 (Curve25519.M.X0 garageowner_P) = garageowner.
60+
Proof. vm_compute. reflexivity. Qed.
61+
4762
Local Notation ST := 0x80000000.
4863
Local Notation PK := 0x80000040.
4964
Local Notation BUF:= 0x80000060.
@@ -164,7 +179,6 @@ Qed.
164179

165180
Local Open Scope list_scope.
166181
Require Crypto.Bedrock.End2End.RupicolaCrypto.Spec.
167-
Import Tuple LittleEndianList.
168182
Local Definition be2 z := rev (le_split 2 z).
169183
Local Coercion to_list : tuple >-> list.
170184
Local Coercion Z.b2z : bool >-> Z.
@@ -200,7 +214,7 @@ Definition garagedoor_iteration : state -> list (lightbulb_spec.OP _) -> state -
200214
(TracePredicate.one ("st", lightbulb_spec.GPIO_DATA_ADDR _, action))) ioh
201215
/\ (
202216
let m := firstn 16 garagedoor_payload in
203-
let v := le_split 32 (F.to_Z (x25519_gallina (le_combine sk) (Field.feval_bytes(FieldRepresentation:=frep25519) garageowner))) in
217+
let v := le_split 32 (M.X0 (Curve25519.M.scalarmult (le_combine sk mod 2^255) garageowner_P)) in
204218
exists set0 set1 : Naive.word32,
205219
(word.unsigned set0 = 1 <-> firstn 16 v = m) /\
206220
(word.unsigned set1 = 1 <-> skipn 16 v = m) /\
@@ -220,7 +234,7 @@ Definition garagedoor_iteration : state -> list (lightbulb_spec.OP _) -> state -
220234
udp_local ++ udp_remote ++
221235
be2 udp_length ++ be2 0 ++
222236
garagedoor_header ++
223-
le_split 32 (F.to_Z (x25519_gallina (le_combine sk) (F.of_Z _ 9)))))
237+
le_split 32 (M.X0 (Curve25519.M.scalarmult (le_combine sk mod 2^255) Curve25519.M.B))))
224238
ioh /\ SEED=seed /\ SK=sk.
225239

226240
Local Instance spec_of_recvEthernet : spec_of "recvEthernet" := spec_of_recvEthernet.
@@ -363,6 +377,7 @@ Proof.
363377
repeat straightline.
364378
straightline_call; ssplit; try ecancel_assumption; try trivial; try ZnWords.
365379
{ cbv. inversion 1. }
380+
{ instantiate (1:=garageowner_P). Decidable.vm_decide. }
366381

367382
rename Lppp into Lihl; assert (List.length ppp = 40)%nat as Lppp by ZnWords.
368383

@@ -387,7 +402,7 @@ Proof.
387402
subst pPPP.
388403
seprewrite_in_by (Array.bytearray_append cmp1) H33 SepAutoArray.listZnWords.
389404

390-
set (k := (Field.feval_bytes _)); remember (le_split 32 (F.to_Z (x25519_gallina (le_combine sk) k))) as vv; subst k.
405+
remember (le_split 32 (M.X0 (Curve25519.M.scalarmult (le_combine sk mod 2^255) garageowner_P))) as vv.
391406
repeat straightline.
392407
pose proof (List.firstn_skipn 16 vv) as Hvv.
393408
pose proof (@firstn_length_le _ vv 16 ltac:(subst vv; rewrite ?length_le_split; ZnWords)).
@@ -852,7 +867,7 @@ Optimize Proof. Optimize Heap.
852867
{ rewrite ?app_length, ?length_le_split. SepAutoArray.listZnWords. }
853868
{ ZnWords. }
854869

855-
pose proof length_le_split 32 (F.to_Z (x25519_gallina (le_combine sk) (F.of_Z _ 9))) as Hpkl.
870+
pose proof length_le_split 32 (F.to_Z (M.X0 (Curve25519.M.scalarmult (le_combine sk mod 2^255) Curve25519.M.B))) as Hpkl.
856871
seprewrite_in_by (fun xs ys=>@bytearray_address_merge _ _ _ _ _ xs ys buf) H37 SepAutoArray.listZnWords.
857872
seprewrite_in_by (fun xs ys=>@bytearray_address_merge _ _ _ _ _ xs ys buf) H37 SepAutoArray.listZnWords.
858873

‎src/Bedrock/End2End/X25519/GarageDoorTop.v

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ Require Import bedrock2Examples.memswap.
2424
Require Import bedrock2Examples.memconst.
2525
Require Import Rupicola.Examples.Net.IPChecksum.IPChecksum.
2626
Require Import Crypto.Bedrock.End2End.X25519.GarageDoor.
27-
Require Import Crypto.Bedrock.End2End.X25519.MontgomeryLadderProperties.
2827
Import Crypto.Bedrock.End2End.RupicolaCrypto.ChaCha20.
2928
Local Open Scope string_scope.
3029
Import Syntax Syntax.Coercions NotationsCustomEntry.

‎src/Bedrock/End2End/X25519/MontgomeryLadder.v

+60-52
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
Require Import Coq.Strings.String.
22
Require Import Coq.Lists.List.
33
Require Import Coq.ZArith.ZArith.
4+
Require Import Crypto.Util.Decidable.
5+
Require Import Crypto.Spec.MontgomeryCurve.
46
Require Import Crypto.Spec.Curve25519.
57
Require Import bedrock2.Map.Separation.
68
Require Import bedrock2.Syntax.
@@ -53,25 +55,29 @@ Require Import coqutil.Map.OfListWord Coq.Init.Byte coqutil.Byte.
5355
Import ProgramLogic.Coercions.
5456
Local Notation "m =* P" := ((P%sep) m) (at level 70, only parsing) (* experiment*).
5557
Local Notation "xs $@ a" := (Array.array ptsto (word.of_Z 1) a xs) (at level 10, format "xs $@ a").
56-
Definition x25519_gallina K U : F (2^255-19) :=
57-
@XZ.M.montladder _ F.zero F.one F.add F.sub F.mul F.inv (F.div (F.of_Z _ 486662 - F.of_Z _ 2) (F.of_Z _ 4))
58-
(Z.to_nat (Z.log2 (Z.pos order))) (Z.testbit K) U.
58+
5959
Global Instance spec_of_x25519 : spec_of "x25519" :=
60-
fnspec! "x25519" out sk pk / (o s p : list Byte.byte) (R : _ -> Prop),
60+
fnspec! "x25519" out sk pk / (o s p : list Byte.byte) P (R : _ -> Prop),
6161
{ requires t m := m =* s$@sk * p$@pk * o$@out * R /\
62-
length s = 32%nat /\ length p = 32%nat /\ length o = 32%nat /\ byte.unsigned (nth 31 p x00) <= 0x7f;
62+
length s = 32%nat /\ length p = 32%nat /\ length o = 32%nat /\
63+
byte.unsigned (nth 31 p x00) <= 0x7f /\ Field.feval_bytes(field_parameters:=field_parameters) p = Curve25519.M.X0 P;
6364
ensures t' m := t=t' /\ m=* s$@sk ⋆ p$@pk ⋆ R ⋆
64-
(le_split 32 (x25519_gallina (le_combine s) (Field.feval_bytes p)))$@out }.
65+
(le_split 32 (M.X0 (Curve25519.M.scalarmult (le_combine s mod 2^255) P))$@out) }.
6566

6667
Local Instance spec_of_fe25519_from_word : spec_of "fe25519_from_word" := Field.spec_of_from_word.
6768
Local Instance spec_of_fe25519_from_bytes : spec_of "fe25519_from_bytes" := Field.spec_of_from_bytes.
6869
Local Instance spec_of_fe25519_to_bytes : spec_of "fe25519_to_bytes" := Field.spec_of_to_bytes.
69-
Local Instance spec_of_montladder : spec_of "montladder" := spec_of_montladder(Z.to_nat (Z.log2 Curve25519.order)).
70+
Local Instance spec_of_montladder : spec_of "montladder" :=
71+
spec_of_montladder
72+
(Z.to_nat (Z.log2 Curve25519.order))
73+
Crypto.Spec.Curve25519.field
74+
Curve25519.M.a Curve25519.M.b Curve25519.M.b_nonzero (char_ge_3:=Curve25519.char_ge_3).
7075

7176
Local Arguments word.rep : simpl never.
7277
Local Arguments word.wrap : simpl never.
7378
Local Arguments word.unsigned : simpl never.
7479
Local Arguments word.of_Z : simpl never.
80+
7581
Lemma x25519_ok : program_logic_goal_for_function! x25519.
7682
Proof.
7783
repeat straightline.
@@ -94,10 +100,10 @@ Proof.
94100
eapply byte.unsigned_range. }
95101
repeat straightline.
96102

97-
seprewrite_in (@Bignum.Bignum_of_bytes _ _ _ _ _ _ 10 a2) H15. { transitivity 40%nat; trivial. }
103+
seprewrite_in (@Bignum.Bignum_of_bytes _ _ _ _ _ _ 10 a2) H16. { transitivity 40%nat; trivial. }
98104

99105
straightline_call; ssplit.
100-
3: { unfold FElem, Field.FElem in *; extract_ex1_and_emp_in_goal; ssplit.
106+
{ unfold FElem, Field.FElem in *; extract_ex1_and_emp_in_goal; ssplit.
101107
{ use_sep_assumption. cancel; repeat ecancel_step.
102108
cancel_seps_at_indices 0%nat 0%nat; trivial. cbn; reflexivity. }
103109
all : eauto.
@@ -106,7 +112,7 @@ Proof.
106112
{ rewrite H3. vm_compute. inversion 1. }
107113
repeat straightline.
108114

109-
cbv [FElem] in H22. extract_ex1_and_emp_in H22.
115+
specialize (H23 P ltac:(assumption)). cbv [FElem] in H23. extract_ex1_and_emp_in H23.
110116
straightline_call; ssplit.
111117
{ ecancel_assumption. }
112118
{ transitivity 32%nat; auto. }
@@ -116,21 +122,20 @@ Proof.
116122
repeat straightline.
117123

118124
cbv [Field.FElem] in *.
119-
seprewrite_in @Bignum.Bignum_to_bytes H25.
120-
seprewrite_in @Bignum.Bignum_to_bytes H25.
121-
extract_ex1_and_emp_in H25.
125+
seprewrite_in @Bignum.Bignum_to_bytes H26.
126+
seprewrite_in @Bignum.Bignum_to_bytes H26.
127+
extract_ex1_and_emp_in H26.
122128

123129
repeat straightline; intuition eauto.
124-
rewrite H29 in *. cbv [x25519_gallina].
125-
use_sep_assumption; cancel. eapply RelationClasses.reflexivity.
130+
rewrite H30 in *.
131+
use_sep_assumption; cancel. reflexivity.
126132
Qed.
127133

128134
Global Instance spec_of_x25519_base : spec_of "x25519_base" :=
129135
fnspec! "x25519_base" out sk / (o s : list Byte.byte) (R : _ -> Prop),
130-
{ requires t m := m =* s$@sk * o$@out * R /\
131-
length s = 32%nat /\ length o = 32%nat;
136+
{ requires t m := m =* s$@sk * o$@out * R /\ length s = 32%nat /\ length o = 32%nat;
132137
ensures t' m := t=t' /\ m=* s$@sk ⋆ R ⋆
133-
(le_split 32 (x25519_gallina (le_combine s) (F.of_Z _ 9)))$@out }.
138+
le_split 32 (M.X0 (Curve25519.M.scalarmult (le_combine s mod 2^255) Curve25519.M.B))$@out }.
134139

135140
Lemma x25519_base_ok : program_logic_goal_for_function! x25519_base.
136141
Proof.
@@ -143,7 +148,7 @@ Proof.
143148
seprewrite_in (@Bignum.Bignum_of_bytes _ _ _ _ _ _ 10 a2) H13. { transitivity 40%nat; trivial. }
144149

145150
straightline_call; ssplit.
146-
3: { unfold FElem, Field.FElem in *; extract_ex1_and_emp_in_goal; ssplit.
151+
{ unfold FElem, Field.FElem in *; extract_ex1_and_emp_in_goal; ssplit.
147152
{ use_sep_assumption. cancel; repeat ecancel_step.
148153
cancel_seps_at_indices 0%nat 0%nat; trivial. cbn; reflexivity. }
149154
all : eauto.
@@ -152,6 +157,7 @@ Proof.
152157
{ rewrite H3. vm_compute. inversion 1. }
153158
repeat straightline.
154159

160+
specialize (H20 Curve25519.M.B eq_refl).
155161
unfold FElem in H20. extract_ex1_and_emp_in H20.
156162
straightline_call; ssplit.
157163
{ ecancel_assumption. }
@@ -167,8 +173,8 @@ Proof.
167173
extract_ex1_and_emp_in H23.
168174

169175
repeat straightline; intuition eauto.
170-
rewrite H27 in *. cbv [x25519_gallina].
171-
use_sep_assumption; cancel. eapply RelationClasses.reflexivity.
176+
rewrite H27 in *.
177+
use_sep_assumption; cancel. reflexivity.
172178
Qed.
173179

174180
Require Import coqutil.Word.Naive.
@@ -196,36 +202,38 @@ Definition funcs :=
196202
Require Import bedrock2.ToCString.
197203
Definition montladder_c_module := list_byte_of_string (ToCString.c_module funcs).
198204

199-
#[export]
200-
Instance BWM_RV32IM : FlatToRiscvCommon.bitwidth_iset 32 Decode.RV32IM := eq_refl.
201-
202-
Derive montladder_compiler_result SuchThat
203-
(compile
204-
(compile_ext_call (funname_env:=SortedListString.map))
205-
funcs = Success montladder_compiler_result)
206-
As montladder_compiler_result_ok.
205+
Lemma link_montladder : spec_of_montladder (map.of_list funcs).
207206
Proof.
208-
match goal with x := _ |- _ => cbv delta [x]; clear x end.
209-
match goal with |- ?a = _ => set a end.
210-
vm_compute.
211-
match goal with |- @Success ?A ?x = Success ?e => is_evar e;
212-
exact (@eq_refl (result A) (@Success A x)) end.
207+
unfold spec_of_montladder, ScalarMult.MontgomeryLadder.spec_of_montladder.
208+
unfold funcs.
209+
(* use montladder correctness proof *)
210+
rewrite montladder_defn.
211+
eapply @montladder_correct; try (typeclasses eauto).
212+
{ reflexivity. }
213+
{ Decidable.vm_decide. }
214+
{ Decidable.vm_decide. }
215+
{ Decidable.vm_decide. }
216+
{ eapply M.a2m4_nonsq. }
217+
{ exact I. }
218+
{ reflexivity. }
219+
{ eapply CSwap.cswap_body_correct; [|exact I|reflexivity].
220+
unfold field_representation, Signature.field_representation, Representation.frep; cbn; unfold n; cbv; trivial. }
221+
{ eapply fe25519_copy_correct. reflexivity. }
222+
{ eapply fe25519_from_word_correct. reflexivity. }
223+
{
224+
cbv [LadderStep.spec_of_ladderstep]; intros.
225+
rewrite ladderstep_defn.
226+
eapply @LadderStep.ladderstep_correct; try (typeclasses eauto).
227+
{ cbv [Core.__rupicola_program_marker]; tauto. }
228+
{ reflexivity. }
229+
{ apply fe25519_mul_correct. reflexivity. }
230+
{ apply fe25519_add_correct. reflexivity. }
231+
{ apply fe25519_sub_correct. reflexivity. }
232+
{ apply fe25519_square_correct. reflexivity. }
233+
{ apply fe25519_scmula24_correct. reflexivity. }
234+
{ ecancel_assumption. } }
235+
{ unshelve eapply AdditionChains.fe25519_inv_correct_exp; [exact I|reflexivity| | ].
236+
{ apply fe25519_square_correct. reflexivity. }
237+
{ apply fe25519_mul_correct. reflexivity. } }
238+
{ apply fe25519_mul_correct. reflexivity. }
213239
Qed.
214-
215-
Definition montladder_stack_size := snd montladder_compiler_result.
216-
Definition montladder_finfo := snd (fst montladder_compiler_result).
217-
Definition montladder_insns := fst (fst montladder_compiler_result).
218-
Definition montladder_bytes := Pipeline.instrencode montladder_insns.
219-
Definition montladder_symbols : list byte := Symbols.symbols montladder_finfo.
220-
221-
222-
Require riscv.Utility.InstructionNotations.
223-
Require riscv.Utility.InstructionCoercions.
224-
Module PrintAssembly.
225-
Import riscv.Utility.InstructionNotations.
226-
Import riscv.Utility.InstructionCoercions.
227-
Unset Printing Coercions.
228-
229-
(* Compute garagedoor_finfo. (* fe25519_mul is more than 10KB in just one function *) *)
230-
Goal True. let r := eval cbv in montladder_insns in idtac (* r *). Abort.
231-
End PrintAssembly.

‎src/Bedrock/End2End/X25519/MontgomeryLadderProperties.v

-182
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
Require Import Coq.ZArith.ZArith.
2+
Require Import bedrock2.Map.Separation.
3+
Require Import bedrock2.Map.SeparationLogic.
4+
Require Import bedrock2.Syntax.
5+
Require Import compiler.Pipeline.
6+
Require Import compiler.MMIO.
7+
Require Import compiler.NaiveRiscvWordProperties.
8+
Require Import coqutil.Map.SortedListWord.
9+
Require Import coqutil.Map.Z_keyed_SortedListMap.
10+
Require Import coqutil.Word.Bitwidth32.
11+
Require Import Crypto.Arithmetic.PrimeFieldTheorems.
12+
Require Import Crypto.Bedrock.End2End.X25519.Field25519.
13+
Require Import Crypto.Bedrock.Field.Synthesis.New.UnsaturatedSolinas.
14+
Require Import Crypto.Bedrock.Specs.Field.
15+
Require Import Crypto.Bedrock.Field.Interface.Compilation2.
16+
Require Import Crypto.Bedrock.Group.ScalarMult.MontgomeryLadder.
17+
Require Import Crypto.Bedrock.End2End.X25519.MontgomeryLadder.
18+
19+
Local Arguments map.rep: clear implicits.
20+
21+
#[export]
22+
Instance BWM_RV32IM : FlatToRiscvCommon.bitwidth_iset 32 Decode.RV32IM := eq_refl.
23+
24+
Derive montladder_compiler_result SuchThat
25+
(compile
26+
(compile_ext_call (funname_env:=SortedListString.map))
27+
funcs = Success montladder_compiler_result)
28+
As montladder_compiler_result_ok.
29+
Proof.
30+
match goal with x := _ |- _ => cbv delta [x]; clear x end.
31+
match goal with |- ?a = _ => set a end.
32+
vm_compute.
33+
match goal with |- @Success ?A ?x = Success ?e => is_evar e;
34+
exact (@eq_refl (result A) (@Success A x)) end.
35+
Qed.
36+
37+
Definition montladder_stack_size := snd montladder_compiler_result.
38+
Definition montladder_finfo := snd (fst montladder_compiler_result).
39+
Definition montladder_insns := fst (fst montladder_compiler_result).
40+
Definition montladder_bytes := Pipeline.instrencode montladder_insns.
41+
Definition montladder_symbols : list _ := Symbols.symbols montladder_finfo.
42+
43+
Require riscv.Utility.InstructionNotations.
44+
Require riscv.Utility.InstructionCoercions.
45+
Module PrintAssembly.
46+
Import riscv.Utility.InstructionNotations.
47+
Import riscv.Utility.InstructionCoercions.
48+
Unset Printing Coercions.
49+
50+
(* Compute garagedoor_finfo. (* fe25519_mul is more than 10KB in just one function *) *)
51+
Goal True. let r := eval cbv in montladder_insns in idtac (* r *). Abort.
52+
End PrintAssembly.
53+
54+
Definition f_rel_pos : Z := ltac:(
55+
let y := eval vm_compute in (List.find (fun '(name, pos) => String.eqb name "montladder") montladder_finfo) in
56+
match y with Some (_, ?pos) => exact pos end).
57+
58+
Local Instance mem : map.map (word.rep (width:=32)) Init.Byte.byte := SortedListWord.map _ _.
59+
Local Existing Instance BW32.

‎src/Bedrock/Group/AdditionChains.v

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
Require Crypto.Spec.Curve25519.
12
Require Import Rupicola.Lib.Api.
23
Require Import Rupicola.Lib.Loops.
34
Require Import Rupicola.Lib.ControlFlow.DownTo.
@@ -457,9 +458,6 @@ Section FElems.
457458
compile.
458459
Qed.
459460

460-
Print Assumptions exp_6_body. (* does not depend on [width] or [word] *)
461-
Print Assumptions exp_97_body. (* depends on [width] and [word] :/ *)
462-
463461
Derive fe25519_inv SuchThat
464462
(defn! "fe25519_inv" ("res", "x") { fe25519_inv },
465463
implements (exp (2^255-21)) using [square; mul])
@@ -469,7 +467,6 @@ Section FElems.
469467
Qed.
470468

471469
Context { F_M_pos : Z.pos M_pos = 2^255-19 }.
472-
Require Import Crypto.Spec.Curve25519.
473470

474471
Lemma compile_inv : forall m l tr functions x,
475472
let v := F.inv x in

‎src/Bedrock/Group/ScalarMult/MontgomeryLadder.v

+67-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
Require Crypto.Bedrock.Group.Loops.
22
Require Import Crypto.Curves.Montgomery.XZ.
3+
Require Import Crypto.Curves.Montgomery.XZProofs.
34
Require Import Rupicola.Lib.Api.
45
Require Import Rupicola.Lib.Alloc.
56
Require Import Rupicola.Lib.SepLocals.
@@ -45,7 +46,7 @@ Notation "'let/n' ( v , w , x , y , z ) := val 'in' body" :=
4546

4647
Section Gallina.
4748
Local Open Scope F_scope.
48-
Context (m : positive) (a24 : F m) (count : nat).
49+
Context {m : positive} (a24 : F m) (count : nat).
4950
Definition montladder_gallina (k : Z) (u : F m)
5051
: F m :=
5152
let/n X1 := stack 1 in
@@ -128,6 +129,32 @@ Section Gallina.
128129
cbn [fst snd to_pair] in Heqp0; inversion_clear Heqp0; trivial. }
129130
{ reflexivity. }
130131
Qed.
132+
133+
Context
134+
(field : @Hierarchy.field (F m) eq F.zero F.one F.opp F.add F.sub F.mul F.inv F.div)
135+
(Hm' : (28 <= m)%positive)
136+
a (a24_correct : (1 + 1 + 1 + 1) * a24 = a - (1 + 1))
137+
(a2m4_nonsq : ~(exists r, F.mul r r = F.sub (F.mul a a) (F.of_Z _ 4)))
138+
(b : F m) (b_nonzero : b <> 0).
139+
140+
Local Instance char_ge_28 : @Ring.char_ge (F m) eq 0 1 F.opp F.add F.sub F.mul 28.
141+
Proof. eapply Algebra.Hierarchy.char_ge_weaken; try eapply F.char_gt; trivial. Qed.
142+
143+
Context {char_ge_3 : @Ring.char_ge (F m) eq 0 1 F.opp F.add F.sub F.mul 3}. (* appears in statement *)
144+
Import MontgomeryCurve Montgomery.Affine.
145+
Local Notation X0 := (@M.X0 _ eq F.zero F.add F.mul a b).
146+
Local Notation add := (M.add(field:=field)(char_ge_3:=char_ge_3)(a:=a)(b_nonzero:=b_nonzero)).
147+
Local Notation opp := (M.opp(field:=field)(a:=a)(b_nonzero:=b_nonzero)).
148+
Local Notation scalarmult := (@ScalarMult.scalarmult_ref _ add M.zero opp).
149+
Add Ring Private_ring : (F.ring_theory m) (morphism (F.ring_morph m), constants [F.is_constant]).
150+
151+
Lemma montladder_gallina_equiv_affine n P :
152+
montladder_gallina n (X0 P) = X0 (scalarmult (n mod 2^Z.of_nat count) P).
153+
Proof.
154+
unshelve erewrite montladder_gallina_equiv, M.montladder_correct;
155+
try lia; try exact _; trivial using F.inv_0.
156+
{ intros r Hr. apply a2m4_nonsq; exists r. rewrite Hr. f_equal. ring. }
157+
Qed.
131158
End Gallina.
132159

133160
Section __.
@@ -146,21 +173,33 @@ Section __.
146173
Section MontLadder.
147174
Context scalarbits (scalarbits_small : word.wrap (Z.of_nat scalarbits) = Z.of_nat scalarbits).
148175
Local Notation "bs $@ a" := (array ptsto (word.of_Z 1) a bs) (at level 20).
149-
176+
Let m : positive := M_pos.
177+
Context
178+
(field : @Hierarchy.field (F m) eq F.zero F.one F.opp F.add F.sub F.mul F.inv F.div) (Hm' : (28 <= m)%positive)
179+
(a : F m) (b : F m) (b_nonzero : b <> F.zero).
180+
181+
Context {char_ge_3 : @Ring.char_ge (F m) eq F.zero F.one F.opp F.add F.sub F.mul 3}. (* appears in statement *)
182+
Import MontgomeryCurve Montgomery.Affine.
183+
Local Notation X0 := (@M.X0 _ eq F.zero F.add F.mul a b).
184+
Local Notation add := (M.add(field:=field)(char_ge_3:=char_ge_3)(a:=a)(b_nonzero:=b_nonzero)).
185+
Local Notation opp := (M.opp(field:=field)(a:=a)(b_nonzero:=b_nonzero)).
186+
Local Notation scalarmult := (@ScalarMult.scalarmult_ref _ add M.zero opp).
187+
188+
Import MontgomeryCurve.
150189
Instance spec_of_montladder : spec_of "montladder" :=
151190
fnspec! "montladder"
152191
(pOUT pK pU : word)
153192
/ Kbytes (K : Z) (U : F M_pos) (* inputs *)
154193
out_bound OUT
155194
R,
156195
{ requires tr mem :=
196+
mem =* FElem out_bound pOUT OUT * Kbytes$@pK * FElem (Some tight_bounds) pU U * R /\
157197
LittleEndianList.le_combine Kbytes = K /\
158-
Z.of_nat scalarbits <= 8*Z.of_nat (length Kbytes) /\
159-
(FElem out_bound pOUT OUT * Kbytes$@pK * FElem (Some tight_bounds) pU U
160-
* R)%sep mem;
198+
Z.of_nat scalarbits <= 8*Z.of_nat (length Kbytes);
161199
ensures tr' mem' :=
162-
tr' = tr
163-
/\ (let OUT := @M.montladder _ F.zero F.one F.add F.sub F.mul F.inv a24 (Z.of_nat scalarbits) (Z.testbit K) U in
200+
tr' = tr /\ (
201+
forall P, U = MontgomeryCurve.M.X0 (Fzero:=F.zero) P ->
202+
let OUT := MontgomeryCurve.M.X0 (Fzero:=F.zero) (scalarmult (K mod 2^Z.of_nat scalarbits) P) in
164203
(FElem (Some tight_bounds) pOUT OUT * Kbytes$@pK
165204
* FElem (Some tight_bounds) pU U
166205
* R)%sep mem') }.
@@ -204,6 +243,7 @@ Section __.
204243
bedrock_cmd:($out_var = (load1($x_var+$i_var>>coq:(3))>>($i_var&coq:(7)))&coq:(1); coq:(k_impl))
205244
<{ pred (nlet_eq [out_var] v k) }>.
206245
Proof using mem_ok scalarbits word_ok.
246+
clear dependent m.
207247
repeat straightline.
208248
repeat (eexists; split; repeat straightline'; eauto); cbn [Semantics.interp_binop].
209249

@@ -255,15 +295,16 @@ Section __.
255295
Existing Instance felem_alloc.
256296

257297

258-
Lemma cswap_same {A} b (a : A): cswap b a a = \<a,a\>.
298+
Lemma cswap_same {A} : forall b (a : A), cswap b a a = \<a,a\>.
259299
Proof using Type.
260-
destruct b; reflexivity.
300+
intros b0; destruct b0; reflexivity.
261301
Qed.
262302

263303
Local Ltac ecancel_assumption ::= ecancel_assumption_impl.
264304

265305
Lemma scalarbits_bound : Z.of_nat scalarbits < 2 ^ width.
266306
Proof using scalarbits_small.
307+
clear dependent m.
267308
rewrite <- scalarbits_small.
268309
unfold word.wrap.
269310
apply Z_mod_lt.
@@ -309,23 +350,23 @@ Section __.
309350
simple eapply word_unsigned_of_Z_eq; [ ZnWords |] : compiler.
310351

311352
(*TODO: should this go in core rupicola?*)
312-
Lemma compile_copy_bool {tr m l functions} (x: bool) :
353+
Lemma compile_copy_bool {tr _m l functions} (x: bool) :
313354
let v := x in
314355
forall P (pred: P v -> predicate)
315356
(k: nlet_eq_k P v) k_impl
316357
x_expr var,
317358

318-
WeakestPrecondition.dexpr m l x_expr (word.of_Z (Z.b2z v)) ->
359+
WeakestPrecondition.dexpr _m l x_expr (word.of_Z (Z.b2z v)) ->
319360

320361
(let v := v in
321362
<{ Trace := tr;
322-
Memory := m;
363+
Memory := _m;
323364
Locals := map.put l var (word.of_Z (Z.b2z v));
324365
Functions := functions }>
325366
k_impl
326367
<{ pred (k v eq_refl) }>) ->
327368
<{ Trace := tr;
328-
Memory := m;
369+
Memory := _m;
329370
Locals := l;
330371
Functions := functions }>
331372
cmd.seq (cmd.set var x_expr) k_impl
@@ -356,31 +397,39 @@ Section __.
356397
| cons _ ?xs => let i := find_implication xs y in constr:(S i)
357398
end.
358399

359-
Context { F_M_pos : Z.pos M_pos = 2^255-19 }.
400+
Context { F_M_pos : M_pos = (2^255-19)%positive }.
401+
Context (a24_correct : F.mul (1 + 1 + 1 + 1) Field.a24 = F.sub a (1 + 1))
402+
(Ha : ~(exists r, F.mul r r = F.sub (F.mul a a) (F.of_Z _ 4))).
360403

361404
Hint Extern 1 (spec_of "fe25519_inv") => (simple refine (spec_of_exp_large)) : typeclass_instances.
362405
Hint Extern 1 (spec_of "felem_cswap") => (simple refine (spec_of_cswap)) : typeclass_instances.
363406

364407
Derive montladder_body SuchThat
365408
(defn! "montladder" ("OUT", "K", "U")
366409
{ montladder_body },
367-
implements montladder_gallina
410+
implements (montladder_gallina(m:=M_pos))
368411
using ["felem_cswap"; felem_copy; from_word;
369412
"ladderstep"; "fe25519_inv"; mul])
370413
As montladder_correct.
371414
Proof.
372415
pose proof scalarbits_bound.
373-
cbv [spec_of_montladder]; intros; eapply Semantics.weaken_call; cycle 1; intros.
374-
{ rewrite <-montladder_gallina_equiv. match goal with H : ?e t' m' rets |- _ => exact H end. }
416+
cbv [spec_of_montladder]; intros; eapply Semantics.weaken_call with
417+
(post1:=fun t' m' rets => rets = [] /\ t' = tr /\
418+
((FElem (Some tight_bounds) pOUT (montladder_gallina a24 scalarbits K U)
419+
⋆ Kbytes $@ pK ⋆ FElem (Some tight_bounds) pU U ⋆ R) m')); cycle 1; intros.
420+
{ DestructHead.destruct_head and; Tactics.ssplit; trivial; intros.
421+
pose proof LittleEndianList.le_combine_bound Kbytes. subst U.
422+
erewrite montladder_gallina_equiv_affine in *; eauto; try lia. }
375423

376424
compile_setup.
377-
repeat compile_step.
425+
repeat compile_step; shelve_unifiable.
378426
eapply compile_nlet_as_nlet_eq.
379427
eapply compile_felem_cswap; repeat compile_step.
380428

381429
eapply compile_nlet_as_nlet_eq.
382430
eapply compile_felem_cswap; repeat compile_step.
383431

432+
lia. (* m = 2^255-19 *)
384433
compile_step.
385434
Qed.
386435

‎src/Bedrock/Group/ScalarMult/ScalarMult.v

-313
This file was deleted.

‎src/Curves/Montgomery/Affine.v

+1-7
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,7 @@ Module M.
2727

2828
Context {a b: F} {b_nonzero:b <> 0}.
2929

30-
Program Definition opp (P:@M.point F Feq Fadd Fmul a b) : @M.point F Feq Fadd Fmul a b :=
31-
match P return F*F+∞ with
32-
| (x, y) => (x, -y)
33-
| ∞ => ∞
34-
end.
35-
Next Obligation. Proof. destruct_head @M.point; cbv; break_match; trivial; fsatz. Qed.
36-
30+
Local Notation opp := (M.opp(a:=a)(b_nonzero:=b_nonzero)).
3731
Local Notation add := (M.add(b_nonzero:=b_nonzero)).
3832
Local Notation point := (@M.point F Feq Fadd Fmul a b).
3933

‎src/Curves/Montgomery/XZProofs.v

+42-79
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ Module M.
2424
Context {F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv}
2525
{field:@Algebra.Hierarchy.field F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv}
2626
{Feq_dec:Decidable.DecidableRel Feq}
27-
{char_ge_3:@Ring.char_ge F Feq Fzero Fone Fopp Fadd Fsub Fmul 3}
28-
{char_ge_5:@Ring.char_ge F Feq Fzero Fone Fopp Fadd Fsub Fmul 5}
29-
{char_ge_12:@Ring.char_ge F Feq Fzero Fone Fopp Fadd Fsub Fmul 12}
3027
{char_ge_28:@Ring.char_ge F Feq Fzero Fone Fopp Fadd Fsub Fmul 28}.
28+
29+
Lemma Private_char_ge_3: @Ring.char_ge F Feq Fzero Fone Fopp Fadd Fsub Fmul 3.
30+
Proof. clear -char_ge_28; eapply Algebra.Hierarchy.char_ge_weaken; eauto; vm_decide. Qed.
31+
Context {char_ge_3 : @Ring.char_ge F Feq Fzero Fone Fopp Fadd Fsub Fmul 3}. (* appears in statement *)
32+
Local Instance char_ge_5: @Ring.char_ge F Feq Fzero Fone Fopp Fadd Fsub Fmul 5.
33+
Proof. clear -char_ge_28; eapply Algebra.Hierarchy.char_ge_weaken; eauto; vm_decide. Qed.
34+
Local Instance char_ge_12: @Ring.char_ge F Feq Fzero Fone Fopp Fadd Fsub Fmul 12.
35+
Proof. clear -char_ge_28; eapply Algebra.Hierarchy.char_ge_weaken; eauto; vm_decide. Qed.
3136
Local Infix "=" := Feq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope.
3237
Local Infix "+" := Fadd. Local Infix "*" := Fmul.
3338
Local Infix "-" := Fsub. Local Infix "/" := Fdiv.
@@ -40,6 +45,7 @@ Module M.
4045
Local Notation Madd := (M.add(a:=a)(b_nonzero:=b_nonzero)(char_ge_3:=char_ge_3)).
4146
Local Notation Mopp := (M.opp(a:=a)(b_nonzero:=b_nonzero)).
4247
Local Notation Mpoint := (@M.point F Feq Fadd Fmul a b).
48+
Local Notation X0 := (M.X0(Fzero:=Fzero)(Feq:=Feq)(Fadd:=Fadd)(Fmul:=Fmul)(a:=a)(b:=b)).
4349
Local Notation to_xz := (M.to_xz(Fzero:=Fzero)(Fone:=Fone)(Feq:=Feq)(Fadd:=Fadd)(Fmul:=Fmul)(a:=a)(b:=b)).
4450
Local Notation xzladderstep := (M.xzladderstep(a24:=a24)(Fadd:=Fadd)(Fsub:=Fsub)(Fmul:=Fmul)).
4551

@@ -226,10 +232,7 @@ Module M.
226232
if dec (snd xz = 0) then 0 else fst xz / snd xz.
227233
Hint Unfold to_x : points_as_coordinates.
228234

229-
Lemma to_x_to_xz Q : to_x (to_xz Q) = match M.coordinates Q with
230-
| ∞ => 0
231-
| (x,y) => x
232-
end.
235+
Lemma to_x_to_xz Q : to_x (to_xz Q) = X0 Q.
233236
Proof. t. Qed.
234237

235238
Lemma proper_to_x_projective xz x'z'
@@ -269,17 +272,11 @@ Module M.
269272
Lemma Z_shiftr_testbit_1 n i: Logic.eq (n>>i)%Z (Z.div2 (n >> i) + Z.div2 (n >> i) + Z.b2z (Z.testbit n i))%Z.
270273
Proof. rewrite ?Z.testbit_odd, ?Z.add_diag, <-?Z.div2_odd; reflexivity. Qed.
271274

275+
Context (HFinv : Finv 0 = 0) (scalarbits : Z) (Hscalarbits : (0 <= scalarbits)%Z).
276+
272277
(* We prove montladder correct by considering the zero and non-zero case
273278
separately. *)
274-
275-
Lemma montladder_correct_0
276-
(HFinv : Finv 0 = 0)
277-
(n : Z)
278-
(scalarbits : Z) (point : F)
279-
(Hz : point = 0)
280-
(Hn : (0 <= n < 2^scalarbits)%Z)
281-
(Hscalarbits : (0 <= scalarbits)%Z)
282-
: montladder scalarbits (Z.testbit n) point = 0.
279+
Lemma montladder_correct_0 n x (Hx : Feq x 0) : montladder scalarbits (Z.testbit n) x = 0.
283280
Proof.
284281
cbv beta delta [M.montladder].
285282
(* [while.by_invariant] expects a goal like [?P (while _ _ _ _)], make it so: *)
@@ -292,7 +289,7 @@ Module M.
292289
(fun s => Z.to_nat (Z.succ (snd s)))).
293290
{ split.
294291
(* invariant holds in the beginning *)
295-
{ cbn; split; [lia|split;[reflexivity|t]]. }
292+
{ cbn; split; [lia|split;[reflexivity|try t]]. }
296293
{ (* fuel <= measure *) cbn. rewrite Z.succ_pred. reflexivity. } }
297294
{ intros [ [ [ [ [x2 z2] x3] z3] swap] i] [Hi [Hz2 Hx3z3]].
298295
destruct (i >=? 0)%Z eqn:Hbranch; (* did the loop continue? *)
@@ -313,44 +310,40 @@ Module M.
313310
cbv [M.cswap]; break_match; break_match_hyps; setoid_subst_rel Feq; fsatz. } }
314311
Qed.
315312

316-
Lemma montladder_correct_nz
317-
(HFinv : Finv 0 = 0)
318-
(n : Z) (P : M.point)
319-
(scalarbits : Z) (point : F)
320-
(Hnz : point <> 0)
321-
(Hn : (0 <= n < 2^scalarbits)%Z)
322-
(Hscalarbits : (0 <= scalarbits)%Z)
323-
(Hpoint : point = to_x (to_xz P))
324-
: montladder scalarbits (Z.testbit n) point = to_x (to_xz (scalarmult n P)).
313+
Lemma montladder_correct_nz n P (Hnz : X0 P <> 0)
314+
: montladder scalarbits (Z.testbit n) (X0 P) = X0 (scalarmult (n mod 2^scalarbits) P).
325315
Proof.
326316
pose proof (let (_, h, _, _) := AffineInstances.M.MontgomeryWeierstrassIsomorphism b_nonzero (a:=a) a2m4_nz in h) as commutative_group.
327317
cbv beta delta [M.montladder].
328318
(* [while.by_invariant] expects a goal like [?P (while _ _ _ _)], make it so: *)
329319
lazymatch goal with |- context [while ?t ?b ?l ?i] => pattern (while t b l i) end.
330320
eapply (while.by_invariant_fuel
331321
(fun '(x2, z2, x3, z3, swap, i) =>
332-
(i >= -1)%Z /\
322+
(-1 <= i < scalarbits)%Z /\
333323
projective (pair x2 z2) /\
334324
projective (pair x3 z3) /\
335325
let q := if (swap:bool) then (pair x3 z3) else (pair x2 z2) in
336326
let q' := if (swap:bool) then (pair x2 z2) else (pair x3 z3) in
337-
let r := (n >> Z.succ i)%Z in
327+
let r := ((n mod 2^scalarbits) >> Z.succ i)%Z in
338328
eq q (to_xz (scalarmult r P)) /\
339329
eq q' (to_xz (scalarmult (Z.succ r) P)) /\
340-
ladder_invariant point (scalarmult r P) (scalarmult (Z.succ r) P))
330+
ladder_invariant (X0 P) (scalarmult r P) (scalarmult (Z.succ r) P))
341331
(fun s => Z.to_nat (Z.succ (snd s))) (* decreasing measure *) ).
342332
{ split; cbn.
343333
{ (* invariant holds in the beginning *)
344-
rewrite ?Z.succ_pred, ?Z.lt_pow_2_shiftr, <-?Z.one_succ by tauto.
345-
repeat split; [lia|t..]. }
334+
rewrite ?Z.succ_pred, ?Z.lt_pow_2_shiftr, <-?Z.one_succ by (apply Z.mod_pos_bound; lia).
335+
repeat split; [lia|lia|t..]. }
346336
{ (* sufficient fuel *) rewrite Z.succ_pred. reflexivity. } }
347337
{ intros [ [ [ [ [x2 z2] x3] z3] swap] i] [Hi [Hx2z2 [Hx3z3 [Hq [Hq' Hladder]]]]].
348338
destruct (i >=? 0)%Z eqn:Hbranch; (* did the loop continue? *)
349339
rewrite Z.geb_ge_iff in Hbranch.
350340
split.
351341
{ (* if loop continued, invariant is preserved *)
342+
remember (Z.testbit n i) as bit eqn:Hbit; symmetry in Hbit.
343+
erewrite <-(Z.mod_pow2_bits_low _ scalarbits) in Hbit by tauto.
344+
set (n mod 2 ^ scalarbits)%Z as n' in *.
352345
let group _ := ltac:(repeat rewrite ?scalarmult_add_l, ?scalarmult_0_l, ?scalarmult_1_l, ?Hierarchy.left_identity, ?Hierarchy.right_identity, ?Hierarchy.associative, ?(Hierarchy.commutative _ P); reflexivity) in
353-
destruct (Z.testbit n i) eqn:Hbit in *;
346+
destruct bit in *;
354347
destruct swap eqn:Hswap in *;
355348
repeat match goal with
356349
| _ => solve [ congruence | assumption | lia ]
@@ -367,8 +360,8 @@ Module M.
367360
=> let pf := constr:(to_xz_add p xz x'z' _ _ H G HQ HQ' ltac:(auto using ladder_invariant_swap)) in
368361
unique pose proof (proj1 pf); destruct (proj2 pf) as [? [? [? ?]]] (* because there is no unique destruct *)
369362
| _ => progress rewrite ?Z.succ_pred, ?Z.shiftr_succ, <-?Z.div2_spec, <-?Z.add_1_r in *
370-
| |- context [scalarmult (n>>i) ] => rewrite (Z_shiftr_testbit_1 n i), Hbit; cbn [Z.b2z]
371-
| |- context [scalarmult (n>>i+1) ] => rewrite (Z_shiftr_testbit_1 n i), Hbit; cbn [Z.b2z]
363+
| |- context [scalarmult (n'>>i) ] => rewrite (Z_shiftr_testbit_1 n' i), Hbit; cbn [Z.b2z]
364+
| |- context [scalarmult (n'>>i+1) ] => rewrite (Z_shiftr_testbit_1 n' i), Hbit; cbn [Z.b2z]
372365
| |- ?P => match type of P with Prop => split end
373366
| H: eq (?f _) (to_xz ?LHS) |- eq (?f _) (to_xz ?RHS)
374367
=> eapply (transitive_eq (to_xz LHS) ltac:(auto using projective_to_xz) H); f_equiv; group ()
@@ -381,71 +374,41 @@ Module M.
381374
{ (* measure decreases *)
382375
cbv [Let_In]; break_match; cbn; rewrite Z.succ_pred; apply Znat.Z2Nat.inj_lt; lia. }
383376
{ (* if loop exited, invariant implies postcondition *)
384-
destruct_head' @and; autorewrite with cancel_pair in *.
385377
replace i with ((-(1))%Z) in * by lia; clear Hi Hbranch.
386378
rewrite Z.succ_m1, Z.shiftr_0_r in *.
387379
cbv [M.cswap];
388380
destruct swap eqn:Hswap; rewrite <-!to_x_inv00 by assumption;
381+
etransitivity; try eapply to_x_to_xz; f_equal;
389382
eauto using projective_to_xz, proper_to_x_projective. } }
390383
Qed.
391384

392385
(* Using montladder_correct_0 in the combined correctness theorem requires
393386
additionally showing that the right-hand-side is 0. This comes from there
394387
being two points such that to_x gives 0: infinity and (0, 0). *)
395388

396-
Lemma opp_to_x_to_xz_0
397-
(P : M.point)
398-
(H : 0 = to_x (to_xz P))
399-
: 0 = to_x (to_xz (Mopp P)).
389+
Lemma X0_opp_0 (P : M.point) (H : X0 P = 0) : X0 (Mopp P) = 0.
400390
Proof. t. Qed.
401391

402-
Lemma add_to_x_to_xz_0
403-
(P Q : M.point)
404-
(HP : 0 = to_x (to_xz P))
405-
(HQ : 0 = to_x (to_xz Q))
406-
: 0 = to_x (to_xz (Madd P Q)).
407-
Proof. t. Qed.
392+
Lemma X0_add_0 (P Q : M.point) (HP : X0 P = 0) (HQ : X0 Q = 0) : X0(Madd P Q) = 0.
393+
Proof. cbv [X0] in *; t. Qed.
408394

409-
Lemma scalarmult_to_x_to_xz_0
410-
(n : Z) (P : M.point)
411-
(H : 0 = to_x (to_xz P))
412-
: 0 = to_x (to_xz (scalarmult n P)).
395+
Lemma X0_scalarmult_0 (n : Z) (P : M.point) (H : X0 P = 0) : X0 (scalarmult n P) = 0.
413396
Proof.
414-
induction n using Z.peano_rect_strong.
415-
{ cbn. t. }
416-
{ (* Induction case from n to Z.succ n. *)
417-
unfold scalarmult_ref.
418-
rewrite Z.peano_rect_succ by lia.
419-
fold (scalarmult n P).
420-
apply add_to_x_to_xz_0; trivial. }
421-
{ (* Induction case from n to Z.pred n. *)
422-
unfold scalarmult_ref.
423-
rewrite Z.peano_rect_pred by lia.
424-
fold (scalarmult n P).
425-
apply add_to_x_to_xz_0.
426-
{ apply opp_to_x_to_xz_0; trivial. }
427-
{ trivial. } }
397+
clear dependent scalarbits.
398+
induction n using Z.peano_rect_strong; try t.
399+
{ unfold scalarmult_ref. rewrite Z.peano_rect_succ by lia. fold (scalarmult n P).
400+
auto using X0_add_0. }
401+
{ unfold scalarmult_ref. rewrite Z.peano_rect_pred by lia. fold (scalarmult n P).
402+
auto using X0_add_0, X0_opp_0. }
428403
Qed.
429404

430405
(* Combine the two cases together. *)
431406

432-
Lemma montladder_correct
433-
(HFinv : Finv 0 = 0)
434-
(n : Z) (P : M.point)
435-
(scalarbits : Z) (point : F)
436-
(Hn : (0 <= n < 2^scalarbits)%Z)
437-
(Hscalarbits : (0 <= scalarbits)%Z)
438-
(Hpoint : point = to_x (to_xz P))
439-
: montladder scalarbits (Z.testbit n) point = to_x (to_xz (scalarmult n P)).
407+
Lemma montladder_correct n P :
408+
montladder scalarbits (Z.testbit n) (X0 P) = X0 (scalarmult (n mod 2^scalarbits) P).
440409
Proof.
441-
destruct (dec (point = 0)) as [Hz|Hnz].
442-
{ rewrite (montladder_correct_0 HFinv _ _ _ Hz Hn Hscalarbits).
443-
setoid_subst_rel Feq.
444-
apply scalarmult_to_x_to_xz_0.
445-
trivial. }
446-
{ apply (montladder_correct_nz HFinv _ _ _ _ Hnz Hn Hscalarbits).
447-
trivial. }
410+
destruct (dec (X0 P = 0)) as [Hz|?]; auto using montladder_correct_nz .
411+
rewrite montladder_correct_0, X0_scalarmult_0 by trivial; reflexivity.
448412
Qed.
449-
450413
End MontgomeryCurve.
451414
End M.

‎src/Spec/Curve25519.v

+29
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,32 @@ Proof.
6868
Proof_certif 2 prime_2] _).
6969
native_cast_no_check (@eq_refl bool true).
7070
Time Qed. (* 1s *)
71+
72+
Local Notation F := (F p).
73+
74+
Require PrimeFieldTheorems.
75+
76+
Lemma field : @Hierarchy.field F eq F.zero F.one F.opp F.add F.sub F.mul F.inv F.div.
77+
Proof. apply PrimeFieldTheorems.F.field_modulo, prime_p. Qed.
78+
Lemma char_ge_3 : @Ring.char_ge F eq F.zero F.one F.opp F.add F.sub F.mul 3.
79+
Proof. eapply Hierarchy.char_ge_weaken; try apply ModularArithmeticTheorems.F.char_gt; Decidable.vm_decide. Qed.
80+
81+
Require Import Spec.MontgomeryCurve.
82+
Module M.
83+
Definition a : F := F.of_Z _ 486662.
84+
Definition b : F := F.one.
85+
Definition a24 : F := ((a - F.of_Z _ 2) / F.of_Z _ 4)%F.
86+
Definition point := @M.point F eq F.add F.mul a F.one.
87+
Definition B : point :=
88+
exist _ (inl (F.of_Z _ 9, F.of_Z _ 14781619447589544791020593568409986887264606134616475288964881837755586237401)) eq_refl.
89+
90+
Lemma a2m4_nonzero : F.sub (F.mul a a) (F.of_Z _ 4) <> F.zero. Decidable.vm_decide. Qed.
91+
Lemma a2m4_nonsq : ~(exists r, F.mul r r = F.sub (F.mul a a) (F.of_Z _ 4)).
92+
Proof. epose (@PrimeFieldTheorems.F.Decidable_square p prime_p eq_refl); Decidable.vm_decide. Qed.
93+
Lemma b_nonzero : b <> F.zero. Decidable.vm_decide. Qed.
94+
95+
Definition add := (M.add(field:=field)(char_ge_3:=char_ge_3)(a:=a)(b_nonzero:=b_nonzero)).
96+
Definition opp := (M.opp(field:=field)(a:=a)(b_nonzero:=b_nonzero)).
97+
Definition X0 := (M.X0(Feq:=eq)(Fzero:=F.zero)(Fadd:=F.add)(Fmul:=F.mul)(a:=a)(b:=b)).
98+
Definition scalarmult := (@ScalarMult.scalarmult_ref _ add M.zero opp).
99+
End M.

‎src/Spec/MontgomeryCurve.v

+16
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,21 @@ Module M.
6161
Proof.
6262
cbv [coordinates]; BreakMatch.break_match; trivial; Field.fsatz.
6363
Qed.
64+
65+
Program Definition opp (P : point) : point :=
66+
match P return F*F+∞ with
67+
| (x, y) => (x, -y)
68+
| ∞ => ∞
69+
end.
70+
Next Obligation.
71+
Proof.
72+
DestructHead.destruct_head @point; cbv; BreakMatch.break_match; trivial; Field.fsatz.
73+
Qed.
74+
75+
Definition X0 (P : point) : F :=
76+
match coordinates P with
77+
| (x, y) => x
78+
| _ => Fzero
79+
end.
6480
End MontgomeryCurve.
6581
End M.

‎src/Spec/Test/X25519.v

+4-7
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@ Require Import Coq.NArith.BinNatDef.
55
Require Import Coq.ZArith.BinIntDef.
66
Require Import Coq.PArith.BinPosDef.
77
Require Import Spec.ModularArithmetic Spec.Curve25519 Spec.MxDH Crypto.Util.Decidable.
8-
Definition F := F Curve25519.p.
9-
Definition a : F := F.of_Z _ 486662.
10-
Definition a24 : F := ((a - F.of_Z _ 2) / F.of_Z _ 4)%F.
118
Definition cswap {T} (swap:bool) (a b:T) := if swap then (b, a) else (a, b).
12-
Definition monty s : F -> F := @MxDH.montladder F F.zero F.one F.add F.sub F.mul F.inv a24 cswap 255 (BinNat.N.testbit_nat s).
9+
Definition monty s : F p -> F p := @MxDH.montladder _ F.zero F.one F.add F.sub F.mul F.inv M.a24 cswap 255 (BinNat.N.testbit_nat s).
1310

1411
Example one_basepoint : F.to_Z (monty 1 (F.of_Z _ 9)) = 9%Z.
1512
Proof. vm_decide_no_check. Qed.
@@ -28,15 +25,15 @@ Example order_basepoint : F.to_Z (monty (N.pos l) (F.of_Z _ 9)) = 0%Z.
2825
Proof. vm_decide_no_check. Qed. (* note: ideally we'd check that z=0 *)
2926

3027
Definition double x := (* takes as input affine x, returns projective x/z *)
31-
fst (@MxDH.ladderstep F F.add F.sub F.mul a24 (F.of_Z _ 0) (x, F.of_Z _ 1) (x, F.of_Z _ 1)).
28+
fst (@MxDH.ladderstep _ F.add F.sub F.mul M.a24 (F.of_Z _ 0) (x, F.of_Z _ 1) (x, F.of_Z _ 1)).
3229
(* EllipticCurve(GF(2^255 - 19), [0,486662,0,1,0]).torsion_polynomial(8).roots(multiplicities=False) *)
3330
(* Point of order 2: *)
3431
Lemma double_zero : snd (double (F.of_Z _ 0)) = F.of_Z _ 0. vm_decide_no_check. Qed.
3532
(* Points of order 4: *)
3633
Lemma double_one : fst (double (F.of_Z _ 1)) = F.of_Z _ 0. vm_decide_no_check. Qed.
3734
Lemma double_minusone:fst(double(F.of_Z _(-1)))=F.of_Z _ 0. vm_decide_no_check. Qed.
3835
(* Points of order 8: *)
39-
Definition order8_x1 : F := F.of_Z _ 39382357235489614581723060781553021112529911719440698176882885853963445705823.
40-
Definition order8_x2 : F := F.of_Z _ 325606250916557431795983626356110631294008115727848805560023387167927233504.
36+
Definition order8_x1 := F.of_Z p 39382357235489614581723060781553021112529911719440698176882885853963445705823.
37+
Definition order8_x2 := F.of_Z p 325606250916557431795983626356110631294008115727848805560023387167927233504.
4138
Lemma double_order8_x1 : fst (double order8_x1) = snd (double order8_x1). vm_decide_no_check. Qed.
4239
Lemma double_order8_x2 : fst (double order8_x2) = snd (double order8_x2). vm_decide_no_check. Qed.

0 commit comments

Comments
 (0)
Please sign in to comment.