Esempio n. 1
0
//! Retrieve rightmost thing of label
Term
rightMostTerm (Term t)
{
  if (t != NULL)
    {
      t = deVar (t);
      if (realTermTuple (t))
	{
	  return rightMostTerm (TermOp2 (t));
	}
    }
  return t;
}
Esempio n. 2
0
/**
 * Currently, inequality constraints are encoded using "NotEqual" claims.
 *
 * Here we check that their arguments have not become equal. If they are not
 * equal, there always exists a solution in which the values are different. The
 * solution generated by the algorithm that grounds the trace (for
 * visualisation) yields a compatible solution.
 *
 * Return true if okay - constraints can be met
 * Return false if not okay - at least one constraint violated
 *
 * Note that this function performs its own proof output if needed.
 * This allows it to pinpoint the exact constraint that is violated.
 *
 * Speed: this is certainly not the most efficient way to solve this. We are
 * looping over all regular events, even if there are not negative constraints
 * at all. Instead, we could simply collect a list of all negative constraints,
 * which would speed up iterating over it.
 */
int
inequalityConstraints (const System sys)
{
  int run;

  for (run = 0; run < sys->maxruns; run++)
    {
      if (sys->runs[run].protocol != INTRUDER)
	{
	  int e;
	  Roledef rd;

	  rd = sys->runs[run].start;
	  for (e = 0; e < sys->runs[run].step; e++)
	    {
	      if (rd->type == CLAIM)
		{
		  // It's a claim
		  if (isTermEqual (rd->claiminfo->type, CLAIM_Notequal))
		    {
		      // TODO ASSERT: Message should be a pair for NotEqual claims
		      if (isTermEqual
			  (TermOp1 (rd->message), TermOp2 (rd->message)))
			{
			  // Inequality violated, no solution exists that makes them inequal anymore.
			  if (switches.output == PROOF)
			    {
			      indentPrint ();
			      eprintf
				("Pruned because the pattern violates an inequality constraint based on the term ");
			      termPrint (TermOp1 (rd->message));
			      eprintf (".\n");
			    }

			  return false;
			}
		    }
		}
	      rd = rd->next;
	    }
	}
    }
  return true;
}
Esempio n. 3
0
//! Print a term in XML form (iteration inner)
void
xmlTermPrintInner (Term term)
{
  if (term != NULL)
    {
      if (!show_substitution_path)
	{
	  /* In a normal situation, variables are immediately substituted, and
	   * only the result is output.
	   */
	  term = deVar (term);
	}

      if (realTermLeaf (term))
	{
	  // Variable?
	  if (realTermVariable (term))
	    {
	      Term substbuffer;

	      eprintf ("<var name=\"");
	      if (term->subst == NULL)
		{
		  // Free variable
		  termPrint (term);	// Must be a normal termPrint
		  eprintf ("\" free=\"true\" />");
		}
	      else
		{
		  // Bound variable
		  substbuffer = term->subst;	// Temporarily unsubst for printing
		  term->subst = NULL;
		  termPrint (term);	// Must be a normal termPrint
		  term->subst = substbuffer;
		  eprintf ("\">");
		  xmlTermPrintInner (term->subst);
		  eprintf ("</var>");
		}
	    }
	  else
	    {
	      // Constant
	      eprintf ("<const>");
	      termPrint (term);	// Must be a normal termPrint
	      eprintf ("</const>");
	    }
	}
      else
	{
	  // Node
	  if (realTermEncrypt (term))
	    {
	      if (isTermLeaf (TermKey (term))
		  && inTermlist (TermKey (term)->stype, TERM_Function))
		{
		  /* function application */
		  eprintf ("<apply><function>");
		  xmlTermPrintInner (TermKey (term));
		  eprintf ("</function><arg>");
		  xmlTermPrintInner (TermOp (term));
		  eprintf ("</arg></apply>");
		}
	      else
		{
		  eprintf ("<encrypt><op>");
		  xmlTermPrintInner (TermOp (term));
		  eprintf ("</op><key>");
		  xmlTermPrintInner (TermKey (term));
		  eprintf ("</key></encrypt>");
		}
	    }
	  else
	    {
	      // Assume tuple
	      eprintf ("<tuple><op1>");
	      xmlTermPrintInner (TermOp1 (term));
	      eprintf ("</op1><op2>");
	      xmlTermPrintInner (TermOp2 (term));
	      eprintf ("</op2></tuple>");
	    }
	}
    }
}
Esempio n. 4
0
/**
 * Try to determine the most general unifier of two terms.
 * Resulting termlist must be termlistDelete'd.
 *
 *@return Returns a list of variables, that were previously open, but are now closed
 * in such a way that the two terms unify. Returns \ref MGUFAIL if it is impossible.
 * The termlist should be deleted.
 *
 * @TODO this code should be removed, as it duplicates 'unify' code, and is
 * ill-suited for adaption later on with multiple unifiers.
 */
