Skip to content

Commit 9b5f833

Browse files
implement and prove Curve25519 scalar clamping (#1845)
1 parent 55c430f commit 9b5f833

File tree

5 files changed

+227
-51
lines changed

5 files changed

+227
-51
lines changed

src/Bedrock/End2End/X25519/GarageDoor.v

+7-18
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,7 @@ Require Import bedrock2Examples.memequal.
2323
Require Import bedrock2Examples.memswap.
2424
Require Import bedrock2Examples.memconst.
2525
Require Import Rupicola.Examples.Net.IPChecksum.IPChecksum.
26-
27-
(******)
28-
2926
Require Crypto.Bedrock.End2End.RupicolaCrypto.ChaCha20.
30-
(*
31-
Require bedrock2.BasicC32Semantics.
32-
Goal bedrock2.BasicC32Semantics.ext_spec = bedrock2.FE310CSemantics.ext_spec.
33-
reflexivity.
34-
cbn.
35-
Require bedrock2.FE310CSemantics*)
36-
37-
(******)
3827

3928
Local Open Scope string_scope.
4029
Import Syntax Syntax.Coercions NotationsCustomEntry.
@@ -214,7 +203,7 @@ Definition garagedoor_iteration : state -> list (lightbulb_spec.OP _) -> state -
214203
(TracePredicate.one ("st", lightbulb_spec.GPIO_DATA_ADDR _, action))) ioh
215204
/\ (
216205
let m := firstn 16 garagedoor_payload in
217-
let v := le_split 32 (M.X0 (Curve25519.M.scalarmult (le_combine sk mod 2^255) garageowner_P)) in
206+
let v := x25519_spec sk garageowner_P in
218207
exists set0 set1 : Naive.word32,
219208
(word.unsigned set0 = 1 <-> firstn 16 v = m) /\
220209
(word.unsigned set1 = 1 <-> skipn 16 v = m) /\
@@ -234,7 +223,7 @@ Definition garagedoor_iteration : state -> list (lightbulb_spec.OP _) -> state -
234223
udp_local ++ udp_remote ++
235224
be2 udp_length ++ be2 0 ++
236225
garagedoor_header ++
237-
le_split 32 (M.X0 (Curve25519.M.scalarmult (le_combine sk mod 2^255) Curve25519.M.B))))
226+
x25519_spec sk Curve25519.M.B))
238227
ioh /\ SEED=seed /\ SK=sk.
239228

240229
Local Instance spec_of_recvEthernet : spec_of "recvEthernet" := spec_of_recvEthernet.
@@ -402,16 +391,16 @@ Proof.
402391
subst pPPP.
403392
seprewrite_in_by (Array.bytearray_append cmp1) H33 SepAutoArray.listZnWords.
404393

405-
remember (le_split 32 (M.X0 (Curve25519.M.scalarmult (le_combine sk mod 2^255) garageowner_P))) as vv.
394+
remember (x25519_spec sk garageowner_P) as vv.
406395
repeat straightline.
407396
pose proof (List.firstn_skipn 16 vv) as Hvv.
408-
pose proof (@firstn_length_le _ vv 16 ltac:(subst vv; rewrite ?length_le_split; ZnWords)).
397+
pose proof (@firstn_length_le _ vv 16 ltac:(subst vv; rewrite length_x25519_spec; ZnWords)).
409398
pose proof skipn_length 16 vv.
410399
forget (List.firstn 16 vv) as vv0.
411400
forget (List.skipn 16 vv) as vv1.
412401
subst vv.
413402
rewrite <-Hvv in H33.
414-
rewrite length_le_split in *.
403+
rewrite length_x25519_spec in *.
415404
seprewrite_in_by (Array.bytearray_append vv0) H33 SepAutoArray.listZnWords.
416405

417406
repeat straightline.
@@ -864,10 +853,10 @@ Optimize Proof. Optimize Heap.
864853
progress rewrite ?word.unsigned_sru_nowrap, ?word.unsigned_of_Z_nowrap in H37 by ZnWords.
865854

866855
straightline_call; [ssplit; cycle -1|]; try ecancel_assumption.
867-
{ rewrite ?app_length, ?length_le_split. SepAutoArray.listZnWords. }
856+
{ rewrite ?app_length, ?length_x25519_spec. SepAutoArray.listZnWords. }
868857
{ ZnWords. }
869858

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.
859+
pose proof length_x25519_spec sk Curve25519.M.B as Hpkl.
871860
seprewrite_in_by (fun xs ys=>@bytearray_address_merge _ _ _ _ _ xs ys buf) H37 SepAutoArray.listZnWords.
872861
seprewrite_in_by (fun xs ys=>@bytearray_address_merge _ _ _ _ _ xs ys buf) H37 SepAutoArray.listZnWords.
873862

