let rec unif_uplet_cmp_f z1 z2 ss = if ss=[] then ss else
  match (z1,z2) with
  | ([],[])                        -> ss
  | ((Var(_) as hd)::tl,(Var(_) as hd2)::tl2) -> 
      (unif_uplet_cmp_g ss hd tl [] z2)@(unif_uplet_cmp_g ss hd2 tl2 [hd] tl)
  | ((Var(_) as hd)::tl,_)         -> unif_uplet_cmp_g ss hd tl [] z2
  | (_,(Var(_) as hd)::tl)         -> unif_uplet_cmp_g ss hd tl [] z1
  | (t1::zz1,t2::zz2)              -> unif_uplet_cmp_f zz1 zz2 (unif_cmp true t1 t2 ss)
  | _                              -> []
and unif_uplet_cmp_g su d1h d1t d2 = function
  | []    -> []
  | t::d3 -> (unif_uplet_cmp_f d1t d3 (unif_cmp true(*false*) d1h
                                         (if d2=[] then t
                                          else Uplet (List.rev (t::d2))) su))
           @ (unif_uplet_cmp_g su d1h d1t (t::d2) d3)
and unif_uplet_cmp_h tas lu lv = function
  | s::fin -> 
      let tas = 
        try 
          merge tas (unif_uplet_cmp_f (unif_uplet_norm s lu) (unif_uplet_norm s lv) [s])
        with
          NeedXor -> unif_combi unif_cmp unif_xor true (Uplet lu) (Uplet lv) [s]
      in unif_uplet_cmp_h tas lu lv fin
  | [] -> tas
and unif_cmp (to_purify : bool) (u : term) (v : term) (subs : t_subst list) : t_subst list =
  match (u,v) with
    | (Var(n),t) | (t,Var(n))       -> add unif_cmp (unif_combi unif_cmp unif_xor) to_purify n t [] subs
    | (Atm(n1),Atm(n2))             -> if n1=n2 then subs else []
    | (Uplet(lu),Uplet(lv))         -> 
        if to_purify then 
          unif_uplet_cmp_h [] lu lv subs
        else 
          unif_uplet_cmp_f lu lv subs
    | (PCrypt(m1,k1),PCrypt(m2,k2))
    | (SCrypt(m1,k1),SCrypt(m2,k2)) -> unif_cmp true m1 m2 (unif_cmp to_purify k1 k2 subs)
    | (Uplet([t1]),_)               -> unif_cmp to_purify t1 v subs
    | (_,Uplet([t2]))               -> unif_cmp to_purify u t2 subs
    | (PInv(t1),t2) | (t2,PInv(t1)) ->
        ( match (t1,t2) with
            | (t1, PInv(t2))  | (PInv(t1), t2) 
            | (Uplet([t1]),t2) -> unif_cmp to_purify t1 t2 subs
            | (Xor(_),_)   -> unif_combi unif_cmp unif_xor to_purify t1 (PInv t2) subs
            | (_, Xor(_))  -> unif_combi unif_cmp unif_xor to_purify (PInv t1) t2 subs
            | (Var(_), _)  -> unif_cmp true t1 (PInv t2) subs
            | _            -> [] )
    | (Xor(_),_) | (_,Xor(_))       ->
        (* TODO: we could first test, if it is really an xor problem,
         * because 0 =? Xor[t1;t2] is not really xor,
         * since it is equivalent to t1 =? t2 *)

        unif_combi unif_cmp unif_xor to_purify u v subs
    | (Exp(a,l1),Exp(b,l2))         -> unif_exp unif_cmp a l1 b l2 subs
    | _             -> []