Skip to content

Commit e76c5da

Browse files
committed
Ed25519: Point-based separation logic for doubling
Convert the doubling function to a point based format, the rest of the functions will follow.
1 parent a6eb6bb commit e76c5da

1 file changed

Lines changed: 99 additions & 87 deletions

File tree

src/Bedrock/End2End/X25519/EdwardsXYZT.v

Lines changed: 99 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ From coqutil.Tactics Require Import Tactics letexists eabstract rdelta reference
2121
Require Import coqutil.Word.Bitwidth32.
2222
Require Import coqutil.Word.Bitwidth.
2323
Require Import coqutil.Word.Interface.
24+
Require Import coqutil.Word.Naive.
2425
From Coq Require Import Init.Byte.
2526
From Coq Require Import List.
2627
From Coq Require Import String.
@@ -76,29 +77,40 @@ Definition add_precomputed := func! (ox, oy, oz, ota, otb, X1, Y1, Z1, Ta1, Tb1,
7677
fe25519_mul(oz, F, G)
7778
}.
7879

80+
(* TODO can I pull those together somehow? *)
81+
Definition felem_size_term := Eval hnf in felem_size_in_bytes.
82+
(* Felem size in bytes in computed form. *)
83+
Definition felem_size := Eval compute in felem_size_term.
84+
85+
(* TODO how do we call these points? I call them normal points in my head :D *)
86+
Notation "A .x" := (expr.op Syntax.bopname.add A (0*felem_size)) (in custom bedrock_expr at level 3, left associativity).
87+
Notation "A .y" := (expr.op Syntax.bopname.add A (1*felem_size)) (in custom bedrock_expr at level 3, left associativity).
88+
Notation "A .z" := (expr.op Syntax.bopname.add A (2*felem_size)) (in custom bedrock_expr at level 3, left associativity).
89+
Notation "A .ta" := (expr.op Syntax.bopname.add A (3*felem_size)) (in custom bedrock_expr at level 3, left associativity).
90+
Notation "A .tb" := (expr.op Syntax.bopname.add A (4*felem_size)) (in custom bedrock_expr at level 3, left associativity).
91+
7992
(* Equivalent of m1double in src/Curves/Edwards/XYZT/Basic.v *)
80-
(* Note: Ta/Tb are unused, but leaving in place in case we want to switch to a point struct in the future *)
81-
Definition double := func! (ox, oy, oz, ota, otb, X, Y, Z, Ta, Tb) {
82-
stackalloc 40 as trX;
83-
fe25519_square(trX, X);
84-
stackalloc 40 as trZ;
85-
fe25519_square(trZ, Y);
86-
stackalloc 40 as t0;
87-
fe25519_square(t0, Z);
88-
stackalloc 40 as trT;
93+
Definition double := func! (p_out, p_a) {
94+
stackalloc felem_size as trX;
95+
fe25519_square(trX, p_a.x);
96+
stackalloc felem_size as trZ;
97+
fe25519_square(trZ, p_a.y);
98+
stackalloc felem_size as t0;
99+
fe25519_square(t0, p_a.z);
100+
stackalloc felem_size as trT;
89101
fe25519_carry_add(trT, t0, t0);
90-
stackalloc 40 as rY;
91-
fe25519_add(rY, X, Y);
102+
stackalloc felem_size as rY;
103+
fe25519_add(rY, p_a.x, p_a.y);
92104
fe25519_square(t0, rY);
93-
fe25519_carry_add(otb, trZ, trX);
94-
stackalloc 40 as cZ;
105+
fe25519_carry_add(p_out.tb, trZ, trX);
106+
stackalloc felem_size as cZ;
95107
fe25519_carry_sub(cZ, trZ, trX);
96-
fe25519_sub(ota, t0, otb);
97-
stackalloc 40 as cT;
108+
fe25519_sub(p_out.ta, t0, p_out.tb);
109+
stackalloc felem_size as cT;
98110
fe25519_sub(cT, trT, cZ);
99-
fe25519_mul(ox, ota, cT);
100-
fe25519_mul(oy, otb, cZ);
101-
fe25519_mul(oz, cZ, cT)
111+
fe25519_mul(p_out.x, p_out.ta, cT);
112+
fe25519_mul(p_out.y, p_out.tb, cZ);
113+
fe25519_mul(p_out.z, cZ, cT)
102114
}.
103115

104116
(* Converting a normal point to a cached point to prepare it for readdition. *)
@@ -148,13 +160,12 @@ Section WithParameters.
148160
Context {a_eq_minus1:a = F.opp F.one} {twice_d} {k_eq_2d:twice_d = (F.add d d)} {nonzero_d: d<>F.zero}.
149161

150162
Local Notation "m =* P" := ((P%sep) m) (at level 70, only parsing).
151-
Local Notation "xs $@ a" := (Array.array ptsto (word.of_Z 1) a xs) (at level 10, format "xs $@ a").
152163

153164
Local Notation FElem := (FElem(FieldRepresentation:=frep25519)).
154165
Local Notation bounded_by := (bounded_by(FieldRepresentation:=frep25519)).
155166
Local Notation word := (Naive.word 32).
156167
Local Notation felem := (felem(FieldRepresentation:=frep25519)).
157-
Local Notation point := (point(Fzero:=F.zero)(Fadd:=F.add)(Fmul:=F.mul)(a:=a)(d:=d)).
168+
Local Notation point := (point(Feq:=Logic.eq)(Fzero:=F.zero)(Fadd:=F.add)(Fmul:=F.mul)(a:=a)(d:=d)).
158169
Local Notation cached := (cached(Fzero:=F.zero)(Fadd:=F.add)(Fmul:=F.mul)(a:=a)(d:=d)).
159170
Local Notation coordinates := (coordinates(Feq:=Logic.eq)).
160171
Local Notation m1double :=
@@ -216,28 +227,34 @@ Global Instance spec_of_add_precomputed : spec_of "add_precomputed" :=
216227
bounded_by loose_bounds otb' /\
217228
m' =* (FElem X1K X1) * (FElem Y1K Y1) * (FElem Z1K Z1) * (FElem Ta1K Ta1) * (FElem Tb1K Tb1) * (FElem half_ypxK half_ypx) * (FElem half_ymxK half_ymx) * (FElem xydK xyd) * (FElem oxK ox') * (FElem oyK oy') * (FElem ozK oz') * (FElem otaK ota') * (FElem otbK otb') * R }.
218229