Termlist
termMguTerm (Term t1, Term t2)
{
  /* added for speed */
  t1 = deVar (t1);
  t2 = deVar (t2);
  if (t1 == t2)
    return NULL;

  if (!(hasTermVariable (t1) || hasTermVariable (t2)))
    {
      if (isTermEqual (t1, t2))
	{
	  return NULL;
	}
      else
	{
	  return MGUFAIL;
	}
    }

  /*
   * Distinguish a special case where both are unbound variables that will be
   * connected, and I want to give one priority over the other for readability.
   *
   * Because t1 and t2 have been deVar'd means that if they are variables, they
   * are also unbound.
   */

  if (realTermVariable (t1) && realTermVariable (t2) && goodsubst (t1, t2))
    {
      /* Both are unbound variables. Decide.
       *
       * The plan: t1->subst will point to t2. But maybe we prefer the other
       * way around?
       */
      if (preferSubstitutionOrder (t2, t1))
	{
	  Term t3;

	  // Swappy.
	  t3 = t1;
	  t1 = t2;
	  t2 = t3;
	}
      t1->subst = t2;
#ifdef DEBUG
      showSubst (t1);
#endif
      return termlistAdd (NULL, t1);
    }

  /* symmetrical tests for single variable.
   */

  if (realTermVariable (t2))
    {
      if (termSubTerm (t1, t2) || !goodsubst (t2, t1))
	return MGUFAIL;
      else
	{
	  t2->subst = t1;
#ifdef DEBUG
	  showSubst (t2);
#endif
	  return termlistAdd (NULL, t2);
	}
    }
  if (realTermVariable (t1))
    {
      if (termSubTerm (t2, t1) || !goodsubst (t1, t2))
	return MGUFAIL;
      else
	{
	  t1->subst = t2;
#ifdef DEBUG
	  showSubst (t1);
#endif
	  return termlistAdd (NULL, t1);
	}
    }

  /* left & right are compounds with variables */
  if (t1->type != t2->type)
    return MGUFAIL;

  /* identical compounds */
  /* encryption first */
  if (realTermEncrypt (t1))
    {
      Termlist tl1, tl2;

      tl1 = termMguTerm (TermKey (t1), TermKey (t2));
      if (tl1 == MGUFAIL)
	{
	  return MGUFAIL;
	}
      else
	{
	  tl2 = termMguTerm (TermOp (t1), TermOp (t2));
	  if (tl2 == MGUFAIL)
	    {
	      termlistSubstReset (tl1);
	      termlistDelete (tl1);
	      return MGUFAIL;
	    }
	  else
	    {
	      return termlistConcat (tl1, tl2);
	    }
	}
    }

  /* tupling second
     non-associative version ! TODO other version */
  if (isTermTuple (t1))
    {
      Termlist tl1, tl2;

      tl1 = termMguTerm (TermOp1 (t1), TermOp1 (t2));
      if (tl1 == MGUFAIL)
	{
	  return MGUFAIL;
	}
      else
	{
	  tl2 = termMguTerm (TermOp2 (t1), TermOp2 (t2));
	  if (tl2 == MGUFAIL)
	    {
	      termlistSubstReset (tl1);
	      termlistDelete (tl1);
	      return MGUFAIL;
	    }
	  else
	    {
	      return termlistConcat (tl1, tl2);
	    }
	}
    }
  return MGUFAIL;
}
Esempio n. 5
0
/**
 * Try to unify (a subterm of) tbig with tsmall.
 *
 * Callback is called with a list of substitutions, and a list of terms that
 * need to be decrypted in order for this to work.
 *
 * E.g. subtermUnify ( {{m}k1}k2, m ) yields a list : {{m}k1}k2, {m}k1 (where
 * the {m}k1 is the last added node to the list)
 *
 * The callback should return true for the iteration to proceed, or false to abort.
 * The final result is this flag.
 *
 * This is the actual procedure used by the Arachne algorithm in archne.c
 */