src/Bedrock/End2End/X25519/GarageDoorTop.v

+2
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ Proof.
9393
pose_correctness spi_write_ok.
9494
pose_correctness spi_read_ok.
9595
pose_correctness (ip_checksum_br2fn_ok I).
96+
pose_correctness memmove.memmove_ok_array.
97+
pose_correctness clamp.clamp_correct.
9698
pose_correctness x25519_base_ok.
9799
pose_correctness fe25519_from_word_correct.
98100
pose_correctness fe25519_to_bytes_correct.

src/Bedrock/End2End/X25519/MontgomeryLadder.v

+64-33
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Require Import Crypto.Spec.MontgomeryCurve.
66
Require Import Crypto.Spec.Curve25519.
77
Require Import bedrock2.Map.Separation.
88
Require Import bedrock2.Syntax.
9+
Require Import bedrock2Examples.memmove.
10+
Require Import bedrock2.SepAutoArray.
911
Require Import compiler.Pipeline.
1012
Require Import compiler.Symbols.
1113
Require Import compiler.MMIO.
@@ -18,6 +20,7 @@ Require Import Crypto.Bedrock.Group.ScalarMult.LadderStep.
1820
Require Import Crypto.Bedrock.Group.ScalarMult.CSwap.
1921
Require Import Crypto.Bedrock.Group.ScalarMult.MontgomeryLadder.
2022
Require Import Crypto.Bedrock.End2End.X25519.Field25519.
23+
Require Import Crypto.Bedrock.End2End.X25519.clamp.
2124
Local Open Scope string_scope.
2225
Import ListNotations.
2326

@@ -32,38 +35,52 @@ Proof. vm_compute. subst; exact eq_refl. Qed.
3235
Require Import bedrock2.NotationsCustomEntry.
3336

3437
Definition x25519 := func! (out, sk, pk) {
38+
stackalloc 32 as K;
39+
memmove(K, sk, $32);
40+
clamp(K);
3541
stackalloc 40 as U;
3642
fe25519_from_bytes(U, pk);
3743
stackalloc 40 as OUT;
38-
montladder(OUT, sk, U);
44+
montladder(OUT, K, U);
3945
fe25519_to_bytes(out, OUT)
4046
}.
4147

4248
Definition x25519_base := func! (out, sk) {
49+
stackalloc 32 as K;
50+
memmove(K, sk, $32);
51+
clamp(K);
4352
stackalloc 40 as U;
4453
fe25519_from_word(U, $9);
4554
stackalloc 40 as OUT;
46-
montladder(OUT, sk, U);
55+
montladder(OUT, K, U);
4756
fe25519_to_bytes(out, OUT)
4857
}.
4958

5059
Import LittleEndianList.
5160
Local Coercion F.to_Z : F >-> Z.
5261
Require Import bedrock2.WeakestPrecondition bedrock2.Semantics bedrock2.ProgramLogic.
5362
Require Import bedrock2.Syntax bedrock2.Map.SeparationLogic.
54-
Require Import coqutil.Map.OfListWord Coq.Init.Byte coqutil.Byte.
63+
Require Import Coq.Init.Byte coqutil.Byte.
5564
Import ProgramLogic.Coercions.
5665
Local Notation "m =* P" := ((P%sep) m) (at level 70, only parsing) (* experiment*).
5766
Local Notation "xs $@ a" := (Array.array ptsto (word.of_Z 1) a xs) (at level 10, format "xs $@ a").
5867

68+
Definition x25519_spec s P := le_split 32 (M.X0 (Curve25519.M.scalarmult (Curve25519.clamp (le_combine s)) P)).
69+
Lemma length_x25519_spec s P : length (x25519_spec s P) = 32%nat. Proof. apply length_le_split. Qed.
70+
5971
Global Instance spec_of_x25519 : spec_of "x25519" :=
6072
fnspec! "x25519" out sk pk / (o s p : list Byte.byte) P (R : _ -> Prop),
6173
{ requires t m := m =* s$@sk * p$@pk * o$@out * R /\
6274
length s = 32%nat /\ length p = 32%nat /\ length o = 32%nat /\
6375
byte.unsigned (nth 31 p x00) <= 0x7f /\ Field.feval_bytes(field_parameters:=field_parameters) p = Curve25519.M.X0 P;
64-
ensures t' m := t=t' /\ m=* s$@sk ⋆ p$@pk ⋆ R ⋆
65-
(le_split 32 (M.X0 (Curve25519.M.scalarmult (le_combine s mod 2^255) P))$@out) }.
76+
ensures t' m := t=t' /\ m=* s$@sk ⋆ p$@pk ⋆ R ⋆ (x25519_spec s P)$@out }.
6677

