// storage type type counter is nat type threshold is nat type authorized_keys is list (key) type id is string type storage is record [ id : id; counter : counter; threshold : threshold; auth : authorized_keys ] // I/O types type message is unit -> list (operation) type signatures is list (key_hash * signature) type check_message_pt is record [ counter : counter; message : message; signatures : signatures ] type return is list (operation) * storage type parameter is CheckMessage of check_message_pt function check_message (const param : check_message_pt; const s : storage) : return is block { var message : message := param.message; if param.counter =/= s.counter then failwith ("Counters does not match") else { const packed_payload : bytes = Bytes.pack ((message, param.counter, s.id, Tezos.chain_id)); var valid : nat := 0n; var keys : authorized_keys := s.auth; for pkh_sig in list param.signatures block { case keys of nil -> skip | key # tl -> block { keys := tl; if pkh_sig.0 = Crypto.hash_key (key) then if Crypto.check (key, pkh_sig.1, packed_payload) then valid := valid + 1n else failwith ("Invalid signature") else skip } end }; if valid < s.threshold then failwith ("Not enough signatures passed the check") else s.counter := s.counter + 1n } } with (message (unit), s) function main (const param : parameter; const s : storage) : return is case param of CheckMessage (p) -> check_message (p,s) end