230+
Definition coords_bounds := (Field.bounds * Field.bounds * Field.bounds * Field.bounds * Field.bounds)%type.
231+
(* TODO find a good name for this construct. *)
232+
Definition bounded_coords := (felem * felem * felem * felem * felem)%type.
233+
Definition feval_coords '(x, y, z, ta, tb) := (feval x, feval y, feval z, feval ta, feval tb).
234+
235+
Definition coords_bounded_by (bounds : coords_bounds) '(x,y,z,ta,tb) : Prop :=
236+
let '(bounds_x, bounds_y, bounds_z, bounds_ta, bounds_tb) := bounds in
237+
bounded_by bounds_x x /\ bounded_by bounds_y y /\ bounded_by bounds_z z /\ bounded_by bounds_ta ta /\ bounded_by bounds_tb tb.
238+
239+
Local Notation "p .+ n" := (word.add p (word.of_Z n)) (at level 50, format "p .+ n", left associativity).
240+
Local Notation "c $@ p" := (let '(x,y,z,ta,tb) := c in sep (sep (sep (sep (FElem (p .+ 0) x) (FElem (p .+ 40) y)) (FElem (p .+ 80) z)) (FElem (p .+ 120) ta)) (FElem (p .+ 160) tb)) (at level 10, format "c $@ p").
241+
242+
219243
Global Instance spec_of_double : spec_of "double" :=
220244
fnspec! "double"
221-
(oxK oyK ozK otaK otbK XK YK ZK TaK TbK : word) /
222-
(ox oy oz ota otb X Y Z Ta Tb : felem) (p : point) (R : _ -> Prop),
223-
{ requires t m :=
224-
coordinates p = ((feval X), (feval Y), (feval Z), (feval Ta), (feval Tb)) /\
225-
bounded_by tight_bounds X /\
226-
bounded_by tight_bounds Y /\
227-
bounded_by loose_bounds Z /\
228-
bounded_by loose_bounds Ta /\
229-
bounded_by loose_bounds Tb /\
230-
m =* (FElem XK X) * (FElem YK Y) * (FElem ZK Z) * (FElem TaK Ta) * (FElem TbK Tb) * (FElem oxK ox) * (FElem oyK oy) * (FElem ozK oz) * (FElem otaK ota) * (FElem otbK otb) * R;
231-
ensures t' m' :=
245+
(p_out p_a : word) /
246+
(p : point) (a anything: bounded_coords) (R : _ -> Prop), {
247+
requires t m :=
248+
coords_bounded_by (tight_bounds, tight_bounds, loose_bounds, loose_bounds, loose_bounds) a /\
249+
feval_coords a = coordinates p /\
250+
m =* anything $@ p_out * a $@ p_a * R;
251+
ensures t' m' :=
232252
t = t' /\
233-
exists ox' oy' oz' ota' otb',
234-
((feval ox'), (feval oy'), (feval oz'), (feval ota'), (feval otb')) = coordinates (@m1double p) /\
235-
bounded_by tight_bounds ox' /\
236-
bounded_by tight_bounds oy' /\
237-
bounded_by tight_bounds oz' /\
238-
bounded_by loose_bounds ota' /\ (* could be tight_bounds if we need it, but I don't think we do *)
239-
bounded_by tight_bounds otb' /\
240-
m' =* (FElem XK X) * (FElem YK Y) * (FElem ZK Z) * (FElem TaK Ta) * (FElem TbK Tb) * (FElem oxK ox') * (FElem oyK oy') * (FElem ozK oz') * (FElem otaK ota') * (FElem otbK otb') * R }.
253+
exists a_double : bounded_coords,
254+
coordinates (@m1double p) = feval_coords a_double /\
255+
coords_bounded_by (tight_bounds, tight_bounds, tight_bounds, loose_bounds, tight_bounds) a_double /\
256+
m' =* a_double $@ p_out * a $@ p_a * R
257+
}.
241258

242259
Global Instance spec_of_to_cached: spec_of "to_cached" :=
243260
fnspec! "to_cached"
@@ -309,10 +326,13 @@ Local Arguments word.rep : simpl never.
309326
Local Arguments word.wrap : simpl never.
310327
Local Arguments word.unsigned : simpl never.
311328
Local Arguments word.of_Z : simpl never.
329+
Local Arguments word.add : simpl never.
330+
331+
Local Arguments feval : simpl never.
312332

313333
Local Ltac cbv_bounds H :=
314-
cbv [un_xbounds bin_xbounds bin_ybounds un_square bin_mul bin_add bin_carry_add bin_sub bin_carry_sub un_outbounds bin_outbounds] in H;
315-
cbv [un_xbounds bin_xbounds bin_ybounds un_square bin_mul bin_add bin_carry_add bin_sub bin_carry_sub un_outbounds bin_outbounds].
334+
cbv [coords_bounded_by un_xbounds bin_xbounds bin_ybounds un_square bin_mul bin_add bin_carry_add bin_sub bin_carry_sub un_outbounds bin_outbounds] in H;
335+
cbv [coords_bounded_by un_xbounds bin_xbounds bin_ybounds un_square bin_mul bin_add bin_carry_add bin_sub bin_carry_sub un_outbounds bin_outbounds].
316336

317337
Local Ltac solve_bounds :=
318338
repeat match goal with
@@ -376,22 +396,6 @@ Proof.
376396
reflexivity. (* ...and completes immediately *)
377397
Qed.
378398

379-
Lemma to_cached_ok: program_logic_goal_for_function! to_cached.
380-
Proof.
381-
repeat single_step. repeat straightline.
382-
383-
exists x1, x3, z, x5; ssplit; try solve_bounds; try solve_mem.
384-
385-
destruct p.
386-
cbv [bin_model bin_mul bin_add bin_carry_add bin_sub coordinates proj1_sig] in *.
387-
cbv match beta delta [m1_prep cached_coordinates proj1_sig].
388-
rewrite H31, H28, H26, H22, H20, H16.
389-
simpl. rewrite H6. auto.
390-
391-
(* Without this, resolution of cbv stalls out Qed. *)
392-
Strategy -1000 [un_xbounds bin_xbounds bin_ybounds un_square bin_model cached_coordinates proj1_sig bin_mul bin_add bin_carry_add bin_sub un_outbounds bin_outbounds].
393-
Qed.
394-
395399
Lemma add_precomputed_ok : program_logic_goal_for_function! add_precomputed.
396400
Proof.
397401
(* Without this, resolution of cbv stalls out Qed. *)
@@ -446,53 +450,61 @@ Proof.
446450
(* Without this, resolution of cbv stalls out Qed. *)
447451
Strategy -1000 [un_xbounds bin_xbounds bin_ybounds un_square bin_mul bin_add bin_carry_add bin_sub bin_carry_sub un_outbounds bin_outbounds].
448452

449-
(* Unwrap each call in the program. *)
450-
(* Each binop produces 2 memory goals on the inputs, 2 bounds goals on the inputs, and 1 memory goal on the output. *)
451-
single_step. (* fe25519_square(trX, X) *)
452-
single_step. (* fe25519_square(trZ, Y) *)
453-
single_step. (* fe25519_square(t0, Z) *)
454-
single_step. (* fe25519_carry_add(trT, t0, t0) *)
455-
single_step. (* fe25519_add(rY, X, Y) *)
456-
single_step. (* fe25519_square(t0, rY) *)
457-
single_step. (* fe25519_carry_add(otb, trZ, trX) *)
458-
single_step. (* fe25519_carry_sub(cZ, trZ, trX) *)
459-
single_step. (* fe25519_sub(ota, t0, otb) *)
460-
single_step. (* fe25519_sub(cT, trT, cZ) *)
461-
single_step. (* fe25519_mul(ox, ota, cT) *)
462-
single_step. (* fe25519_mul(oy, otb, cZ) *)
463-
single_step. (* fe25519_mul(oz, cZ, cT) *)
453+
straightline.
454+
destruct a0 as ((((fx, fy), fz), fta), ftb).
455+
destruct p as (((((x, y), z), ta), tb), HP).
456+
destruct anything as ((((ax, ay), az), ata), atb).
457+
cbv beta match delta [feval_coords coords_bounded_by coordinates proj1_sig] in *.
458+
repeat straightline.
459+
inversion H13.
460+
461+
repeat single_step.
464462

465463
(* Solve the postconditions *)
466464
repeat straightline.
467-
(* Rewrites the FElems for the stack (in H87) to be about bytes instead *)
468-
cbv [FElem] in *.
469-
(* Prevent output from being rewritten by seprewrite_in *)
470-
remember (Bignum.Bignum felem_size_in_words ozK _) as Pz in H87.
471-
remember (Bignum.Bignum felem_size_in_words oyK _) as Py in H87.
472-
remember (Bignum.Bignum felem_size_in_words oxK _) as Px in H87.
473-
remember (Bignum.Bignum felem_size_in_words otaK _) as Pta in H87.
474-
remember (Bignum.Bignum felem_size_in_words otbK _) as Ptb in H87.
475-
do 7 (seprewrite_in @Bignum.Bignum_to_bytes H87).
476-
subst Pz Py Px Pta Ptb.
477-
extract_ex1_and_emp_in H87.
465+
466+
(* Now we need to convert scalar to ptsto, because straightline_dealloc can't handle scalar yet. *)
467+
cbv [FElem] in *.
468+
(* Prevent output from being rewritten by seprewrite_in *)
469+
remember (Bignum.Bignum felem_size_in_words (p_out.+80) x12) as Pz in H92.
470+
remember (Bignum.Bignum felem_size_in_words (p_out.+40) x11) as Py in H92.
471+
remember (Bignum.Bignum felem_size_in_words (p_out.+0) x10) as Px in H92.
472+
remember (Bignum.Bignum felem_size_in_words (p_out.+120) x8) as Pta in H92.
473+
remember (Bignum.Bignum felem_size_in_words (p_out.+160) x6) as Ptb in H92.
474+
do 7 (seprewrite_in @Bignum.Bignum_to_bytes H92).
475+
subst Pz Py Px Pta Ptb.
476+
extract_ex1_and_emp_in H92.
478477

479478
(* Solve stack/memory stuff *)
480479
repeat straightline.
481480

482481
(* Post-conditions *)
483-
exists x9,x10,x11,x7,x5; ssplit. 2,3,4,5,6:solve_bounds.
482+
exists (x10,x11,x12,x8,x6); ssplit. 2,3,4,5,6:solve_bounds.
484483
{ (* Correctness: result matches Gallina *)
485484
cbv [bin_model bin_mul bin_add bin_carry_add bin_sub bin_carry_sub un_model un_square] in *.
486-
cbv match beta delta [m1double coordinates proj1_sig].
487-
destruct p. cbv [coordinates proj1_sig] in H12.
488-
rewrite H12.
485+
cbv match zeta beta delta [m1double coordinates proj1_sig].
489486
rewrite F.pow_2_r in *.
490487
congruence.
491488
}
492489
(* Safety: memory is what it should be *)
493490
ecancel_assumption.
494491
Qed.
495492

493+
Lemma to_cached_ok: program_logic_goal_for_function! to_cached.
494+
Proof.
495+
repeat single_step. repeat straightline.
496+
497+
exists x1, x3, z, x5; ssplit; try solve_bounds; try solve_mem.
498+
499+
destruct p.
500+
cbv [bin_model bin_mul bin_add bin_carry_add bin_sub coordinates proj1_sig] in *.
501+
cbv match beta delta [m1_prep cached_coordinates proj1_sig].
502+
rewrite H31, H28, H26, H22, H20, H16.
503+
simpl. rewrite H6. auto.
504+
505+
(* Without this, resolution of cbv stalls out Qed. *)
506+
Strategy -1000 [un_xbounds bin_xbounds bin_ybounds un_square bin_model cached_coordinates proj1_sig bin_mul bin_add bin_carry_add bin_sub un_outbounds bin_outbounds].
507+
Qed.
496508

497509
Lemma readd_ok : program_logic_goal_for_function! readd.
498510
Proof.

0 commit comments

Comments
 (0)