// Type of a pointer with an explicit length
// in C: (size_t len, void* content)
type vlbytes = (| len:UInt32.t & b:bytes{length b.content >= v len } |)

let vllength (b:vlbytes) =
  let (len, _) = b in len

assume val vlcreate: len:UInt32.t -> 

(* Type of functions that turn F* types into sequences of bytes *)
type vlserializer (t:Type0) =
  f:(t -> Tot vlbytes){injective f}

(* Type of the inverse of the serialization *)
type vlparser (#t:Type0) ($f:serializer t) =
  vlbytes -> Tot (result t)

noeq type vlserializable (t:Type0) : Type0 =
| VLSerializable: $f:vlserializer t -> $g:vlparser f{inverse f g} -> vlserializable t

type lsize = n:int{n = 1 \/ n = 2 \/ n = 3}
type csize = n:t{v n = 1 \/ v n = 2 \/ v n = 3}

type vlbuffer (#t:Type0) (ty:vlserializable t) (n:lsize) =
  

// ------------------------------------------------------------
// Example

enum {
  P_256(1);
  // ...
} NamedGroup;

struct {
  NamedGroup ng;
  opaque cr[32]
  opaque share<1..2^16-1>;
} ks;

struct {
  ks shares<1..2^16-1>;
} kse;
 
----------------------------------------------------------

// Constant size: fixed-length theory
type namedGroup =
| P_256 // ...

let namedGroup_bytes : serializer namedGroup = function
| P_256 -> abyte2 (0z,1z) // ...

let parse_namedGroup: parser namedGroup_bytes =
// ...

assume SizeOfNamedGroup: sizeof namedGroup = 2

type ks = {
  ng: namedGroup;
  cr: buff u8 32;
  share: vlbytes;
}

let ks_bytes (ks:ks) : vlserializer ks =
  let ng_b = namedGroup_bytes ks.ng in
  let ng_l = sizeof namedGroup in
  let (share_length, share_b) = share in
  vlcreate (ng_l +^ share_length) (ng_b @| share_b) // @| on seq
  
let parse_ks (b:vlbytes) : vlparser ks_bytes =
  if vllength b >= 2 then
    let (ng, rest) = vlsplit 2 b in
    match parse_NamedGroup ng with
    | Correct x -> ...
    | Error -> Error
  else Error


