module Hacl.Impl.Ed25519.Pow2_252m2
open FStar.HyperStack.All
module ST = FStar.HyperStack.ST
open FStar.Mul
open Lib.IntTypes
open Lib.Buffer
open Hacl.Bignum25519
module F51 = Hacl.Impl.Ed25519.Field51
module SC = Spec.Curve25519
module CI = Hacl.Spec.Curve25519.Finv
#set-options "--z3rlimit 500 --max_fuel 0 --max_ifuel 0"
inline_for_extraction noextract
val crecip_1:
out:felem
-> buf:lbuffer uint64 20ul
-> z:felem ->
Stack unit
(requires fun h -> live h out /\ live h buf /\ live h z /\
disjoint buf z /\ disjoint out z /\ disjoint out buf /\
F51.mul_inv_t h z)
(ensures fun h0 _ h1 ->
modifies (loc buf) h0 h1 /\
F51.mul_inv_t h1 (gsub buf 10ul 5ul) /\
F51.felem_fits h1 (gsub buf 5ul 5ul) (1, 2, 1, 1, 1) /\
F51.fevalh h1 (gsub buf 5ul 5ul) == CI.pow (F51.fevalh h0 z) 1267650600228228275596796362752 /\
F51.fevalh h1 (gsub buf 10ul 5ul) == CI.pow (F51.fevalh h0 z) 1125899906842623
)
let crecip_1 out buf z =
let a = sub buf 0ul 5ul in
let t0 = sub buf 5ul 5ul in
let b = sub buf 10ul 5ul in
let c = sub buf 15ul 5ul in
(**) let h0 = get() in
fsquare_times a z 1ul; // a = z ** (2 ** 1) == z ** 2
(**) assert_norm (pow2 1 == 2);
fsquare_times t0 a 2ul; // t0 == a ** (2 ** 2) == (z ** 2) ** 4 == z ** 8
(**) CI.lemma_pow_mul (F51.fevalh h0 z) 2 4;
(**) assert_norm (pow2 2 == 4);
fmul b t0 z; // b == z0 ** 9
(**) CI.lemma_pow_one (F51.fevalh h0 z);
(**) CI.lemma_pow_add (F51.fevalh h0 z) 8 1;
fmul a b a; // a == b * a == z ** 11
(**) CI.lemma_pow_add (F51.fevalh h0 z) 9 2;
fsquare_times t0 a 1ul; // t0 == a ** 2 == z ** 22
(**) CI.lemma_pow_mul (F51.fevalh h0 z) 11 2;
fmul b t0 b; // b == z ** 31
(**) CI.lemma_pow_add (F51.fevalh h0 z) 22 9;
fsquare_times t0 b 5ul; // t0 == b ** (2 ** 5) == z ** 992
(**) assert_norm (pow2 5 == 32);
(**) CI.lemma_pow_mul (F51.fevalh h0 z) 31 32;
fmul b t0 b; // b == t0 * b == z ** 1023
(**) CI.lemma_pow_add (F51.fevalh h0 z) 992 31;
fsquare_times t0 b 10ul; // t0 = b ** (2 ** 1024) == z ** 1047552
(**) assert_norm (pow2 10 == 1024);
(**) CI.lemma_pow_mul (F51.fevalh h0 z) 1023 1024;
fmul c t0 b; // c == z ** 1048575
(**) CI.lemma_pow_add (F51.fevalh h0 z) 1047552 1023;
fsquare_times t0 c 20ul; // t0 == c ** (2 ** 20) == 1099510579200
(**) assert_norm (pow2 20 == 1048576);
(**) CI.lemma_pow_mul (F51.fevalh h0 z) 1048575 1048576;
fmul t0 t0 c; // t0 == z ** 1099511627775
(**) CI.lemma_pow_add (F51.fevalh h0 z) 1099510579200 1048575;
fsquare_times_inplace t0 10ul; // t0 == z ** 1125899906841600
(**) CI.lemma_pow_mul (F51.fevalh h0 z) 1099511627775 1024;
fmul b t0 b; // b == z ** 1125899906842623
(**) CI.lemma_pow_add (F51.fevalh h0 z) 1125899906841600 1023;
fsquare_times t0 b 50ul; // t0 == z ** 1267650600228228275596796362752;
(**) assert_norm (pow2 50 = 1125899906842624);
(**) CI.lemma_pow_mul (F51.fevalh h0 z) 1125899906842623 1125899906842624
inline_for_extraction noextract
val crecip_2:
out:felem
-> buf:lbuffer uint64 20ul
-> z:felem ->
Stack unit
(requires fun h -> live h out /\ live h buf /\ live h z /\
disjoint buf z /\ disjoint out z /\ disjoint out buf /\
F51.mul_inv_t h (gsub buf 10ul 5ul) /\
F51.felem_fits h (gsub buf 5ul 5ul) (1, 2, 1, 1, 1) /\
F51.fevalh h (gsub buf 5ul 5ul) == CI.pow (F51.fevalh h z) 1267650600228228275596796362752 /\
F51.fevalh h (gsub buf 10ul 5ul) == CI.pow (F51.fevalh h z) 1125899906842623 /\
F51.mul_inv_t h z)
(ensures fun h0 _ h1 ->
modifies (loc buf |+| loc out) h0 h1 /\
F51.mul_inv_t h1 out /\
F51.fevalh h1 out == CI.pow (F51.fevalh h0 z) 7237005577332262213973186563042994240829374041602535252466099000494570602494
)
let crecip_2 out buf z =
let a = sub buf 0ul 5ul in
let t0 = sub buf 5ul 5ul in
let b = sub buf 10ul 5ul in
let c = sub buf 15ul 5ul in
let h0 = get() in
(**) assert_norm (pow2 1 == 2);
fsquare_times a z 1ul; // a == z ** 2;
fmul c t0 b; // c == z ** 1267650600228229401496703205375
(**) CI.lemma_pow_add (F51.fevalh h0 z) 1267650600228228275596796362752 1125899906842623;
fsquare_times t0 c 100ul; // t0 == z ** 1606938044258990275541962092339894951921974764381296132096000
(**) assert_norm (pow2 100 = 1267650600228229401496703205376);
(**) CI.lemma_pow_mul (F51.fevalh h0 z) 1267650600228229401496703205375 1267650600228229401496703205376;
fmul t0 t0 c; // t0 == z ** 1606938044258990275541962092341162602522202993782792835301375
(**) CI.lemma_pow_add (F51.fevalh h0 z) 1606938044258990275541962092339894951921974764381296132096000 1267650600228229401496703205375;
(**) assert_norm (pow2 50 == 1125899906842624);
fsquare_times_inplace t0 50ul; // t0 == z ** 1809251394333065553493296640760748560207343510400633813116523624223735808000
(**) CI.lemma_pow_mul (F51.fevalh h0 z) 1606938044258990275541962092341162602522202993782792835301375 1125899906842624;
fmul t0 t0 b; // t0 == z ** 1809251394333065553493296640760748560207343510400633813116524750123642650623
(**) CI.lemma_pow_add (F51.fevalh h0 z) 1809251394333065553493296640760748560207343510400633813116523624223735808000 1125899906842623;
(**) assert_norm (pow2 2 == 4);
fsquare_times_inplace t0 2ul; // t0 == z ** 7237005577332262213973186563042994240829374041602535252466099000494570602492
(**) CI.lemma_pow_mul (F51.fevalh h0 z) 1809251394333065553493296640760748560207343510400633813116524750123642650623 4;
fmul out t0 a;
(**) CI.lemma_pow_add (F51.fevalh h0 z) 7237005577332262213973186563042994240829374041602535252466099000494570602492 2
val pow2_252m2:
out:felem
-> z:felem ->
Stack unit
(requires fun h -> live h out /\ live h z /\ disjoint out z /\ F51.mul_inv_t h z)
(ensures fun h0 _ h1 -> modifies (loc out) h0 h1 /\
F51.mul_inv_t h1 out /\
F51.fevalh h1 out == F51.fevalh h0 z `SC.fpow` ((SC.prime + 3) / 8)
)
let pow2_252m2 out z =
push_frame();
let buf = create 20ul (u64 0) in
let h0 = get() in
crecip_1 out buf z;
crecip_2 out buf z;
CI.lemma_fpow_is_pow (F51.fevalh h0 z) 7237005577332262213973186563042994240829374041602535252466099000494570602494;
assert_norm (7237005577332262213973186563042994240829374041602535252466099000494570602494 == (SC.prime + 3) / 8);
pop_frame()