// storage type

type counter = nat
type threshold = nat
type authorized_keys = key list
type id = string

type storage = {
  id        : id;
  counter   : counter;
  threshold : threshold;
  auth      : authorized_keys
}

// I/O types

type message = unit -> operation list

type signatures = (key_hash * signature) list

type check_message_pt = {
  counter    : counter;
  message    : message;
  signatures : signatures
}

type return = operation list * storage

type parameter = CheckMessage of check_message_pt

let check_message (param, s : check_message_pt * storage) : return =
  let message : message = param.message in
  let s =
    if param.counter <> s.counter then
      (failwith "Counters does not match" : storage)
    else
      let packed_payload : bytes =
        Bytes.pack (message, param.counter, s.id, chain_id) in
      let valid : nat = 0n in
      let keys : authorized_keys = s.auth in
      let aux =
        fun (vk, pkh_sig: (nat * authorized_keys)*(key_hash * signature)) ->
          let valid, keys = vk in
            match keys with
            | [] -> vk
            | key::keys ->
               if pkh_sig.0 = Crypto.hash_key key
               then
                 let valid =
                   if Crypto.check key pkh_sig.1 packed_payload
                   then valid + 1n
                   else (failwith "Invalid signature" : nat)
                 in valid, keys
               else valid, keys in
      let valid, keys  =
        List.fold aux param.signatures (valid, keys) in
      if valid < s.threshold then
        (failwith ("Not enough signatures passed the check") : storage)
      else {s with counter = s.counter + 1n}
    in message unit, s

let main (action, store : parameter * storage) : return =
  match action with
    CheckMessage (p) -> check_message (p, store)
