let split_subst (sub : t_subst) (u : term) (v : term)
: term * term * t_split_subst * int list * int list =
(* add_var adds n clever to (std_vs,xor_vs). If n has a type different from 0,
* it will be added to std_vs, no matter what to_std is.
* It will not produce duplicates in std_vs or xor_vs (insert is used).
*
* Input: n - an index of a variable
* to_std - true, if n should be added to std_vs
* to_xor - true, if n should be added to xor_vs
* std_vs - list of variables
* xor_vs - list of variables
*)
let add_var n (to_std,to_xor) (std_vs,xor_vs) =
let to_std = to_std || (var_type n <> 0)
in
match (to_std,to_xor) with
| (true ,true ) -> (insert n std_vs,insert n xor_vs)
| (true ,false) -> (insert n std_vs, xor_vs)
| (false,true ) -> ( std_vs,insert n xor_vs)
| (false,false) -> ( std_vs, xor_vs)
in
(* Returns true, iff n is in std_vs or in xor_vs
*)
let mem_var n (std_vs,xor_vs) =
List.mem n std_vs || List.mem n xor_vs
in
(* applies " to a list of terms " instead of just a single term
*)
let rec apply_f_to_list (in_std : bool) tas = function
| t::ts ->
let tas, t = f in_std tas t in
let tas, ts = apply_f_to_list in_std tas ts in
(tas, t::ts)
| [] -> tas, []
(* applies " to a list of terms " instead of just a single term
*)
and apply_f_to_list_sign (in_std : bool) tas = function
| (t,si)::ts ->
let tas, t = f in_std tas t in
let tas, ts = apply_f_to_list_sign in_std tas ts in
(tas, (t,si)::ts)
| [] -> tas, []
and
(* f takes a term t and returns t2 which has the following properties:
* - t2 contains only variables that are free or have a value different
* from a variable and an atom (except Atm(0) if t is std and Atm(n)
* (n<>0) if t is xor)
* - otherwise t2 is the same as t
*
* In tas it collects all standard equations (in std), all xor
* equations (in xor), all variables (in vars) and the remaining
* substitution (in s).
* f goes into the structure of t and collects all variables.
* For every variable t it goes into the structure of the value of
* this variable (if there is any). If there is a value t2 different
* from Atm or Var it is either a standard or an xor expression and the
* equation t = t2 will be added to std or xor, respectively.
* The value for the variable will also be removed from s because the
* information is now stored in std or xor and it is not necessary
* to store it twice.
*
* The value of in_std is only relevant if t is a variable, otherwise it
* is ignored. It indicates weather the appearance of t is in a std term
* or an xor term.
*)
f (in_std : bool) (std,xor,vars,s as tas) (t : term) =
match t with
| Var(n) ->
if mem_var n vars then
(* n in vars means, that we have already handled it. We do not need to
* do it twice, but if in_std is false we have to add it to xor_vs and
* vice versa *)
((std,xor,(add_var n (in_std, not in_std) vars),s), t)
else
(* We found a variable that is not handled yet. If there is a value
* for it in s, add this as an equation to std or xor, respectively.
*
* TODO: Here could be done some optimization, because most time we
* look for the value of n in s and remove this from the substitution
* afterwards. You could do this in one step. *)
(match valeur n s with
| Var(m) as t2 ->
if m=n then
(* m=n means, that n is free in s *)
((std,xor,add_var n (in_std, not in_std) vars, s), t)
else
(* forget that we saw Var(n) and replace it with Var(m) (= t2)
*)
f in_std tas t2
| Xor l ->
(* add n to standard vars if in_std is true and add n to xor vars
* in any case *)
let vars = add_var n (in_std,true) vars in
(* apply f to l *)
let ((std, xor, vars, s), l) =
apply_f_to_list false (std, xor, vars, remove_from_subs n s) l
in
(* add the equation 0 = t+l to xor *)
((std, (t::l)::xor, vars, s), t)
| Atm(0) ->
(* add n to standard vars if in_std is true and add n to xor vars
* in any case *)
let vars = add_var n (in_std,true) vars in
(* do not replace an Atm(0), but add " to xor *)
((std, [t]::xor, vars, remove_from_subs n s), t)
| Atm(_) as t2 ->
if in_std then
(* there is an atom t2 assigned to n so we can replace n by t2
* and forget about n *)
((std, xor, vars, s), t2)
else
(* There is an atom t2 assigned to n, but because we are in an
* xor term we cannot replace n by t2. *)
(* Add n to std_vars and to xor_vars. *)
let vars = add_var n (true,true) vars in
(* Add n -> t2 to std. *)
(((n,t2)::std, xor, vars, remove_from_subs n s), t)
| u ->
(* u has to be standard. *)
(* Add n to xor vars if in_std is false and add n to standard vars
* in any case. *)
let vars = add_var n (true,not in_std) vars in
(* Apply f on u *)
let (std,xor,vars,s),u =
f true (std, xor, vars, remove_from_subs n s) u in
(* Add n -> u to std. *)
(((n,u)::std, xor, vars, s), t)
)
| Atm(_) ->
tas, t
| Xor l ->
let tas, l = apply_f_to_list false tas l in
tas, (Xor l)
| Uplet l ->
let tas, l = apply_f_to_list true tas l in
tas, (Uplet l)
| PCrypt(m,k) ->
let tas,m = f true tas m in
let tas,k = f true tas k in
tas, PCrypt(m,k)
| SCrypt(m,k) ->
let tas,m = f true tas m in
let tas,k = f true tas k in
tas, SCrypt(m,k)
| PInv(t) ->
let tas,t = f true tas t in
tas, PInv(t)
| Exp(t,l) ->
let tas,t = f true tas t in
let tas,l = apply_f_to_list_sign true tas l in
tas, Exp(t,l)
in
(* in_std will be true, iff u and v are both std *)
let in_std = match (u,v) with
| (Atm(0),_ )
| (Xor(_),_ )
| (_ ,Atm(0))
| (_ ,Xor(_)) -> false
| _ -> true
in
(* Apply f on u with an empty tas. *)
let tas,u = f in_std ([],[],([],[]),sub) u in
(* Apply f on v with the tas obtained before. *)
let (std_ls,xor_ls,(std_vars,xor_vars),(rem_ls,fv,ctr)),v = f in_std tas v in
u,v,(std_ls,xor_ls,rem_ls,fv,ctr),std_vars,xor_vars