https://github.com/project-everest/hacl-star
Raw File
Tip revision: f95b54abf9076a7a072a54750b40dc9f85039b74 authored by Dzomo, the Everest Yak on 01 October 2021, 08:30:56 UTC
[CI] regenerate hints and dist
Tip revision: f95b54a
Hacl.Hash.Definitions.fst
module Hacl.Hash.Definitions

module HS = FStar.HyperStack
module ST = FStar.HyperStack.ST

module M = LowStar.Modifies
module B = LowStar.Buffer
module Spec = Spec.Hash.PadFinish
module Blake2 = Hacl.Impl.Blake2.Core

open Lib.IntTypes
open Spec.Hash.Definitions
open FStar.Mul

#set-options "--z3rlimit 25 --fuel 0 --ifuel 1"

(** The low-level types that our clients need to be aware of, in order to
    successfully call this module. *)

inline_for_extraction noextract
let m_spec (a:hash_alg) : Type0 =
  match a with
  | MD5 | SHA1 | SHA2_224 | SHA2_256 | SHA2_384 | SHA2_512 -> unit
  | Blake2S | Blake2B -> Blake2.m_spec

inline_for_extraction
type impl = a:hash_alg & m_spec a

inline_for_extraction noextract
let mk_impl (a:hash_alg) (m:m_spec a) : impl = (|a, m|)

inline_for_extraction noextract
let get_alg (i:impl) : hash_alg =
  match i with (|a, m|) -> a

inline_for_extraction noextract
let get_spec (i:impl) : m_spec (get_alg i) =
  match i with (|a, m|) -> m

inline_for_extraction noextract
let impl_word (i:impl) =
  [@inline_let] let a = get_alg i in
  match a with
  | MD5 | SHA1 | SHA2_224 | SHA2_256 | SHA2_384 | SHA2_512 -> word a
  | Blake2S | Blake2B -> Blake2.element_t (to_blake_alg a) (get_spec i)

inline_for_extraction noextract
let impl_state_length (i:impl) =
  [@inline_let] let a = get_alg i in
  match a with
  | MD5 | SHA1 | SHA2_224 | SHA2_256 | SHA2_384 | SHA2_512 -> state_word_length a
  | Blake2S | Blake2B -> UInt32.v (4ul *. Blake2.row_len (to_blake_alg a) (get_spec i))

inline_for_extraction noextract
let impl_state_len (i:impl) : s:size_t{size_v s == impl_state_length i} =
  [@inline_let] let a = get_alg i in
  [@inline_let] let m = get_spec i in
  match a with
  | MD5 -> 4ul
  | SHA1 -> 5ul
  | SHA2_224 | SHA2_256 | SHA2_384 | SHA2_512 -> 8ul
  | _ ->
    (**) mul_mod_lemma 4ul (Blake2.row_len (to_blake_alg a) (get_spec i));
    match a, m with
    | Blake2S, Blake2.M32
    | Blake2B, Blake2.M32 | Blake2B, Blake2.M128 -> 16ul
    | Blake2S, Blake2.M128 | Blake2S, Blake2.M256
    | Blake2B, Blake2.M256 -> 4ul
  
inline_for_extraction
type state (i:impl) =
  b:B.buffer (impl_word i) { B.length b = impl_state_length i }