int
subtermUnify (Term tbig, Term tsmall, Termlist tl, Termlist keylist,
	      int (*callback) (), void *state)
{
  int proceed;
  struct su_kcb_state kcb_state;

  kcb_state.oldstate = state;
  kcb_state.callback = callback;
  kcb_state.keylist = keylist;

  proceed = true;

  // Devar
  tbig = deVar (tbig);
  tsmall = deVar (tsmall);

  // Three options:
  // 1. simple unification
  proceed = proceed && unify (tbig, tsmall, tl, keycallback, &kcb_state);

  // [2/3]: complex
  if (switches.intruder)
    {
      // 2. interm unification
      // Only if there is an intruder
      if (realTermTuple (tbig))
	{
	  proceed = proceed
	    && subtermUnify (TermOp1 (tbig), tsmall, tl, keylist, callback,
			     state);
	  proceed = proceed
	    && subtermUnify (TermOp2 (tbig), tsmall, tl, keylist, callback,
			     state);
	}

      // 3. unification with encryption needed
      if (realTermEncrypt (tbig))
	{
	  // extend the keylist
	  keylist = termlistAdd (keylist, tbig);
	  proceed = proceed
	    && subtermUnify (TermOp (tbig), tsmall, tl, keylist, callback,
			     state);
	  // remove last item again
	  keylist = termlistDelTerm (keylist);
	}
    }

  // Athena problem case: open variable about to be unified.
	  /**
	   * In this case we really need to consider the problematic Athena case for untyped variables.
	   */
  if (isTermVariable (tbig))
    {
      // Check the type: can it contain tuples, encryptions?
      if (isOpenVariable (tbig))
	{
	  // This one needs to be pursued by further constraint adding
	  /**
	   * Currently, this is not implemented yet. TODO.
	   * This is actually the main Athena problem that we haven't solved yet.
	   */
	  // Mark that we don't have a full proof, and possibly remark in proof output.
	  markNoFullProof (tbig, tsmall);
	}
    }

  return proceed;
}
Esempio n. 6
0
/**
 * Try to determine the most general unifier of two terms, if so calls function.
 *
 * int callback(Termlist, *state)
 *
 * The callback receives a list of variables, that were previously open, but are now closed
 * in such a way that the two terms unify. 
 *
 * The callback must return true for the iteration to proceed: if it returns false, a single call would abort the scan.
 * The return value shows this: it is false if the scan was aborted, and true if not.
 */
int
unify (Term t1, Term t2, Termlist tl, int (*callback) (), void *state)
{
  /* added for speed */
  t1 = deVar (t1);
  t2 = deVar (t2);
  if (t1 == t2)
    {
      return callback (tl, state);
    }

  if (!(hasTermVariable (t1) || hasTermVariable (t2)))
    {
      // None has a variable
      if (isTermEqual (t1, t2))
	{
	  // Equal!
	  return callback (tl, state);
	}
      else
	{
	  // Can never be fixed, no variables
	  return true;
	}
    }

  /*
   * Distinguish a special case where both are unbound variables that will be
   * connected, and I want to give one priority over the other for readability.
   *
   * Because t1 and t2 have been deVar'd means that if they are variables, they
   * are also unbound.
   */

  if (realTermVariable (t1) && realTermVariable (t2) && goodsubst (t1, t2))
    {
      /* Both are unbound variables. Decide.
       *
       * The plan: t1->subst will point to t2. But maybe we prefer the other
       * way around?
       */
      if (preferSubstitutionOrder (t2, t1))
	{
	  Term t3;

	  // Swappy.
	  t3 = t1;
	  t1 = t2;
	  t2 = t3;
	}
      return callsubst (callback, state, tl, t1, t2);
    }

  /* symmetrical tests for single variable.
   */

  if (realTermVariable (t2))
    {
      if (termSubTerm (t1, t2) || !goodsubst (t2, t1))
	return true;
      else
	{
	  return callsubst (callback, state, tl, t2, t1);
	}
    }
  if (realTermVariable (t1))
    {
      if (termSubTerm (t2, t1) || !goodsubst (t1, t2))
	return true;
      else
	{
	  return callsubst (callback, state, tl, t1, t2);
	}
    }

  /* left & right are compounds with variables */
  if (t1->type != t2->type)
    return true;

  /* identical compound types */

  /* encryption first */
  if (realTermEncrypt (t1))
    {
      struct state_mgu_tmp tmpstate;

      tmpstate.oldstate = state;
      tmpstate.oldcallback = callback;
      tmpstate.unifyt1 = TermOp (t1);
      tmpstate.unifyt2 = TermOp (t2);

      return unify (TermKey (t1), TermKey (t2), tl, unify_callback_wrapper,
		    &tmpstate);
    }

  /* tupling second
     non-associative version ! TODO other version */
  if (isTermTuple (t1))
    {
      struct state_mgu_tmp tmpstate;

      tmpstate.oldstate = state;
      tmpstate.oldcallback = callback;
      tmpstate.unifyt1 = TermOp2 (t1);
      tmpstate.unifyt2 = TermOp2 (t2);

      return unify (TermOp1 (t1), TermOp1 (t2), tl, unify_callback_wrapper,
		    &tmpstate);
    }

  return true;
}