78+
Global Instance spec_of_x25519_base : spec_of "x25519_base" :=
79+
fnspec! "x25519_base" out sk / (o s : list Byte.byte) (R : _ -> Prop),
80+
{ requires t m := m =* s$@sk * o$@out * R /\ length s = 32%nat /\ length o = 32%nat;
81+
ensures t' m := t=t' /\ m=* s$@sk ⋆ R ⋆ (x25519_spec s Curve25519.M.B)$@out }.
82+
83+
Local Instance spec_of_memmove_array : spec_of "memmove" := spec_of_memmove_array.
6784
Local Instance spec_of_fe25519_from_word : spec_of "fe25519_from_word" := Field.spec_of_from_word.
6885
Local Instance spec_of_fe25519_from_bytes : spec_of "fe25519_from_bytes" := Field.spec_of_from_bytes.
6986
Local Instance spec_of_fe25519_to_bytes : spec_of "fe25519_to_bytes" := Field.spec_of_to_bytes.
@@ -81,12 +98,16 @@ Local Arguments word.of_Z : simpl never.
8198
Lemma x25519_ok : program_logic_goal_for_function! x25519.
8299
Proof.
83100
repeat straightline.
84-
seprewrite_in (@Bignum.Bignum_of_bytes _ _ _ _ _ _ 10 a) H2. { transitivity 40%nat; trivial. }
101+
102+
straightline_call; ssplit; try ecancel_assumption; repeat straightline; try listZnWords; [].
103+
straightline_call; ssplit; try ecancel_assumption; repeat straightline; try listZnWords; [].
104+
105+
seprewrite_in (@Bignum.Bignum_of_bytes _ _ _ _ _ _ 10 a0) H17. { transitivity 40%nat; trivial. }
85106

86107
straightline_call; ssplit.
87108
{ eexists. ecancel_assumption. }
88109
{ cbv [Field.FElem].
89-
use_sep_assumption. cancel. cancel_seps_at_indices 0%nat 0%nat; cbn; trivial. eapply RelationClasses.reflexivity. }
110+
use_sep_assumption. cancel. cancel_seps_at_indices 0%nat 0%nat; cbn [seps]; eapply RelationClasses.reflexivity. }
90111
{ unfold Field.bytes_in_bounds, frep25519, field_representation, Signature.field_representation, Representation.frep.
91112
match goal with |- ?P ?x ?z => let y := eval cbv in x in change (P y z) end; cbn.
92113
repeat (destruct p as [|? p]; try (cbn [length] in *;discriminate); []).
@@ -100,7 +121,7 @@ Proof.
100121
eapply byte.unsigned_range. }
101122
repeat straightline.
102123

103-
seprewrite_in (@Bignum.Bignum_of_bytes _ _ _ _ _ _ 10 a2) H16. { transitivity 40%nat; trivial. }
124+
seprewrite_in (@Bignum.Bignum_of_bytes _ _ _ _ _ _ 10 a2) H24. { transitivity 40%nat; trivial. }
104125

105126
straightline_call; ssplit.
106127
{ unfold FElem, Field.FElem in *; extract_ex1_and_emp_in_goal; ssplit.
@@ -109,10 +130,10 @@ Proof.
109130
all : eauto.
110131
{ instantiate (1:=None). exact I. } }
111132
{ reflexivity. }
112-
{ rewrite H3. vm_compute. inversion 1. }
133+
{ rewrite ?length_le_split. vm_compute. inversion 1. }
113134
repeat straightline.
114135

115-
specialize (H23 P ltac:(assumption)). cbv [FElem] in H23. extract_ex1_and_emp_in H23.
136+
specialize (H31 P ltac:(assumption)). cbv [FElem] in H31. extract_ex1_and_emp_in H31.
116137
straightline_call; ssplit.
117138
{ ecancel_assumption. }
118139
{ transitivity 32%nat; auto. }
@@ -122,43 +143,46 @@ Proof.
122143
repeat straightline.
123144

124145
cbv [Field.FElem] in *.
125-
seprewrite_in @Bignum.Bignum_to_bytes H26.
126-
seprewrite_in @Bignum.Bignum_to_bytes H26.
127-
extract_ex1_and_emp_in H26.
146+
seprewrite_in @Bignum.Bignum_to_bytes H34.
147+
seprewrite_in @Bignum.Bignum_to_bytes H34.
148+
extract_ex1_and_emp_in H34.
149+
pose proof length_le_split 32 (Curve25519.clamp (le_combine s)).
128150

129151
repeat straightline; intuition eauto.
130-
rewrite H30 in *.
131-
use_sep_assumption; cancel. reflexivity.
152+
cbv [x25519_spec].
153+
use_sep_assumption; cancel.
154+
rewrite H38, le_combine_split.
155+
do 7 Morphisms.f_equiv.
156+
pose proof clamp_range (le_combine s).
157+
(rewrite_strat bottomup Z.mod_small); change (Z.of_nat (Z.to_nat (Z.log2 (Z.pos order)))) with 255; try Lia.lia.
132158
Qed.
133159

