val stream_deltas_snoc2 (#i: id) (#rw: rw) (s: StAE.state i rw) (h0 h1: mem) (f: Content.fragment i)
    : Lemma
    (authId i /\ StAE.fragments s h1 == Seq.snoc (StAE.fragments s h0) f ==>
      stream_deltas s h1 == Seq.append (stream_deltas s h0) (project_one_frag f))
val stream_deltas_snoc2 (#i: id) (#rw: rw) (s: StAE.state i rw) (h0 h1: mem) (f: Content.fragment i)
    : Lemma
    (authId i /\ StAE.fragments s h1 == Seq.snoc (StAE.fragments s h0) f ==>
      stream_deltas s h1 == Seq.append (stream_deltas s h0) (project_one_frag f))
let stream_deltas_snoc2 (#i:id) (#rw:rw) (s:StAE.state i rw) (h0:mem) (h1:mem) (f:Content.fragment i)
  : Lemma (authId i /\ StAE.fragments s h1 == Seq.snoc (StAE.fragments s h0) f
	   ==> stream_deltas s h1 == Seq.append (stream_deltas s h0) (project_one_frag f))
  = if authId i then stream_deltas_snoc i (StAE.fragments s h0) f else ()
module MiTLS.StreamDeltas
open MiTLS

open FStar.Bytes
open FStar.Error

open MiTLS.Mem
open FStar.HyperStack
open MiTLS.TLSConstants
open MiTLS.TLSInfo

module HS   = FStar.HyperStack
module HST = FStar.HyperStack.ST //Added automatically; avoid.
module MS   = FStar.Monotonic.Seq
module S    = MiTLS.StAE
module C    = MiTLS.Content
module DS   = MiTLS.DataStream

let deltas i = Seq.seq (DS.delta i) //not yet handling the well-formedness condition of final deltas

let singleton (x:'a) : Tot (Seq.seq 'a) = Seq.create 1 x

#reset-options "--initial_fuel 1 --max_fuel 1 --initial_ifuel 1 --max_ifuel 1"

private type id = i:id{~(PlaintextID? i)}

val project_one_frag: #i:id -> f:C.fragment i -> Tot (Seq.seq (DS.delta i))
let project_one_frag #i = function
    | C.CT_Data rg d -> 
      let d : DS.pre_fragment i = d in //A widening coercion as a proof hint, unpacking (d:fragment i (frange i)) to a pre_fr
      singleton (DataStream.Data d)
    | C.CT_Alert _ ad -> singleton (DataStream.Alert ad)
    | _ -> Seq.empty                 // other fragments are internal to TLS

val project_deltas: #i:id -> fs:S.frags i -> GTot (deltas i)
let project_deltas #i fs = MS.collect project_one_frag fs

val stream_deltas: #i:id -> #rw:rw -> s:StAE.state i rw{authId i} -> mem -> GTot (deltas i)
let stream_deltas #i #rw s h = project_deltas (StAE.fragments s h)

let stream_deltas_snoc (i:id) (frags:StAE.frags i) (f:Content.fragment i)
  : Lemma (project_deltas (Seq.snoc frags f) == Seq.append (project_deltas frags) (project_one_frag f))
  = MS.collect_snoc project_one_frag frags f

//A predicate stating the deltas of s always as ds as a prefix
let deltas_prefix (#i:id) (#rw:rw) (s:S.state i rw{authId i}) (ds:deltas i) (h:mem)
  : GTot Type0 
  = MS.grows ds (project_deltas (S.fragments s h))

val project_fragment_deltas: #i:id -> #rw:rw -> s:S.state i rw -> fs:S.frags i
		  -> Lemma (authId i /\ HST.witnessed (S.fragments_prefix s fs)
			   ==> HST.witnessed (deltas_prefix s (project_deltas fs)))
let project_fragment_deltas #i #rw s fs =
  if authId i 
  then let j : i:id{authId i} = i in //re-label for better implicit arg inference below
       let s  : S.state j rw = s in
       let fs : S.frags j = fs in
       let aux : h:mem -> Lemma (S.fragments_prefix s fs h
			    ==> deltas_prefix s (project_deltas fs) h) =
	  fun h -> MS.collect_grows project_one_frag fs (S.fragments s h) in
       let _ = FStar.Classical.forall_intro aux in
       weaken_witness (S.fragments_prefix s fs) (deltas_prefix s (project_deltas fs))
  else ()
/
prims.fst.checked MiTLS.TLSInfo.fst.checked MiTLS.TLSConstants.fsti.checked MiTLS.StAE.fst.checked MiTLS.Mem.fst.checked MiTLS.DataStream.fst.checked MiTLS.Content.fst.checked FStar.Seq.fst.checked FStar.Pervasives.fsti.checked FStar.Monotonic.Seq.fst.checked FStar.HyperStack.ST.fsti.checked FStar.HyperStack.fst.checked FStar.Error.fst.checked FStar.Classical.fsti.checked FStar.Bytes.fsti.checked
MiTLS.StreamDeltas.fst

    s: MiTLS.StAE.state i rw ->
    h0: FStar.Monotonic.HyperStack.mem ->
    h1: FStar.Monotonic.HyperStack.mem ->
    f: MiTLS.Content.fragment i
  -> FStar.Pervasives.Lemma
    (ensures
      MiTLS.TLSInfo.authId i /\
      MiTLS.StAE.fragments s h1 == FStar.Seq.Properties.snoc (MiTLS.StAE.fragments s h0) f ==>
      MiTLS.StreamDeltas.stream_deltas s h1 ==
      FStar.Seq.Base.append (MiTLS.StreamDeltas.stream_deltas s h0)
        (MiTLS.StreamDeltas.project_one_frag f))
MiTLS.StreamDeltas.id MiTLS.TLSConstants.rw MiTLS.StAE.state FStar.Monotonic.HyperStack.mem MiTLS.Content.fragment MiTLS.TLSInfo.authId MiTLS.StreamDeltas.stream_deltas_snoc MiTLS.StAE.fragments Prims.bool Prims.unit Prims.l_True Prims.squash Prims.l_imp Prims.l_and Prims.b2t Prims.eq2 FStar.Seq.Base.seq FStar.Seq.Properties.snoc MiTLS.DataStream.delta MiTLS.StreamDeltas.stream_deltas FStar.Seq.Base.append MiTLS.StreamDeltas.project_one_frag Prims.Nil FStar.Pervasives.pattern
let stream_deltas_snoc2 (#i: id) (#rw: rw) (s: StAE.state i rw) (h0 h1: mem) (f: Content.fragment i)
    : Lemma
    (authId i /\ StAE.fragments s h1 == Seq.snoc (StAE.fragments s h0) f ==>
      stream_deltas s h1 == Seq.append (stream_deltas s h0) (project_one_frag f)) =
  
if authId i then stream_deltas_snoc i (StAE.fragments s h0) f