https://github.com/project-everest/hacl-star
Tip revision: 7b8ff286676eb6022b8c24474916188a857b53c3 authored by Aseem Rastogi on 27 September 2018, 16:08:56 UTC
hints
hints
Tip revision: 7b8ff28
Spec.CTR3.fst
module Spec.CTR3
module ST = FStar.HyperStack.ST
open FStar.HyperStack.All
open FStar.Mul
open FStar.Seq
open Spec.Lib
open Spec.CTR
#reset-options "--max_fuel 0"
val counter_mode_blocks3:
k:key Spec.Chacha20_vec.chacha20_ctx ->
n:nonce Spec.Chacha20_vec.chacha20_ctx ->
c:counter Spec.Chacha20_vec.chacha20_ctx ->
plain:seq UInt8.t ->
len:nat{192 * len = length plain /\ c + 3 * len < pow2 32} ->
Tot (lbytes (length plain))
(decreases (len))
#reset-options "--z3rlimit 20 --max_fuel 0"
let rec counter_mode_blocks3 key nonce counter plain len =
if len = 0 then Seq.empty #UInt8.t
else (
assert(length plain >= 192);
let prefix, block = split plain (length plain - 192) in
let cipher = counter_mode_blocks3 key nonce counter prefix (len - 1) in
let mask0 = Spec.Chacha20_vec.chacha20_block key nonce (counter + 3 * len - 3) in
let mask1 = Spec.Chacha20_vec.chacha20_block key nonce (counter + 3 * len - 2) in
let mask2 = Spec.Chacha20_vec.chacha20_block key nonce (counter + 3 * len - 1) in
let block0 = slice block 0 64 in
let block1 = slice block 64 128 in
let block2 = slice block 128 192 in
let cipher0 = xor #64 block0 mask0 in
let cipher1 = xor #64 block1 mask1 in
let cipher2 = xor #64 block2 mask2 in
let eb = cipher0 @| cipher1 @| cipher2 in
cipher @| eb
)
val counter_mode_blocks:
k:key Spec.Chacha20_vec.chacha20_ctx ->
n:nonce Spec.Chacha20_vec.chacha20_ctx ->
c:counter Spec.Chacha20_vec.chacha20_ctx ->
plain:seq UInt8.t ->
len:nat{64 * len = length plain /\ c + len < pow2 32} ->
Tot (lbytes (length plain))
#reset-options "--z3rlimit 20 --max_fuel 0"
let counter_mode_blocks key nonce counter plain len =
let len3 = len / 3 in
let rest3 = len % 3 in
let plain3, plain3' = split plain (len3 * 192) in
let cipher3 = counter_mode_blocks3 key nonce counter plain3 len3 in
let cipher3' =
if rest3 = 2 then
let mask0 = Spec.Chacha20_vec.chacha20_block key nonce (counter + 3 * len3) in
let mask1 = Spec.Chacha20_vec.chacha20_block key nonce (counter + 3 * len3 + 1) in
let mask = mask0 @| mask1 in
let block0 = slice plain3' 0 64 in
let block1 = slice plain3' 64 128 in
let cipher0 = xor #64 block0 mask0 in
let cipher1 = xor #64 block1 mask1 in
cipher0 @| cipher1
else if rest3 = 1 then
let mask = Spec.Chacha20_vec.chacha20_block key nonce (counter + 3 * len3) in
xor #64 plain3' mask
else empty in
cipher3 @| cipher3'
val counter_mode:
k:key Spec.Chacha20_vec.chacha20_ctx ->
n:nonce Spec.Chacha20_vec.chacha20_ctx ->
c:counter Spec.Chacha20_vec.chacha20_ctx ->
plain:seq UInt8.t{c + length plain / 64 < pow2 32} ->
Tot (lbytes (length plain))
#reset-options "--z3rlimit 20 --max_fuel 0"
let counter_mode key nonce counter plain =
let len = length plain in
let len64 = len / 64 in
let blocks_len = 64 * (len / 64) in
let part_len = len % 64 in
let blocks, last_block = split plain blocks_len in
let cipher_blocks = counter_mode_blocks key nonce counter blocks len64 in
let cipher_last_block =
if part_len > 0
then (* encrypt final partial block(s) *)
let mask = Spec.Chacha20_vec.chacha20_block key nonce (counter+len64) in
let mask = slice mask 0 part_len in
assert(length last_block = part_len);
xor #part_len last_block mask
else empty in
cipher_blocks @| cipher_last_block
val lemma_counter_mode_blocks_def1:
k:key Spec.Chacha20_vec.chacha20_ctx ->
n:nonce Spec.Chacha20_vec.chacha20_ctx ->
c:counter Spec.Chacha20_vec.chacha20_ctx ->
plain:seq UInt8.t ->
len:nat{64 * len = length plain /\ c + len < pow2 32 /\ length plain >= 64} ->
Lemma (Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx
Spec.Chacha20_vec.chacha20_cipher k n c plain ==
(let len = length plain in
let len' = len / 64 in
let prefix, block = split plain (len - 64) in
Math.Lemmas.lemma_mod_plus (length prefix) 1 (64);
Math.Lemmas.lemma_div_le (length prefix) len 64;
Spec.CTR.Lemmas.lemma_div len (64);
let cipher = Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx
Spec.Chacha20_vec.chacha20_cipher
k n c prefix in
let mask = Spec.Chacha20_vec.chacha20_block k n (c+(len/64-1)) in
let eb = xor block mask in
cipher @| eb))
#reset-options "--z3rlimit 200 --max_fuel 1"
let lemma_counter_mode_blocks_def1 k n c plain len =
assert(len > 0)
#reset-options "--z3rlimit 20 --max_fuel 0"
val lemma_counter_mode_blocks_def0:
k:key Spec.Chacha20_vec.chacha20_ctx ->
n:nonce Spec.Chacha20_vec.chacha20_ctx ->
c:counter Spec.Chacha20_vec.chacha20_ctx ->
plain:seq UInt8.t{length plain = 0} ->
Lemma (Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx
Spec.Chacha20_vec.chacha20_cipher k n c plain ==
empty)
#reset-options "--z3rlimit 200 --max_fuel 1"
let lemma_counter_mode_blocks_def0 k n c plain = ()
#reset-options "--z3rlimit 20 --max_fuel 0"
val lemma_counter_mode_blocks3_def1:
k:key Spec.Chacha20_vec.chacha20_ctx ->
n:nonce Spec.Chacha20_vec.chacha20_ctx ->
c:counter Spec.Chacha20_vec.chacha20_ctx ->
plain:seq UInt8.t ->
len:nat{192 * len = length plain /\ c + 3 * len < pow2 32 /\ len > 0} ->
Lemma (counter_mode_blocks3 k n c plain len ==
(let prefix, block = split plain (length plain - 192) in
let cipher = counter_mode_blocks3 k n c prefix (len - 1) in
let mask0 = Spec.Chacha20_vec.chacha20_block k n (c + 3 * len - 3) in
let mask1 = Spec.Chacha20_vec.chacha20_block k n (c + 3 * len - 2) in
let mask2 = Spec.Chacha20_vec.chacha20_block k n (c + 3 * len - 1) in
let block0 = slice block 0 64 in
let block1 = slice block 64 128 in
let block2 = slice block 128 192 in
let cipher0 = xor #64 block0 mask0 in
let cipher1 = xor #64 block1 mask1 in
let cipher2 = xor #64 block2 mask2 in
let eb = cipher0 @| cipher1 @| cipher2 in
cipher @| eb))
#reset-options "--z3rlimit 200 --max_fuel 1"
let lemma_counter_mode_blocks3_def1 k n c plain len = ()
#reset-options "--z3rlimit 20 --max_fuel 0"
val lemma_counter_mode_blocks3_def0:
k:key Spec.Chacha20_vec.chacha20_ctx ->
n:nonce Spec.Chacha20_vec.chacha20_ctx ->
c:counter Spec.Chacha20_vec.chacha20_ctx ->
plain:seq UInt8.t{length plain = 0} ->
Lemma (counter_mode_blocks3 k n c plain 0 == empty)
#reset-options "--z3rlimit 200 --max_fuel 1"
let lemma_counter_mode_blocks3_def0 k n c plain = ()
#reset-options "--z3rlimit 20 --max_fuel 0"
val lemma_counter_mode_blocks3_eq:
k:key Spec.Chacha20_vec.chacha20_ctx ->
n:nonce Spec.Chacha20_vec.chacha20_ctx ->
c:counter Spec.Chacha20_vec.chacha20_ctx ->
plain:seq UInt8.t ->
len:nat{192 * len = length plain /\ c + 3 * len < pow2 32} ->
Lemma (requires (True))
(ensures (Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_cipher k n c plain == counter_mode_blocks3 k n c plain len))
(decreases len)
#reset-options "--z3rlimit 200 --max_fuel 0"
let rec lemma_counter_mode_blocks3_eq k n c plain len =
if len = 0 then (
lemma_counter_mode_blocks3_def0 k n c plain;
lemma_counter_mode_blocks_def0 k n c plain)
else (
let mask0 = Spec.Chacha20_vec.chacha20_block k n (c + 3 * len - 3) in
let mask1 = Spec.Chacha20_vec.chacha20_block k n (c + 3 * len - 2) in
let mask2 = Spec.Chacha20_vec.chacha20_block k n (c + 3 * len - 1) in
let prefix, blocks = split plain (length plain - 192) in
let block0 = slice blocks 0 64 in
let block1 = slice blocks 64 128 in
let block2 = slice blocks 128 192 in
let cipher0 = xor #64 block0 mask0 in
let cipher1 = xor #64 block1 mask1 in
let cipher2 = xor #64 block2 mask2 in
lemma_counter_mode_blocks3_eq k n c prefix (len - 1);
let cipher = counter_mode_blocks3 k n c plain len in
lemma_eq_intro plain (((prefix @| block0) @| block1) @| block2);
lemma_counter_mode_blocks_def1 k n c (((prefix @| block0) @| block1) @| block2) (3 * len);
lemma_counter_mode_blocks_def1 k n c ((prefix @| block0) @| block1) (3 * len - 1);
lemma_counter_mode_blocks_def1 k n c (prefix @| block0) (3 * len - 2);
let x = Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_block k n c plain in
let y = Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_block k n c ((prefix @| block0) @| block1) in
let z = Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_block k n c ((prefix @| block0)) in
let w = Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_block k n c prefix in
let pre, block = split plain ((3 * len) * 64 - 64) in
lemma_eq_intro block (slice blocks 128 192);
lemma_eq_intro pre ((prefix @| block0) @| block1);
Math.Lemmas.lemma_mod_plus (length pre) 1 (64);
Math.Lemmas.lemma_div_le (length pre) (length plain) 64;
Spec.CTR.Lemmas.lemma_div (length plain) (64);
assert(c + (length plain / 64 - 1) = c + 3 * len - 1);
assert(c + ((length plain - 64) / 64 - 1) = c + 3 * len - 2);
assert(c + ((length plain - 128) / 64 - 1) = c + 3 * len - 3);
let mask' = Spec.Chacha20_vec.chacha20_block k n (c + (length plain / 64) - 1) in
let cip = xor #64 block mask' in
lemma_eq_intro cip cipher2;
lemma_eq_intro (y @| cipher2) x;
let pre, block = split ((prefix @| block0) @| block1) ((3 * len - 1) * 64 - 64) in
lemma_eq_intro block block1;
lemma_eq_intro pre ((prefix @| block0));
lemma_eq_intro (z @| cipher1) y;
let pre, block = split ((prefix @| block0)) ((3 * len - 2) * 64 - 64) in
lemma_eq_intro block block0;
lemma_eq_intro pre ((prefix));
lemma_eq_intro (w @| cipher0) z;
lemma_counter_mode_blocks3_def1 k n c plain len;
lemma_eq_intro (slice (((prefix @| block0) @| block1) @| block2) (length plain - 64) (length plain)) block2;
lemma_eq_intro (slice (((prefix @| block0) @| block1)) (length plain - 128) (length plain - 64)) block1;
lemma_eq_intro (slice (((prefix @| block0))) (length plain - 192) (length plain - 128)) block0;
let cipher'' = Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_block k n c prefix in
let cipher' = cipher0 @| cipher1 @| cipher2 in
lemma_eq_intro cipher' (slice cipher (length plain - 192) (length plain));
lemma_eq_intro cipher'' (slice cipher 0 (length prefix));
lemma_eq_intro (cipher') (cipher0 @| cipher1 @| cipher2);
lemma_eq_intro (cipher @| (cipher0 @| cipher1 @| cipher2)) (((cipher @| cipher0) @| cipher1) @| cipher2);
lemma_eq_intro x (y @| cipher2);
lemma_eq_intro x (w @| (cipher0 @| cipher1 @| cipher2));
lemma_eq_intro (Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_cipher k n c plain) (counter_mode_blocks3 k n c plain len)
)
val lemma_counter_mode_blocks_eq:
k:key Spec.Chacha20_vec.chacha20_ctx ->
n:nonce Spec.Chacha20_vec.chacha20_ctx ->
c:counter Spec.Chacha20_vec.chacha20_ctx ->
plain:seq UInt8.t ->
len:nat{64 * len = length plain /\ c + len < pow2 32} ->
Lemma (Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_cipher k n c plain == counter_mode_blocks k n c plain len)
#reset-options "--z3rlimit 200 --max_fuel 0"
let lemma_counter_mode_blocks_eq k n c plain len =
let len3 = len / 3 in
let rest3 = len % 3 in
let plain3, plain3' = split plain (len3 * 192) in
lemma_counter_mode_blocks3_eq k n c plain3 len3;
let cipher3 = counter_mode_blocks3 k n c plain3 len3 in
if rest3 = 2 then (
assert(c + ((length plain - 64) / 64 - 3) = c + 3 * len3 - 2);
let mask0 = Spec.Chacha20_vec.chacha20_block k n (c + length plain / 64 - 2) in
let mask1 = Spec.Chacha20_vec.chacha20_block k n (c + length plain / 64 - 1) in
let prefix, blocks = split plain (length plain - 128) in
let block0 = slice blocks 0 64 in
let block1 = slice blocks 64 128 in
let cipher0 = xor #64 block0 mask0 in
let cipher1 = xor #64 block1 mask1 in
lemma_eq_intro plain (((prefix @| block0) @| block1));
lemma_counter_mode_blocks_def1 k n c ((prefix @| block0) @| block1) (length plain / 64);
lemma_counter_mode_blocks_def1 k n c (prefix @| block0) (length plain / 64 - 1);
let x = Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_block k n c plain in
let y = Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_block k n c ((prefix @| block0)) in
let z = Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_block k n c prefix in
let pre, block = split plain (length plain - 64) in
lemma_eq_intro block (slice blocks 64 128);
lemma_eq_intro pre ((prefix @| block0));
Math.Lemmas.lemma_mod_plus (length pre) 1 (64);
Math.Lemmas.lemma_div_le (length pre) (length plain) 64;
Spec.CTR.Lemmas.lemma_div (length plain) (64);
let mask' = Spec.Chacha20_vec.chacha20_block k n (c + (length plain / 64) - 1) in
let cip = xor #64 block mask' in
lemma_eq_intro cip cipher1;
lemma_eq_intro (y @| cipher1) x;
let pre, block = split (prefix @| block0) (length plain - 128) in
lemma_eq_intro block block0;
lemma_eq_intro pre prefix;
lemma_eq_intro pre plain3;
lemma_eq_intro (z @| cipher0) y;
lemma_eq_intro x (z @| (cipher0 @| cipher1));
lemma_eq_intro (Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_cipher k n c plain) (counter_mode_blocks k n c plain len)
)
else if rest3 = 1 then (
lemma_counter_mode_blocks_def1 k n c plain (length plain / 64);
lemma_eq_intro (Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_cipher k n c plain) (counter_mode_blocks k n c plain len)
) else (
assert(rest3 = 0);
let x = Spec.CTR.counter_mode_blocks Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_cipher k n c plain in
let x' = counter_mode_blocks k n c plain len in
lemma_eq_intro cipher3 (cipher3 @| empty);
lemma_eq_intro cipher3 (cipher3 @| empty);
lemma_eq_intro plain plain3)
val lemma_counter_mode3_eq:
k:key Spec.Chacha20_vec.chacha20_ctx ->
n:nonce Spec.Chacha20_vec.chacha20_ctx ->
c:counter Spec.Chacha20_vec.chacha20_ctx ->
plain:seq UInt8.t{c + length plain / 64 < pow2 32} ->
Lemma (Spec.CTR.counter_mode Spec.Chacha20_vec.chacha20_ctx Spec.Chacha20_vec.chacha20_cipher k n c plain == counter_mode k n c plain)
let lemma_counter_mode3_eq k n c plain =
let len = length plain / 64 in
let plain, _ = split plain (64 * len) in
lemma_counter_mode_blocks_eq k n c plain len