134-
Global Instance spec_of_x25519_base : spec_of "x25519_base" :=
135-
fnspec! "x25519_base" out sk / (o s : list Byte.byte) (R : _ -> Prop),
136-
{ requires t m := m =* s$@sk * o$@out * R /\ length s = 32%nat /\ length o = 32%nat;
137-
ensures t' m := t=t' /\ m=* s$@sk ⋆ R ⋆
138-
le_split 32 (M.X0 (Curve25519.M.scalarmult (le_combine s mod 2^255) Curve25519.M.B))$@out }.
139-
140160
Lemma x25519_base_ok : program_logic_goal_for_function! x25519_base.
141161
Proof.
142162
repeat straightline.
143-
seprewrite_in (@Bignum.Bignum_of_bytes _ _ _ _ _ _ 10 a) H2. { transitivity 40%nat; trivial. }
163+
164+
straightline_call; ssplit; try ecancel_assumption; repeat straightline; try listZnWords; [].
165+
straightline_call; ssplit; try ecancel_assumption; repeat straightline; try listZnWords; [].
166+
167+
seprewrite_in (@Bignum.Bignum_of_bytes _ _ _ _ _ _ 10 a0) H14. { transitivity 40%nat; trivial. }
144168
straightline_call; ssplit.
145169
{ cbv [Field.FElem]. cbn. cbv [n]. ecancel_assumption. }
146170
repeat straightline.
147171

148-
seprewrite_in (@Bignum.Bignum_of_bytes _ _ _ _ _ _ 10 a2) H13. { transitivity 40%nat; trivial. }
172+
seprewrite_in (@Bignum.Bignum_of_bytes _ _ _ _ _ _ 10 a2) H21. { transitivity 40%nat; trivial. }
149173

150174
straightline_call; ssplit.
151175
{ unfold FElem, Field.FElem in *; extract_ex1_and_emp_in_goal; ssplit.
152176
{ use_sep_assumption. cancel; repeat ecancel_step.
153-
cancel_seps_at_indices 0%nat 0%nat; trivial. cbn; reflexivity. }
177+
cancel_seps_at_indices 0%nat 0%nat; trivial. cbn [seps]. reflexivity. }
154178
all : eauto.
155179
{ instantiate (1:=None). exact I. } }
156180
{ reflexivity. }
157-
{ rewrite H3. vm_compute. inversion 1. }
181+
{ rewrite length_le_split. vm_compute. inversion 1. }
158182
repeat straightline.
159183

160-
specialize (H20 Curve25519.M.B eq_refl).
161-
unfold FElem in H20. extract_ex1_and_emp_in H20.
184+
specialize (H28 Curve25519.M.B eq_refl).
185+
unfold FElem in H28. extract_ex1_and_emp_in H28.
162186
straightline_call; ssplit.
163187
{ ecancel_assumption. }
164188
{ transitivity 32%nat; auto. }
@@ -168,13 +192,18 @@ Proof.
168192
repeat straightline.
169193

170194
cbv [Field.FElem] in *.
171-
seprewrite_in @Bignum.Bignum_to_bytes H23.
172-
seprewrite_in @Bignum.Bignum_to_bytes H23.
173-
extract_ex1_and_emp_in H23.
195+
seprewrite_in @Bignum.Bignum_to_bytes H31.
196+
seprewrite_in @Bignum.Bignum_to_bytes H31.
197+
extract_ex1_and_emp_in H31.
198+
pose proof length_le_split 32 (Curve25519.clamp (le_combine s)).
174199

175200
repeat straightline; intuition eauto.
176-
rewrite H27 in *.
177-
use_sep_assumption; cancel. reflexivity.
201+
cbv [x25519_spec].
202+
use_sep_assumption; cancel.
203+
rewrite H35, le_combine_split.
204+
do 7 Morphisms.f_equiv.
205+
pose proof clamp_range (le_combine s).
206+
(rewrite_strat bottomup Z.mod_small); change (Z.of_nat (Z.to_nat (Z.log2 (Z.pos order)))) with 255; try Lia.lia.
178207
Qed.
179208

180209
Require Import coqutil.Word.Naive.
@@ -197,7 +226,9 @@ Definition funcs :=
197226
fe25519_add;
198227
fe25519_sub;
199228
fe25519_square;
200-
fe25519_scmula24 ].
229+
fe25519_scmula24;
230+
clamp;
231+
memmove ].
201232

202233
Require Import bedrock2.ToCString.
203234
Definition montladder_c_module := list_byte_of_string (ToCString.c_module funcs).

0 commit comments

Comments
 (0)