566 lines
21 KiB
Plaintext
566 lines
21 KiB
Plaintext
(*
|
|
(C) Copyright Andreas Viktor Hess, DTU, 2020
|
|
(C) Copyright Sebastian A. Mödersheim, DTU, 2020
|
|
(C) Copyright Achim D. Brucker, University of Exeter, 2020
|
|
(C) Copyright Anders Schlichtkrull, DTU, 2020
|
|
|
|
All Rights Reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are
|
|
met:
|
|
|
|
- Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
- Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
- Neither the name of the copyright holder nor the names of its
|
|
contributors may be used to endorse or promote products
|
|
derived from this software without specific prior written
|
|
permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*)
|
|
|
|
(* Title: trac_term.thy
|
|
Author: Andreas Viktor Hess, DTU
|
|
Author: Sebastian A. Mödersheim, DTU
|
|
Author: Achim D. Brucker, University of Exeter
|
|
Author: Anders Schlichtkrull, DTU
|
|
*)
|
|
|
|
section \<open>Abstract Syntax for Trac Terms\<close>
|
|
theory
|
|
trac_term
|
|
imports
|
|
"First_Order_Terms.Term"
|
|
"ml_yacc_lib"
|
|
(* Alternatively (provides, as a side-effect, ml-yacc-lib):
|
|
"HOL-TPTP.TPTP_Parser"
|
|
*)
|
|
begin
|
|
datatype cMsg = cVar "string * string"
|
|
| cConst string
|
|
| cFun "string * cMsg list"
|
|
|
|
ML\<open>
|
|
structure Trac_Utils =
|
|
struct
|
|
|
|
fun list_find p ts =
|
|
let
|
|
fun aux _ [] = NONE
|
|
| aux n (t::ts) =
|
|
if p t
|
|
then SOME (t,n)
|
|
else aux (n+1) ts
|
|
in
|
|
aux 0 ts
|
|
end
|
|
|
|
fun map_prod f (a,b) = (f a, f b)
|
|
|
|
|
|
|
|
fun list_product [] = [[]]
|
|
| list_product (xs::xss) =
|
|
List.concat (map (fn x => map (fn ys => x::ys) (list_product xss)) xs)
|
|
|
|
fun list_toString elem_toString xs =
|
|
let
|
|
fun aux [] = ""
|
|
| aux [x] = elem_toString x
|
|
| aux (x::y::xs) = elem_toString x ^ ", " ^ aux (y::xs)
|
|
in
|
|
"[" ^ aux xs ^ "]"
|
|
end
|
|
|
|
val list_to_str = list_toString (fn x => x)
|
|
|
|
fun list_triangle_product _ [] = []
|
|
| list_triangle_product f (x::xs) = map (f x) xs@list_triangle_product f xs
|
|
|
|
fun list_subseqs [] = [[]]
|
|
| list_subseqs (x::xs) = let val xss = list_subseqs xs in map (cons x) xss@xss end
|
|
|
|
fun list_intersect xs ys =
|
|
List.exists (fn x => member (op =) ys x) xs orelse
|
|
List.exists (fn y => member (op =) xs y) ys
|
|
|
|
fun list_partitions xs constrs =
|
|
let
|
|
val peq = eq_set (op =)
|
|
val pseq = eq_set peq
|
|
val psseq = eq_set pseq
|
|
|
|
fun illegal p q =
|
|
let
|
|
val pq = union (op =) p q
|
|
fun f (a,b) = member (op =) pq a andalso member (op =) pq b
|
|
in
|
|
List.exists f constrs
|
|
end
|
|
|
|
fun merges _ [] = []
|
|
| merges q (p::ps) =
|
|
if illegal p q then map (cons p) (merges q ps)
|
|
else (union (op =) p q::ps)::(map (cons p) (merges q ps))
|
|
|
|
fun merges_all [] = []
|
|
| merges_all (p::ps) = merges p ps@map (cons p) (merges_all ps)
|
|
|
|
fun step pss = fold (union pseq) (map merges_all pss) []
|
|
|
|
fun loop pss pssprev =
|
|
let val pss' = step pss
|
|
in if psseq (pss,pss') then pssprev else loop pss' (union pseq pss' pssprev)
|
|
end
|
|
|
|
val init = [map single xs]
|
|
in
|
|
loop init init
|
|
end
|
|
|
|
fun mk_unique [] = []
|
|
| mk_unique (x::xs) = x::mk_unique(List.filter (fn y => y <> x) xs)
|
|
|
|
fun list_rm_pair sel l x = filter (fn e => sel e <> x) l
|
|
|
|
fun list_minus list_rm l m = List.foldl (fn (a,b) => list_rm b a) l m
|
|
|
|
fun list_upto n =
|
|
let
|
|
fun aux m = if m >= n then [] else m::aux (m+1)
|
|
in
|
|
aux 0
|
|
end
|
|
end
|
|
\<close>
|
|
|
|
ML\<open>
|
|
structure Trac_Term (* : TRAC_TERM *) =
|
|
struct
|
|
open Trac_Utils
|
|
exception TypeError
|
|
|
|
type TypeDecl = string * string
|
|
|
|
datatype Msg = Var of string
|
|
| Const of string
|
|
| Fun of string * Msg list
|
|
| Attack
|
|
|
|
datatype VarType = EnumType of string
|
|
| ValueType
|
|
| Untyped
|
|
|
|
datatype cMsg = cVar of string * VarType
|
|
| cConst of string
|
|
| cFun of string * cMsg list
|
|
| cAttack
|
|
| cSet of string * cMsg list
|
|
| cAbs of (string * string list) list
|
|
| cOccursFact of cMsg
|
|
| cPrivFunSec
|
|
| cEnum of string
|
|
|
|
fun type_of et vt n =
|
|
case List.find (fn (v,_) => v = n) et of
|
|
SOME (_,t) => EnumType t
|
|
| NONE =>
|
|
if List.exists (fn v => v = n) vt
|
|
then ValueType
|
|
else Untyped
|
|
|
|
fun certifyMsg et vt (Var n) = cVar (n, type_of et vt n)
|
|
| certifyMsg _ _ (Const c) = cConst c
|
|
| certifyMsg et vt (Fun (f, ts)) = cFun (f, map (certifyMsg et vt) ts)
|
|
| certifyMsg _ _ Attack = cAttack
|
|
|
|
fun mk_Value_cVar x = cVar (x,ValueType)
|
|
|
|
val fv_Msg =
|
|
let
|
|
fun aux (Var x) = [x]
|
|
| aux (Fun (_,ts)) = List.concat (map aux ts)
|
|
| aux _ = []
|
|
in
|
|
mk_unique o aux
|
|
end
|
|
|
|
val fv_cMsg =
|
|
let
|
|
fun aux (cVar x) = [x]
|
|
| aux (cFun (_,ts)) = List.concat (map aux ts)
|
|
| aux (cSet (_,ts)) = List.concat (map aux ts)
|
|
| aux (cOccursFact bs) = aux bs
|
|
| aux _ = []
|
|
in
|
|
mk_unique o aux
|
|
end
|
|
|
|
fun subst_apply' (delta:(string * VarType) -> cMsg) (t:cMsg) =
|
|
case t of
|
|
cVar x => delta x
|
|
| cFun (f,ts) => cFun (f, map (subst_apply' delta) ts)
|
|
| cSet (s,ts) => cSet (s, map (subst_apply' delta) ts)
|
|
| cOccursFact bs => cOccursFact (subst_apply' delta bs)
|
|
| c => c
|
|
|
|
fun subst_apply (delta:(string * cMsg) list) =
|
|
subst_apply' (fn (n,tau) => (
|
|
case List.find (fn x => fst x = n) delta of
|
|
SOME x => snd x
|
|
| NONE => cVar (n,tau)))
|
|
end
|
|
\<close>
|
|
|
|
ML\<open>
|
|
|
|
structure TracProtocol (* : TRAC_TERM *) =
|
|
struct
|
|
open Trac_Utils
|
|
datatype type_spec_elem =
|
|
Consts of string list
|
|
| Union of string list
|
|
|
|
fun is_Consts t = case t of Consts _ => true | _ => false
|
|
fun the_Consts t = case t of Consts cs => cs | _ => error "Consts"
|
|
|
|
type type_spec = (string * type_spec_elem) list
|
|
type set_spec = (string * string)
|
|
|
|
fun extract_Consts (tspec:type_spec) =
|
|
(List.concat o map the_Consts o filter is_Consts o map snd) tspec
|
|
|
|
type funT = (string * string)
|
|
type fun_spec = {private: funT list, public: funT list}
|
|
|
|
type ruleT = (string * string list) * Trac_Term.Msg list * string list
|
|
type anaT = ruleT list
|
|
|
|
datatype prot_label = LabelN | LabelS
|
|
|
|
datatype action = RECEIVE of Trac_Term.Msg
|
|
| SEND of Trac_Term.Msg
|
|
| IN of Trac_Term.Msg * (string * Trac_Term.Msg list)
|
|
| NOTIN of Trac_Term.Msg * (string * Trac_Term.Msg list)
|
|
| NOTINANY of Trac_Term.Msg * string
|
|
| INSERT of Trac_Term.Msg * (string * Trac_Term.Msg list)
|
|
| DELETE of Trac_Term.Msg * (string * Trac_Term.Msg list)
|
|
| NEW of string
|
|
| ATTACK
|
|
|
|
datatype cAction = cReceive of Trac_Term.cMsg
|
|
| cSend of Trac_Term.cMsg
|
|
| cInequality of Trac_Term.cMsg * Trac_Term.cMsg
|
|
| cInSet of Trac_Term.cMsg * Trac_Term.cMsg
|
|
| cNotInSet of Trac_Term.cMsg * Trac_Term.cMsg
|
|
| cNotInAny of Trac_Term.cMsg * string
|
|
| cInsert of Trac_Term.cMsg * Trac_Term.cMsg
|
|
| cDelete of Trac_Term.cMsg * Trac_Term.cMsg
|
|
| cNew of string
|
|
| cAssertAttack
|
|
|
|
type transaction_name = string * (string * string) list * (string * string) list
|
|
|
|
type transaction={transaction:transaction_name,actions:(prot_label * action) list}
|
|
|
|
type cTransaction={
|
|
transaction:transaction_name,
|
|
receive_actions:(prot_label * cAction) list,
|
|
checksingle_actions:(prot_label * cAction) list,
|
|
checkall_actions:(prot_label * cAction) list,
|
|
fresh_actions:(prot_label * cAction) list,
|
|
update_actions:(prot_label * cAction) list,
|
|
send_actions:(prot_label * cAction) list,
|
|
attack_actions:(prot_label * cAction) list}
|
|
|
|
fun mkTransaction transaction actions = {transaction=transaction,
|
|
actions=actions}:transaction
|
|
|
|
fun is_RECEIVE a = case a of RECEIVE _ => true | _ => false
|
|
fun is_SEND a = case a of SEND _ => true | _ => false
|
|
fun is_IN a = case a of IN _ => true | _ => false
|
|
fun is_NOTIN a = case a of NOTIN _ => true | _ => false
|
|
fun is_NOTINANY a = case a of NOTINANY _ => true | _ => false
|
|
fun is_INSERT a = case a of INSERT _ => true | _ => false
|
|
fun is_DELETE a = case a of DELETE _ => true | _ => false
|
|
fun is_NEW a = case a of NEW _ => true | _ => false
|
|
fun is_ATTACK a = case a of ATTACK => true | _ => false
|
|
|
|
fun the_RECEIVE a = case a of RECEIVE t => t | _ => error "RECEIVE"
|
|
fun the_SEND a = case a of SEND t => t | _ => error "SEND"
|
|
fun the_IN a = case a of IN t => t | _ => error "IN"
|
|
fun the_NOTIN a = case a of NOTIN t => t | _ => error "NOTIN"
|
|
fun the_NOTINANY a = case a of NOTINANY t => t | _ => error "NOTINANY"
|
|
fun the_INSERT a = case a of INSERT t => t | _ => error "INSERT"
|
|
fun the_DELETE a = case a of DELETE t => t | _ => error "DELETE"
|
|
fun the_NEW a = case a of NEW t => t | _ => error "FRESH"
|
|
|
|
fun maybe_the_RECEIVE a = case a of RECEIVE t => SOME t | _ => NONE
|
|
fun maybe_the_SEND a = case a of SEND t => SOME t | _ => NONE
|
|
fun maybe_the_IN a = case a of IN t => SOME t | _ => NONE
|
|
fun maybe_the_NOTIN a = case a of NOTIN t => SOME t | _ => NONE
|
|
fun maybe_the_NOTINANY a = case a of NOTINANY t => SOME t | _ => NONE
|
|
fun maybe_the_INSERT a = case a of INSERT t => SOME t | _ => NONE
|
|
fun maybe_the_DELETE a = case a of DELETE t => SOME t | _ => NONE
|
|
fun maybe_the_NEW a = case a of NEW t => SOME t | _ => NONE
|
|
|
|
fun is_Receive a = case a of cReceive _ => true | _ => false
|
|
fun is_Send a = case a of cSend _ => true | _ => false
|
|
fun is_Inequality a = case a of cInequality _ => true | _ => false
|
|
fun is_InSet a = case a of cInSet _ => true | _ => false
|
|
fun is_NotInSet a = case a of cNotInSet _ => true | _ => false
|
|
fun is_NotInAny a = case a of cNotInAny _ => true | _ => false
|
|
fun is_Insert a = case a of cInsert _ => true | _ => false
|
|
fun is_Delete a = case a of cDelete _ => true | _ => false
|
|
fun is_Fresh a = case a of cNew _ => true | _ => false
|
|
fun is_Attack a = case a of cAssertAttack => true | _ => false
|
|
|
|
fun the_Receive a = case a of cReceive t => t | _ => error "Receive"
|
|
fun the_Send a = case a of cSend t => t | _ => error "Send"
|
|
fun the_Inequality a = case a of cInequality t => t | _ => error "Inequality"
|
|
fun the_InSet a = case a of cInSet t => t | _ => error "InSet"
|
|
fun the_NotInSet a = case a of cNotInSet t => t | _ => error "NotInSet"
|
|
fun the_NotInAny a = case a of cNotInAny t => t | _ => error "NotInAny"
|
|
fun the_Insert a = case a of cInsert t => t | _ => error "Insert"
|
|
fun the_Delete a = case a of cDelete t => t | _ => error "Delete"
|
|
fun the_Fresh a = case a of cNew t => t | _ => error "New"
|
|
|
|
fun maybe_the_Receive a = case a of cReceive t => SOME t | _ => NONE
|
|
fun maybe_the_Send a = case a of cSend t => SOME t | _ => NONE
|
|
fun maybe_the_Inequality a = case a of cInequality t => SOME t | _ => NONE
|
|
fun maybe_the_InSet a = case a of cInSet t => SOME t | _ => NONE
|
|
fun maybe_the_NotInSet a = case a of cNotInSet t => SOME t | _ => NONE
|
|
fun maybe_the_NotInAny a = case a of cNotInAny t => SOME t | _ => NONE
|
|
fun maybe_the_Insert a = case a of cInsert t => SOME t | _ => NONE
|
|
fun maybe_the_Delete a = case a of cDelete t => SOME t | _ => NONE
|
|
fun maybe_the_Fresh a = case a of cNew t => SOME t | _ => NONE
|
|
|
|
fun certifyAction et vt (lbl,SEND t) = (lbl,cSend (Trac_Term.certifyMsg et vt t))
|
|
| certifyAction et vt (lbl,RECEIVE t) = (lbl,cReceive (Trac_Term.certifyMsg et vt t))
|
|
| certifyAction et vt (lbl,IN (x,(s,ps))) = (lbl,cInSet
|
|
(Trac_Term.certifyMsg et vt x, Trac_Term.cSet (s, map (Trac_Term.certifyMsg et vt) ps)))
|
|
| certifyAction et vt (lbl,NOTIN (x,(s,ps))) = (lbl,cNotInSet
|
|
(Trac_Term.certifyMsg et vt x, Trac_Term.cSet (s, map (Trac_Term.certifyMsg et vt) ps)))
|
|
| certifyAction et vt (lbl,NOTINANY (x,s)) = (lbl,cNotInAny (Trac_Term.certifyMsg et vt x, s))
|
|
| certifyAction et vt (lbl,INSERT (x,(s,ps))) = (lbl,cInsert
|
|
(Trac_Term.certifyMsg et vt x, Trac_Term.cSet (s, map (Trac_Term.certifyMsg et vt) ps)))
|
|
| certifyAction et vt (lbl,DELETE (x,(s,ps))) = (lbl,cDelete
|
|
(Trac_Term.certifyMsg et vt x, Trac_Term.cSet (s, map (Trac_Term.certifyMsg et vt) ps)))
|
|
| certifyAction _ _ (lbl,NEW x) = (lbl,cNew x)
|
|
| certifyAction _ _ (lbl,ATTACK) = (lbl,cAssertAttack)
|
|
|
|
fun certifyTransaction (tr:transaction) =
|
|
let
|
|
val mk_cOccurs = Trac_Term.cOccursFact
|
|
fun mk_Value_cVar x = Trac_Term.cVar (x,Trac_Term.ValueType)
|
|
fun mk_cInequality x y = cInequality (mk_Value_cVar x, mk_Value_cVar y)
|
|
val mk_cInequalities = list_triangle_product mk_cInequality
|
|
|
|
val fresh_vals = map_filter (maybe_the_NEW o snd) (#actions tr)
|
|
val decl_vars = map fst (#2 (#transaction tr))
|
|
val neq_constrs = #3 (#transaction tr)
|
|
|
|
val _ = if List.exists (fn x => List.exists (fn y => x = y) fresh_vals) decl_vars
|
|
orelse List.exists (fn x => List.exists (fn y => x = y) decl_vars) fresh_vals
|
|
then error "the fresh and the declared variables must not overlap"
|
|
else ()
|
|
|
|
val _ = case List.find (fn (x,y) => x = y) neq_constrs of
|
|
SOME (x,y) => error ("illegal inequality constraint: " ^ x ^ " != " ^ y)
|
|
| NONE => ()
|
|
|
|
val nonfresh_vals = map fst (filter (fn x => snd x = "value") (#2 (#transaction tr)))
|
|
val enum_vars = filter (fn x => snd x <> "value") (#2 (#transaction tr))
|
|
|
|
fun lblS t = (LabelS,t)
|
|
|
|
val cactions = map (certifyAction enum_vars (nonfresh_vals@fresh_vals)) (#actions tr)
|
|
|
|
val nonfresh_occurs = map (lblS o cReceive o mk_cOccurs o mk_Value_cVar) nonfresh_vals
|
|
val receives = filter (is_Receive o snd) cactions
|
|
val value_inequalities = map lblS (mk_cInequalities nonfresh_vals)
|
|
val checksingles = filter (fn (_,a) => is_InSet a orelse is_NotInSet a) cactions
|
|
val checkalls = filter (is_NotInAny o snd) cactions
|
|
val updates = filter (fn (_,a) => is_Insert a orelse is_Delete a) cactions
|
|
val fresh = filter (is_Fresh o snd) cactions
|
|
val sends = filter (is_Send o snd) cactions
|
|
val fresh_occurs = map (lblS o cSend o mk_cOccurs o mk_Value_cVar) fresh_vals
|
|
val attack_signals = filter (is_Attack o snd) cactions
|
|
in
|
|
{transaction = #transaction tr,
|
|
receive_actions = nonfresh_occurs@receives,
|
|
checksingle_actions = value_inequalities@checksingles,
|
|
checkall_actions = checkalls,
|
|
fresh_actions = fresh,
|
|
update_actions = updates,
|
|
send_actions = sends@fresh_occurs,
|
|
attack_actions = attack_signals}:cTransaction
|
|
end
|
|
|
|
fun subst_apply_action (delta:(string * Trac_Term.cMsg) list) (lbl:prot_label,a:cAction) =
|
|
let
|
|
val apply = Trac_Term.subst_apply delta
|
|
in
|
|
case a of
|
|
cReceive t => (lbl,cReceive (apply t))
|
|
| cSend t => (lbl,cSend (apply t))
|
|
| cInequality (x,y) => (lbl,cInequality (apply x, apply y))
|
|
| cInSet (x,s) => (lbl,cInSet (apply x, apply s))
|
|
| cNotInSet (x,s) => (lbl,cNotInSet (apply x, apply s))
|
|
| cNotInAny (x,s) => (lbl,cNotInAny (apply x, s))
|
|
| cInsert (x,s) => (lbl,cInsert (apply x, apply s))
|
|
| cDelete (x,s) => (lbl,cDelete (apply x, apply s))
|
|
| cNew x => (lbl,cNew x)
|
|
| cAssertAttack => (lbl,cAssertAttack)
|
|
end
|
|
|
|
fun subst_apply_actions delta =
|
|
map (subst_apply_action delta)
|
|
|
|
|
|
type protocol = {
|
|
name:string
|
|
,type_spec:type_spec
|
|
,set_spec:set_spec list
|
|
,function_spec:fun_spec option
|
|
,analysis_spec:anaT
|
|
,transaction_spec:(string option * transaction list) list
|
|
,fixed_point: (Trac_Term.cMsg list * (string * string list) list list *
|
|
((string * string list) list * (string * string list) list) list) option
|
|
}
|
|
|
|
exception TypeError
|
|
|
|
val fun_empty = {
|
|
public=[]
|
|
,private=[]
|
|
}:fun_spec
|
|
|
|
fun update_fun_public (fun_spec:fun_spec) public =
|
|
({public = public
|
|
,private = #private fun_spec
|
|
}):fun_spec
|
|
|
|
fun update_fun_private (fun_spec:fun_spec) private =
|
|
({public = #public fun_spec
|
|
,private = private
|
|
}):fun_spec
|
|
|
|
|
|
val empty={
|
|
name=""
|
|
,type_spec=[]
|
|
,set_spec=[]
|
|
,function_spec=NONE
|
|
,analysis_spec=[]
|
|
,transaction_spec=[]
|
|
,fixed_point = NONE
|
|
}:protocol
|
|
|
|
fun update_name (protocol_spec:protocol) name =
|
|
({name = name
|
|
,type_spec = #type_spec protocol_spec
|
|
,set_spec = #set_spec protocol_spec
|
|
,function_spec = #function_spec protocol_spec
|
|
,analysis_spec = #analysis_spec protocol_spec
|
|
,transaction_spec = #transaction_spec protocol_spec
|
|
,fixed_point = #fixed_point protocol_spec
|
|
}):protocol
|
|
fun update_sets (protocol_spec:protocol) set_spec =
|
|
({name = #name protocol_spec
|
|
,type_spec = #type_spec protocol_spec
|
|
,set_spec =
|
|
if has_duplicates (op =) (map fst set_spec)
|
|
then error "Multiple declarations of the same set family"
|
|
else set_spec
|
|
,function_spec = #function_spec protocol_spec
|
|
,analysis_spec = #analysis_spec protocol_spec
|
|
,transaction_spec = #transaction_spec protocol_spec
|
|
,fixed_point = #fixed_point protocol_spec
|
|
}):protocol
|
|
fun update_type_spec (protocol_spec:protocol) type_spec =
|
|
({name = #name protocol_spec
|
|
,type_spec =
|
|
if has_duplicates (op =) (map fst type_spec)
|
|
then error "Multiple declarations of the same enumeration type"
|
|
else type_spec
|
|
,set_spec = #set_spec protocol_spec
|
|
,function_spec = #function_spec protocol_spec
|
|
,analysis_spec = #analysis_spec protocol_spec
|
|
,transaction_spec = #transaction_spec protocol_spec
|
|
,fixed_point = #fixed_point protocol_spec
|
|
}):protocol
|
|
fun update_functions (protocol_spec:protocol) function_spec =
|
|
({name = #name protocol_spec
|
|
,type_spec = #type_spec protocol_spec
|
|
,set_spec = #set_spec protocol_spec
|
|
,function_spec = case function_spec of
|
|
SOME fs =>
|
|
if has_duplicates (op =) (map fst ((#public fs)@(#private fs)))
|
|
then error "Multiple declarations of the same constant or function symbol"
|
|
else SOME fs
|
|
| NONE => NONE
|
|
,analysis_spec = #analysis_spec protocol_spec
|
|
,transaction_spec = #transaction_spec protocol_spec
|
|
,fixed_point = #fixed_point protocol_spec
|
|
}):protocol
|
|
fun update_analysis (protocol_spec:protocol) analysis_spec =
|
|
({name = #name protocol_spec
|
|
,type_spec = #type_spec protocol_spec
|
|
,set_spec = #set_spec protocol_spec
|
|
,function_spec = #function_spec protocol_spec
|
|
,analysis_spec =
|
|
if has_duplicates (op =) (map (#1 o #1) analysis_spec)
|
|
then error "Multiple analysis rules declared for the same function symbol"
|
|
else if List.exists (has_duplicates (op =)) (map (#2 o #1) analysis_spec)
|
|
then error "The heads of the analysis rules must be linear terms"
|
|
else if let fun f ((_,xs),ts,ys) =
|
|
subset (op =) (ys@List.concat (map Trac_Term.fv_Msg ts), xs)
|
|
in List.exists (not o f) analysis_spec end
|
|
then error "Variables occurring in the body of an analysis rule should also occur in its head"
|
|
else analysis_spec
|
|
,transaction_spec = #transaction_spec protocol_spec
|
|
,fixed_point = #fixed_point protocol_spec
|
|
}):protocol
|
|
fun update_transactions (prot_name:string option) (protocol_spec:protocol) transaction_spec =
|
|
({name = #name protocol_spec
|
|
,type_spec = #type_spec protocol_spec
|
|
,set_spec = #set_spec protocol_spec
|
|
,function_spec = #function_spec protocol_spec
|
|
,analysis_spec = #analysis_spec protocol_spec
|
|
,transaction_spec = (prot_name,transaction_spec)::(#transaction_spec protocol_spec)
|
|
,fixed_point = #fixed_point protocol_spec
|
|
}):protocol
|
|
fun update_fixed_point (protocol_spec:protocol) fixed_point =
|
|
({name = #name protocol_spec
|
|
,type_spec = #type_spec protocol_spec
|
|
,set_spec = #set_spec protocol_spec
|
|
,function_spec = #function_spec protocol_spec
|
|
,analysis_spec = #analysis_spec protocol_spec
|
|
,transaction_spec = #transaction_spec protocol_spec
|
|
,fixed_point = fixed_point
|
|
}):protocol
|
|
|
|
|
|
end
|
|
\<close>
|
|
|
|
|
|
end
|