inline_for_extraction noextract
let as_seq (#i:impl) (h:HS.mem) (s:state i) : GTot (words_state' (get_alg i)) =
  match get_alg i with
  | MD5 | SHA1 | SHA2_224 | SHA2_256 | SHA2_384 | SHA2_512 -> B.as_seq h s
  | Blake2S -> Blake2.state_v #Spec.Blake2.Blake2S #(get_spec i) h s
  | Blake2B -> Blake2.state_v #Spec.Blake2.Blake2B #(get_spec i) h s

inline_for_extraction
let word_len (a: hash_alg) : n:size_t { v n = word_length a } =
  match a with
  | MD5 | SHA1 | SHA2_224 | SHA2_256 -> 4ul
  | SHA2_384 | SHA2_512 -> 8ul
  | Blake2S -> 4ul
  | Blake2B -> 8ul

inline_for_extraction
let block_len (a: hash_alg): n:size_t { v n = block_length a } =
  match a with
  | MD5 | SHA1 | SHA2_224 | SHA2_256 -> 64ul
  | SHA2_384 | SHA2_512 -> 128ul
  | Blake2S -> 64ul
  | Blake2B -> 128ul

inline_for_extraction
let hash_word_len (a: hash_alg): n:size_t { v n = hash_word_length a } =
  match a with
  | MD5 -> 4ul
  | SHA1 -> 5ul
  | SHA2_224 -> 7ul
  | SHA2_256 -> 8ul
  | SHA2_384 -> 6ul
  | SHA2_512 -> 8ul
  | Blake2S | Blake2B -> 8ul

inline_for_extraction
let hash_len (a: hash_alg): n:size_t { v n = hash_length a } =
  match a with
  | MD5 -> 16ul
  | SHA1 -> 20ul
  | SHA2_224 -> 28ul
  | SHA2_256 -> 32ul
  | SHA2_384 -> 48ul
  | SHA2_512 -> 64ul
  | Blake2S -> 32ul
  | Blake2B -> 64ul

noextract inline_for_extraction
let blocks_t (a: hash_alg) =
  b:B.buffer uint8 { B.length b % block_length a = 0 }

let hash_t (a: hash_alg) = b:B.buffer uint8 { B.length b = hash_length a }

// The proper way to generate an extra state from a constant nat.
noextract inline_for_extraction
let const_nat_to_extra_state (a:hash_alg{is_blake a}) (n:nat{n <= maxint U64}) :
  extra_state a =
  match a with
  | Blake2S -> mk_int #U64 #SEC n
  | Blake2B -> cast U128 SEC (mk_int #U64 #SEC n)

noextract inline_for_extraction
let initial_extra_state (a:hash_alg) : extra_state a =
  if is_blake a then const_nat_to_extra_state a 0
  else ()

(** The types of all stateful operations for a hash algorithm. *)

noextract inline_for_extraction
let alloca_st (i:impl) = unit -> ST.StackInline (state i & extra_state (get_alg i))
  (requires (fun h ->
    HS.is_stack_region (HS.get_tip h)))
  (ensures (fun h0 (s, v) h1 ->
    M.(modifies M.loc_none h0 h1) /\
    B.frameOf s == HS.get_tip h0 /\
    (as_seq h1 s, v) == Spec.Agile.Hash.init (get_alg i) /\
    B.live h1 s /\
    B.fresh_loc (M.loc_buffer s) h0 h1))

noextract inline_for_extraction
let init_st (i:impl) = s:state i -> ST.Stack (extra_state (get_alg i))
  (requires (fun h ->
    B.live h s))
  (ensures (fun h0 v h1 ->
    M.(modifies (loc_buffer s) h0 h1) /\
    (as_seq h1 s, v) == Spec.Agile.Hash.init (get_alg i)))

noextract inline_for_extraction
let update_st (i:impl) =
  s:state i ->
  v:extra_state (get_alg i) ->
  block:B.buffer uint8 { B.length block = block_length (get_alg i) } ->
  ST.Stack (extra_state (get_alg i))
    (requires (fun h ->
      B.live h s /\ B.live h block /\ B.disjoint s block))
    (ensures (fun h0 v' h1 ->
      M.(modifies (loc_buffer s) h0 h1) /\
      (as_seq h1 s, v') ==
        Spec.Agile.Hash.update (get_alg i) (as_seq h0 s, v) (B.as_seq h0 block)))

noextract inline_for_extraction
let pad_st (a: hash_alg) = len:len_t a -> dst:B.buffer uint8 ->
  ST.Stack unit
    (requires (fun h ->
      len_v a len <= max_input_length a /\
      B.live h dst /\
      B.length dst = pad_length a (len_v a len)))
    (ensures (fun h0 _ h1 ->
      M.(modifies (loc_buffer dst) h0 h1) /\
      Seq.equal (B.as_seq h1 dst) (Spec.pad a (len_v a len))))

// Note: we cannot take more than 4GB of data because we are currently
// constrained by the size of buffers...
noextract inline_for_extraction
let update_multi_st (i:impl) =
  s:state i ->
  ev:extra_state (get_alg i) ->
  blocks:blocks_t (get_alg i) ->
  n:size_t { B.length blocks = block_length (get_alg i) * v n } ->
  ST.Stack (extra_state (get_alg i))
    (requires (fun h ->
      B.live h s /\ B.live h blocks /\ B.disjoint s blocks))
    (ensures (fun h0 ev' h1 ->
      B.(modifies (loc_buffer s) h0 h1) /\
      (as_seq h1 s, ev') ==
        Spec.Agile.Hash.update_multi (get_alg i) (as_seq h0 s, ev) (B.as_seq h0 blocks)))

noextract inline_for_extraction
let update_last_st (i:impl) =
  s:state i ->
  ev:extra_state (get_alg i) ->
  prev_len:len_t (get_alg i) { len_v (get_alg i) prev_len % block_length (get_alg i) = 0 } ->
  input:B.buffer uint8 { B.length input + len_v (get_alg i) prev_len <= max_input_length (get_alg i) } ->
  input_len:size_t { B.length input = v input_len } ->
  ST.Stack (extra_state (get_alg i))
    (requires (fun h ->
      B.live h s /\ B.live h input /\ B.disjoint s input /\
      (* ``extra_state_v ev`` is equal to 0 if the algorithm is not blake *)
      B.length input + extra_state_v ev <= max_input_length (get_alg i)))
    (ensures (fun h0 ev' h1 ->
      B.(modifies (loc_buffer s) h0 h1) /\
      (as_seq h1 s, ev') ==
        Spec.Hash.Incremental.update_last (get_alg i) (as_seq h0 s, ev)
                                          (len_v (get_alg i) prev_len)
                                          (B.as_seq h0 input)))

noextract inline_for_extraction
let finish_st (i:impl) =
  s:state i -> ev:extra_state (get_alg i) -> dst:hash_t (get_alg i) -> ST.Stack unit
  (requires (fun h ->
    B.live h s /\ B.live h dst /\ B.disjoint s dst))
  (ensures (fun h0 _ h1 ->
    M.(modifies (loc_buffer dst) h0 h1) /\
    Seq.equal (B.as_seq h1 dst) (Spec.Hash.PadFinish.finish (get_alg i) (as_seq h0 s, ev))))

noextract inline_for_extraction
let hash_st (a: hash_alg) =
  input:B.buffer uint8 ->
  input_len:size_t { B.length input = v input_len } ->
  dst:hash_t a->
  ST.Stack unit
    (requires (fun h ->
      B.live h input /\
      B.live h dst /\
      B.disjoint input dst /\
      B.length input <= max_input_length a))
    (ensures (fun h0 _ h1 ->
      B.(modifies (loc_buffer dst) h0 h1) /\
      Seq.equal (B.as_seq h1 dst) (Spec.Agile.Hash.hash a (B.as_seq h0 input))))
back to top