https://github.com/project-everest/hacl-star
Raw File
Tip revision: 7b8ff286676eb6022b8c24474916188a857b53c3 authored by Aseem Rastogi on 27 September 2018, 16:08:56 UTC
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
back to top