Hacl.Impl.Curve25519.Generic.fst
module Hacl.Impl.Curve25519.Generic
open FStar.HyperStack
open FStar.HyperStack.All
open FStar.Mul
open Lib.IntTypes
open Lib.Buffer
open Lib.ByteBuffer
open Hacl.Impl.Curve25519.Fields
include Hacl.Impl.Curve25519.Finv
include Hacl.Impl.Curve25519.AddAndDouble
module ST = FStar.HyperStack.ST
module BSeq = Lib.ByteSequence
module LSeq = Lib.Sequence
module C = Hacl.Impl.Curve25519.Fields.Core
module S = Spec.Curve25519
module M = Hacl.Spec.Curve25519.AddAndDouble
module Lemmas = Hacl.Spec.Curve25519.Field64.Lemmas
friend Lib.LoopCombinators
#reset-options "--z3rlimit 200 --max_fuel 2 --using_facts_from '* -FStar.Seq -Hacl.Spec.*' --record_options"
//#set-options "--debug Hacl.Impl.Curve25519.Generic --debug_level ExtractNorm"
inline_for_extraction noextract
let scalar = lbuffer uint8 32ul
inline_for_extraction noextract
val scalar_bit:
s:scalar
-> n:size_t{v n < 256}
-> Stack uint64
(requires fun h0 -> live h0 s)
(ensures fun h0 r h1 -> h0 == h1 /\
r == S.ith_bit (as_seq h0 s) (v n) /\ v r <= 1)
let scalar_bit s n =
let h0 = ST.get () in
mod_mask_lemma ((LSeq.index (as_seq h0 s) (v n / 8)) >>. (n %. 8ul)) 1ul;
assert_norm (1 = pow2 1 - 1);
assert (v (mod_mask #U8 #SEC 1ul) == v (u8 1));
to_u64 ((s.(n /. 8ul) >>. (n %. 8ul)) &. u8 1)
inline_for_extraction noextract
val decode_point:
#s:field_spec
-> o:point s
-> i:lbuffer uint8 32ul
-> Stack unit
(requires fun h0 -> live h0 o /\ live h0 i /\ disjoint o i)
(ensures fun h0 _ h1 -> modifies (loc o) h0 h1 /\
state_inv_t h1 (get_x o) /\ state_inv_t h1 (get_z o) /\
fget_x h1 o == S.decodePoint (as_seq h0 i) /\ fget_z h1 o == 1)
[@ Meta.Attribute.specialize ]
let decode_point #s o i =
push_frame();
let tmp = create 4ul (u64 0) in
let h0 = ST.get () in
uints_from_bytes_le #U64 tmp i;
let h1 = ST.get () in
BSeq.uints_from_bytes_le_nat_lemma #U64 #SEC #4 (as_seq h0 i);
assert (BSeq.nat_from_intseq_le (as_seq h1 tmp) == BSeq.nat_from_bytes_le (as_seq h0 i));
let tmp3 = tmp.(3ul) in
tmp.(3ul) <- tmp3 &. u64 0x7fffffffffffffff;
mod_mask_lemma tmp3 63ul;
assert_norm (0x7fffffffffffffff = pow2 63 - 1);
assert (v (mod_mask #U64 #SEC 63ul) == v (u64 0x7fffffffffffffff));
let h2 = ST.get () in
assert (v (LSeq.index (as_seq h2 tmp) 3) < pow2 63);
Lemmas.lemma_felem64_mod255 (as_seq h1 tmp);
assert (BSeq.nat_from_intseq_le (as_seq h2 tmp) == BSeq.nat_from_bytes_le (as_seq h0 i) % pow2 255);
let x : felem s = sub o 0ul (nlimb s) in
let z : felem s = sub o (nlimb s) (nlimb s) in
set_one z;
load_felem x tmp;
pop_frame()
val encode_point:
#s:field_spec
-> o:lbuffer uint8 32ul
-> i:point s
-> Stack unit
(requires fun h0 ->
live h0 o /\ live h0 i /\ disjoint o i /\
state_inv_t h0 (get_x i) /\ state_inv_t h0 (get_z i))
(ensures fun h0 _ h1 -> modifies (loc o) h0 h1 /\
as_seq h1 o == S.encodePoint (fget_x h0 i, fget_z h0 i))
[@ Meta.Attribute.specialize ]
let encode_point #s o i =
push_frame();
let x : felem s = sub i 0ul (nlimb s) in
let z : felem s = sub i (nlimb s) (nlimb s) in
let tmp = create_felem s in
let u64s = create 4ul (u64 0) in
let tmp_w = create (2ul `FStar.UInt32.mul` ((nwide s) <: FStar.UInt32.t)) (wide_zero s) in
let h0 = ST.get () in
finv tmp z tmp_w;
fmul tmp tmp x tmp_w;
let h1 = ST.get () in
assert (feval h1 tmp == S.fmul (S.fpow (feval h0 z) (pow2 255 - 21)) (feval h0 x));
assert (feval h1 tmp == S.fmul (feval h0 x) (S.fpow (feval h0 z) (pow2 255 - 21)));
store_felem u64s tmp;
let h2 = ST.get () in
assert (as_seq h2 u64s == BSeq.nat_to_intseq_le 4 (feval h1 tmp));
uints_to_bytes_le #U64 4ul o u64s;
let h3 = ST.get () in
BSeq.uints_to_bytes_le_nat_lemma #U64 #SEC 4 (feval h1 tmp);
assert (as_seq h3 o == BSeq.nat_to_bytes_le 32 (feval h1 tmp));
pop_frame()
// TODO: why re-define the signature here?
val cswap2:
#s:field_spec
-> bit:uint64{v bit <= 1}
-> p1:felem2 s
-> p2:felem2 s
-> Stack unit
(requires fun h0 ->
live h0 p1 /\ live h0 p2 /\ disjoint p1 p2)
(ensures fun h0 _ h1 ->
modifies (loc p1 |+| loc p2) h0 h1 /\
(v bit == 1 ==> as_seq h1 p1 == as_seq h0 p2 /\ as_seq h1 p2 == as_seq h0 p1) /\
(v bit == 0 ==> as_seq h1 p1 == as_seq h0 p1 /\ as_seq h1 p2 == as_seq h0 p2) /\
(fget_xz h1 p1, fget_xz h1 p2) == S.cswap2 bit (fget_xz h0 p1) (fget_xz h0 p2))
[@ Meta.Attribute.inline_ ]
let cswap2 #s bit p0 p1 =
C.cswap2 #s bit p0 p1
#set-options "--z3rlimit 150 --fuel 0 --ifuel 1"
val ladder_step:
#s:field_spec
-> k:scalar
-> q:point s
-> i:size_t{v i < 251}
-> p01_tmp1_swap:lbuffer (limb s) (8ul *! nlimb s +! 1ul)
-> tmp2:felem_wide2 s
-> Stack unit
(requires fun h0 ->
live h0 k /\ live h0 q /\ live h0 p01_tmp1_swap /\ live h0 tmp2 /\
LowStar.Monotonic.Buffer.all_disjoint [loc k; loc q; loc p01_tmp1_swap; loc tmp2] /\
(let nq = gsub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let nq_p1 = gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
let bit : lbuffer uint64 1ul = gsub p01_tmp1_swap (8ul *! nlimb s) 1ul in
v (LSeq.index (as_seq h0 bit) 0) <= 1 /\
state_inv_t h0 (get_x q) /\ state_inv_t h0 (get_z q) /\
state_inv_t h0 (get_x nq) /\ state_inv_t h0 (get_z nq) /\
state_inv_t h0 (get_x nq_p1) /\ state_inv_t h0 (get_z nq_p1)))
(ensures fun h0 _ h1 ->
modifies (loc p01_tmp1_swap |+| loc tmp2) h0 h1 /\
(let nq = gsub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let nq_p1 = gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
let bit : lbuffer uint64 1ul = gsub p01_tmp1_swap (8ul *! nlimb s) 1ul in
let (p0, p1, b) = S.ladder_step (as_seq h0 k) (fget_xz h0 q) (v i)
(fget_xz h0 nq, fget_xz h0 nq_p1, LSeq.index (as_seq h0 bit) 0) in
p0 == fget_xz h1 nq /\ p1 == fget_xz h1 nq_p1 /\
b == LSeq.index (as_seq h1 bit) 0 /\
v (LSeq.index (as_seq h1 bit) 0) <= 1 /\
state_inv_t h1 (get_x q) /\ state_inv_t h1 (get_z q) /\
state_inv_t h1 (get_x nq) /\ state_inv_t h1 (get_z nq) /\
state_inv_t h1 (get_x nq_p1) /\ state_inv_t h1 (get_z nq_p1)))
[@ Meta.Attribute.inline_ ]
let ladder_step #s k q i p01_tmp1_swap tmp2 =
let p01_tmp1 = sub p01_tmp1_swap 0ul (8ul *! nlimb s) in
let swap : lbuffer uint64 1ul = sub p01_tmp1_swap (8ul *! nlimb s) 1ul in
let nq = sub p01_tmp1 0ul (2ul *! nlimb s) in
let nq_p1 = sub p01_tmp1 (2ul *! nlimb s) (2ul *! nlimb s) in
assert (gsub p01_tmp1_swap 0ul (2ul *! nlimb s) == nq);
assert (gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) == nq_p1);
assert (gsub p01_tmp1 0ul (2ul *! nlimb s) == nq);
assert (gsub p01_tmp1 (2ul *! nlimb s) (2ul *! nlimb s) == nq_p1);
assert (gsub p01_tmp1_swap 0ul (8ul *! nlimb s) == p01_tmp1);
assert (gsub p01_tmp1_swap (8ul *! nlimb s) 1ul == swap);
let h0 = ST.get () in
let bit = scalar_bit k (253ul -. i) in
assert (v bit == v (S.ith_bit (as_seq h0 k) (253 - v i)));
let sw = swap.(0ul) ^. bit in
logxor_lemma1 (LSeq.index (as_seq h0 swap) 0) bit;
cswap2 #s sw nq nq_p1;
point_add_and_double #s q p01_tmp1 tmp2;
swap.(0ul) <- bit
#set-options "--z3rlimit 300 --fuel 1 --ifuel 1"
val ladder_step_loop:
#s:field_spec
-> k:scalar
-> q:point s
-> p01_tmp1_swap:lbuffer (limb s) (8ul *! nlimb s +! 1ul)
-> tmp2:felem_wide2 s
-> Stack unit
(requires fun h0 ->
live h0 k /\ live h0 q /\ live h0 p01_tmp1_swap /\ live h0 tmp2 /\
LowStar.Monotonic.Buffer.all_disjoint [loc k; loc q; loc p01_tmp1_swap; loc tmp2] /\
(let nq = gsub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let nq_p1 = gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
let bit : lbuffer uint64 1ul = gsub p01_tmp1_swap (8ul *! nlimb s) 1ul in
v (LSeq.index (as_seq h0 bit) 0) <= 1 /\
state_inv_t h0 (get_x q) /\ state_inv_t h0 (get_z q) /\
state_inv_t h0 (get_x nq) /\ state_inv_t h0 (get_z nq) /\
state_inv_t h0 (get_x nq_p1) /\ state_inv_t h0 (get_z nq_p1)))
(ensures fun h0 _ h1 ->
modifies (loc p01_tmp1_swap |+| loc tmp2) h0 h1 /\
(let nq = gsub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let nq_p1 = gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
let bit : lbuffer uint64 1ul = gsub p01_tmp1_swap (8ul *! nlimb s) 1ul in
let (p0, p1, b) =
Lib.LoopCombinators.repeati 251
(S.ladder_step (as_seq h0 k) (fget_xz h0 q))
(fget_xz h0 nq, fget_xz h0 nq_p1, LSeq.index (as_seq h0 bit) 0) in
p0 == fget_xz h1 nq /\ p1 == fget_xz h1 nq_p1 /\ b == LSeq.index (as_seq h1 bit) 0 /\
v (LSeq.index (as_seq h1 bit) 0) <= 1 /\
state_inv_t h1 (get_x nq) /\ state_inv_t h1 (get_z nq) /\
state_inv_t h1 (get_x nq_p1) /\ state_inv_t h1 (get_z nq_p1)))
[@ Meta.Attribute.inline_ ]
let ladder_step_loop #s k q p01_tmp1_swap tmp2 =
let h0 = ST.get () in
[@ inline_let]
let spec_fh h0 =
S.ladder_step (as_seq h0 k) (fget_x h0 q, fget_z h0 q) in
[@ inline_let]
let acc h : GTot (tuple3 S.proj_point S.proj_point uint64) =
let nq = gsub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let nq_p1 = gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
let bit : lbuffer uint64 1ul = gsub p01_tmp1_swap (8ul *! nlimb s) 1ul in
(fget_xz h nq, fget_xz h nq_p1, LSeq.index (as_seq h bit) 0) in
[@ inline_let]
let inv h (i:nat{i <= 251}) =
let nq = gsub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let nq_p1 = gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
let bit : lbuffer uint64 1ul = gsub p01_tmp1_swap (8ul *! nlimb s) 1ul in
modifies (loc p01_tmp1_swap |+| loc tmp2) h0 h /\
v (LSeq.index (as_seq h bit) 0) <= 1 /\
state_inv_t h (get_x q) /\ state_inv_t h (get_z q) /\
state_inv_t h (get_x nq) /\ state_inv_t h (get_z nq) /\
state_inv_t h (get_x nq_p1) /\ state_inv_t h (get_z nq_p1) /\
acc h == Lib.LoopCombinators.repeati i (spec_fh h0) (acc h0) in
Lib.Loops.for 0ul 251ul inv
(fun i ->
Lib.LoopCombinators.unfold_repeati 251 (spec_fh h0) (acc h0) (v i);
ladder_step #s k q i p01_tmp1_swap tmp2)
#set-options "--z3refresh --fuel 0 --ifuel 1 --z3rlimit 800"
val ladder0_:
#s:field_spec
-> k:scalar
-> q:point s
-> p01_tmp1_swap:lbuffer (limb s) (8ul *! nlimb s +! 1ul)
-> tmp2:felem_wide2 s
-> Stack unit
(requires fun h0 ->
live h0 k /\ live h0 q /\ live h0 p01_tmp1_swap /\ live h0 tmp2 /\
LowStar.Monotonic.Buffer.all_disjoint [loc k; loc q; loc p01_tmp1_swap; loc tmp2] /\
(let nq = gsub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let nq_p1 = gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
state_inv_t h0 (get_x q) /\ state_inv_t h0 (get_z q) /\
state_inv_t h0 (get_x nq) /\ state_inv_t h0 (get_z nq) /\
state_inv_t h0 (get_x nq_p1) /\ state_inv_t h0 (get_z nq_p1)))
(ensures fun h0 _ h1 ->
modifies (loc p01_tmp1_swap |+| loc tmp2) h0 h1 /\
(let nq = gsub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let nq_p1 = gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
state_inv_t h1 (get_x nq) /\ state_inv_t h1 (get_z nq) /\
fget_xz h1 nq ==
M.montgomery_ladder1_0 (as_seq h0 k) (fget_xz h0 q) (fget_xz h0 nq) (fget_xz h0 nq_p1)))
[@ Meta.Attribute.inline_ ]
let ladder0_ #s k q p01_tmp1_swap tmp2 =
let p01_tmp1 = sub p01_tmp1_swap 0ul (8ul *! nlimb s) in
let nq : point s = sub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let nq_p1 : point s = sub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
let swap:lbuffer uint64 1ul = sub p01_tmp1_swap (8ul *! nlimb s) 1ul in
assert (gsub p01_tmp1_swap 0ul (2ul *! nlimb s) == nq);
assert (gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) == nq_p1);
assert (gsub p01_tmp1 0ul (2ul *! nlimb s) == nq);
assert (gsub p01_tmp1 (2ul *! nlimb s) (2ul *! nlimb s) == nq_p1);
assert (gsub p01_tmp1_swap 0ul (8ul *! nlimb s) == p01_tmp1);
assert (gsub p01_tmp1_swap (8ul *! nlimb s) 1ul == swap);
// bit 255 is 0 and bit 254 is 1
cswap2 #s (u64 1) nq nq_p1;
point_add_and_double #s q p01_tmp1 tmp2;
swap.(0ul) <- u64 1;
//Got about 1K speedup by removing 4 iterations here.
//First iteration can be skipped because top bit of scalar is 0
ladder_step_loop #s k q p01_tmp1_swap tmp2;
let sw = swap.(0ul) in
cswap2 #s sw nq nq_p1
val ladder1_:
#s:field_spec
-> p01_tmp1:lbuffer (limb s) (8ul *! nlimb s)
-> tmp2:felem_wide2 s
-> Stack unit
(requires fun h0 ->
live h0 p01_tmp1 /\ live h0 tmp2 /\ disjoint p01_tmp1 tmp2 /\
(let nq = gsub p01_tmp1 0ul (2ul *! nlimb s) in
state_inv_t h0 (get_x nq) /\ state_inv_t h0 (get_z nq)))
(ensures fun h0 _ h1 ->
modifies (loc p01_tmp1 |+| loc tmp2) h0 h1 /\
(let nq = gsub p01_tmp1 0ul (2ul *! nlimb s) in
state_inv_t h1 (get_x nq) /\ state_inv_t h1 (get_z nq) /\
fget_xz h1 nq == M.montgomery_ladder1_1 (fget_xz h0 nq)))
[@ Meta.Attribute.inline_ ]
let ladder1_ #s p01_tmp1 tmp2 =
let nq : point s = sub p01_tmp1 0ul (2ul *! nlimb s) in
let tmp1 = sub p01_tmp1 (4ul *! nlimb s) (4ul *! nlimb s) in
assert (gsub p01_tmp1 0ul (2ul *! nlimb s) == nq);
assert (gsub p01_tmp1 (4ul *! nlimb s) (4ul *! nlimb s) == tmp1);
point_double nq tmp1 tmp2;
point_double nq tmp1 tmp2;
point_double nq tmp1 tmp2
val ladder2_:
#s:field_spec
-> k:scalar
-> q:point s
-> p01_tmp1_swap:lbuffer (limb s) (8ul *! nlimb s +! 1ul)
-> tmp2:felem_wide2 s
-> Stack unit
(requires fun h0 ->
live h0 k /\ live h0 q /\ live h0 p01_tmp1_swap /\ live h0 tmp2 /\
LowStar.Monotonic.Buffer.all_disjoint [loc k; loc q; loc p01_tmp1_swap; loc tmp2] /\
(let nq = gsub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let nq_p1 = gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
state_inv_t h0 (get_x q) /\ state_inv_t h0 (get_z q) /\
state_inv_t h0 (get_x nq) /\ state_inv_t h0 (get_z nq) /\
state_inv_t h0 (get_x nq_p1) /\ state_inv_t h0 (get_z nq_p1)))
(ensures fun h0 _ h1 ->
modifies (loc p01_tmp1_swap |+| loc tmp2) h0 h1 /\
(let nq = gsub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let nq_p1 = gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
state_inv_t h1 (get_x nq) /\ state_inv_t h1 (get_z nq) /\
(let nq' = M.montgomery_ladder1_0 (as_seq h0 k) (fget_xz h0 q) (fget_xz h0 nq) (fget_xz h0 nq_p1) in
fget_xz h1 nq == M.montgomery_ladder1_1 nq')))
[@ Meta.Attribute.inline_ ]
let ladder2_ #s k q p01_tmp1_swap tmp2 =
let p01_tmp1 = sub p01_tmp1_swap 0ul (8ul *! nlimb s) in
let nq : point s = sub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let nq_p1 : point s = sub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
assert (gsub p01_tmp1_swap 0ul (8ul *! nlimb s) == p01_tmp1);
assert (gsub p01_tmp1_swap 0ul (2ul *! nlimb s) == nq);
assert (gsub p01_tmp1 0ul (2ul *! nlimb s) == nq);
assert (gsub p01_tmp1 (2ul *! nlimb s) (2ul *! nlimb s) == nq_p1);
assert (gsub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) == nq_p1);
ladder0_ #s k q p01_tmp1_swap tmp2;
ladder1_ #s p01_tmp1 tmp2
inline_for_extraction noextract
val ladder3_:
#s:field_spec
-> q:point s
-> p01:lbuffer (limb s) (4ul *! nlimb s)
-> Stack unit
(requires fun h0 ->
live h0 q /\ live h0 p01 /\ disjoint q p01 /\
fget_z h0 q == 1 /\ state_inv_t h0 (get_x q) /\ state_inv_t h0 (get_z q))
(ensures fun h0 _ h1 ->
modifies (loc p01) h0 h1 /\
(let nq = gsub p01 0ul (2ul *! nlimb s) in
let nq_p1 = gsub p01 (2ul *! nlimb s) (2ul *! nlimb s) in
state_inv_t h1 (get_x q) /\ state_inv_t h1 (get_z q) /\
state_inv_t h1 (get_x nq) /\ state_inv_t h1 (get_z nq) /\
state_inv_t h1 (get_x nq_p1) /\ state_inv_t h1 (get_z nq_p1) /\
(fget_xz h1 q, fget_xz h1 nq, fget_xz h1 nq_p1) == M.montgomery_ladder1_2 (fget_x h0 q)))
let ladder3_ #s q p01 =
let p0 : point s = sub p01 0ul (2ul *! nlimb s) in
let p1 : point s = sub p01 (2ul *! nlimb s) (2ul *! nlimb s) in
copy p1 q;
let x0 : felem s = sub p0 0ul (nlimb s) in
let z0 : felem s = sub p0 (nlimb s) (nlimb s) in
set_one x0;
set_zero z0;
let h0 = ST.get () in
assert (gsub p01 0ul (2ul *! nlimb s) == p0);
assert (gsub p01 (2ul *! nlimb s) (2ul *! nlimb s) == p1);
assert (gsub p0 0ul (nlimb s) == x0);
assert (gsub p0 (nlimb s) (nlimb s) == z0);
assert (fget_x h0 p1 == fget_x h0 q);
assert (fget_z h0 p1 == 1);
assert (fget_x h0 p0 == 1);
assert (fget_z h0 p0 == 0);
assert (
state_inv_t h0 (get_x q) /\ state_inv_t h0 (get_z q) /\
state_inv_t h0 (get_x p0) /\ state_inv_t h0 (get_z p0) /\
state_inv_t h0 (get_x p1) /\ state_inv_t h0 (get_z p1))
val ladder4_:
#s:field_spec
-> k:scalar
-> q:point s
-> p01_tmp1_swap:lbuffer (limb s) (8ul *! nlimb s +! 1ul)
-> tmp2:felem_wide2 s
-> Stack unit
(requires fun h0 ->
live h0 k /\ live h0 q /\ live h0 p01_tmp1_swap /\ live h0 tmp2 /\
LowStar.Monotonic.Buffer.all_disjoint [loc k; loc q; loc p01_tmp1_swap; loc tmp2] /\
fget_z h0 q == 1 /\ state_inv_t h0 (get_x q) /\ state_inv_t h0 (get_z q))
(ensures fun h0 _ h1 ->
modifies (loc p01_tmp1_swap |+| loc tmp2) h0 h1 /\
(let nq = gsub p01_tmp1_swap 0ul (2ul *! nlimb s) in
state_inv_t h1 (get_x nq) /\ state_inv_t h1 (get_z nq) /\
fget_xz h1 nq == S.montgomery_ladder (fget_x h0 q) (as_seq h0 k)))
[@ Meta.Attribute.inline_ ]
let ladder4_ #s k q p01_tmp1_swap tmp2 =
let h0 = ST.get () in
let p01 = sub p01_tmp1_swap 0ul (4ul *! nlimb s) in
let p0 : point s = sub p01_tmp1_swap 0ul (2ul *! nlimb s) in
let p1 : point s = sub p01_tmp1_swap (2ul *! nlimb s) (2ul *! nlimb s) in
assert (gsub p01_tmp1_swap 0ul (4ul *! nlimb s) == p01);
assert (gsub p01 0ul (2ul *! nlimb s) == p0);
assert (gsub p01 (2ul *! nlimb s) (2ul *! nlimb s) == p1);
ladder3_ #s q p01;
ladder2_ #s k q p01_tmp1_swap tmp2;
let h1 = ST.get () in
assert (fget_xz h1 p0 == M.montgomery_ladder1 (fget_x h0 q) (as_seq h0 k));
M.lemma_montgomery_ladder (fget_x h0 q) (as_seq h0 k)
val montgomery_ladder:
#s:field_spec
-> o:point s
-> k:scalar
-> i:point s
-> Stack unit
(requires fun h0 ->
live h0 o /\ live h0 k /\ live h0 i /\
(disjoint o i \/ o == i) /\ disjoint o k /\ disjoint k i /\
fget_z h0 i == 1 /\ state_inv_t h0 (get_x i) /\ state_inv_t h0 (get_z i))
(ensures fun h0 _ h1 ->
modifies (loc o) h0 h1 /\
state_inv_t h1 (get_x o) /\ state_inv_t h1 (get_z o) /\
fget_xz h1 o == S.montgomery_ladder (fget_x h0 i) (as_seq h0 k))
[@ Meta.Attribute.specialize ]
let montgomery_ladder #s out key init =
push_frame();
let h0 = ST.get () in
let tmp2 = create (2ul `FStar.UInt32.mul` ((nwide s) <: FStar.UInt32.t)) (wide_zero s) in
let p01_tmp1_swap = create (8ul *! nlimb s +! 1ul) (limb_zero s) in
let p0 : point s = sub p01_tmp1_swap 0ul (2ul *! nlimb s) in
assert (gsub p01_tmp1_swap 0ul (2ul *! nlimb s) == p0);
ladder4_ #s key init p01_tmp1_swap tmp2;
copy out p0;
pop_frame ()
#set-options "--fuel 0 --ifuel 1 --z3rlimit 300"
inline_for_extraction noextract
let g25519_t = x:glbuffer byte_t 32ul{witnessed x (Lib.Sequence.of_list S.basepoint_list) /\ recallable x}
/// Public API
/// ==========
val scalarmult: (#s: field_spec) -> scalarmult_st s True
[@ Meta.Attribute.specialize ]
let scalarmult #s out priv pub =
push_frame ();
let init = create (2ul `FStar.UInt32.mul` ((nlimb s) <: FStar.UInt32.t)) (limb_zero s) in
decode_point #s init pub;
montgomery_ladder #s init priv init;
encode_point #s out init;
pop_frame()
val secret_to_public (#s:field_spec) (g25519: g25519_t): secret_to_public_st s True
[@ Meta.Attribute.specialize ]
let secret_to_public #s g25519 pub priv =
push_frame ();
recall_contents g25519 S.basepoint_lseq;
let basepoint = create 32ul (u8 0) in
mapT 32ul basepoint secret g25519;
scalarmult #s pub priv basepoint;
pop_frame()
val ecdh: (#s:field_spec) -> ecdh_st s True
[@ Meta.Attribute.specialize ]
let ecdh #s out priv pub =
push_frame ();
let zeros = create 32ul (u8 0) in
scalarmult #s out priv pub;
let r = lbytes_eq #32ul out zeros in
pop_frame();
not r