Rati Gelashvili reported a rare but annoying bug in the hash function handling.
The fix requires a significant reworking of the function handling. This is a first attempt. Conflicts: src/knowledge.c src/knowledge.h Regression test suggests that the Hashfunction fix works.
This commit is contained in:
parent
4a1898db92
commit
7658644295
@ -787,7 +787,7 @@ createDecryptionChain (const Binding b, const int run, const int index,
|
|||||||
indentDepth++;
|
indentDepth++;
|
||||||
|
|
||||||
tdecr = keylist->term;
|
tdecr = keylist->term;
|
||||||
tkey = inverseKey (sys->know->inverses, TermKey (tdecr));
|
tkey = inverseKey (sys->know, TermKey (tdecr));
|
||||||
smallrun = create_decryptor (tdecr, tkey);
|
smallrun = create_decryptor (tdecr, tkey);
|
||||||
{
|
{
|
||||||
Roledef rddecrypt;
|
Roledef rddecrypt;
|
||||||
|
@ -1101,7 +1101,7 @@ hashfunctions (Tac tcstart)
|
|||||||
error
|
error
|
||||||
("Bug in hashfunction generation code. Please contact the authors.\n");
|
("Bug in hashfunction generation code. Please contact the authors.\n");
|
||||||
}
|
}
|
||||||
knowledgeAddInverse (sys->know, hfuncs->term, hinvs->term);
|
knowledgeAddInverseKeys (sys->know, hfuncs->term, hinvs->term);
|
||||||
hfuncs->term->stype = termlistAdd (NULL, TERM_Function);
|
hfuncs->term->stype = termlistAdd (NULL, TERM_Function);
|
||||||
hinvs->term->stype = termlistAdd (NULL, TERM_Function);
|
hinvs->term->stype = termlistAdd (NULL, TERM_Function);
|
||||||
hfuncs = hfuncs->next;
|
hfuncs = hfuncs->next;
|
||||||
@ -1157,8 +1157,12 @@ normalDeclaration (Tac tc)
|
|||||||
knowledgeAddTermlist (sys->know, tacTermlist (tc->t1.tac));
|
knowledgeAddTermlist (sys->know, tacTermlist (tc->t1.tac));
|
||||||
break;
|
break;
|
||||||
case TAC_INVERSEKEYS:
|
case TAC_INVERSEKEYS:
|
||||||
knowledgeAddInverse (sys->know, tacTerm (tc->t1.tac),
|
knowledgeAddInverseKeys (sys->know, tacTerm (tc->t1.tac),
|
||||||
tacTerm (tc->t2.tac));
|
tacTerm (tc->t2.tac));
|
||||||
|
break;
|
||||||
|
case TAC_INVERSEKEYFUNCTIONS:
|
||||||
|
knowledgeAddInverseKeyFunctions (sys->know, tacTerm (tc->t1.tac),
|
||||||
|
tacTerm (tc->t2.tac));
|
||||||
break;
|
break;
|
||||||
case TAC_HASHFUNCTION:
|
case TAC_HASHFUNCTION:
|
||||||
hashfunctions (tc);
|
hashfunctions (tc);
|
||||||
@ -1568,8 +1572,14 @@ tacProcess (Tac tc)
|
|||||||
Term
|
Term
|
||||||
tacTerm (Tac tc)
|
tacTerm (Tac tc)
|
||||||
{
|
{
|
||||||
|
Term t;
|
||||||
|
|
||||||
switch (tc->op)
|
switch (tc->op)
|
||||||
{
|
{
|
||||||
|
case TAC_FCALL:
|
||||||
|
t = makeTermEncrypt (tacTerm (tc->t1.tac), tacTerm (tc->t2.tac));
|
||||||
|
t->helper.fcall = true;
|
||||||
|
return t;
|
||||||
case TAC_ENCRYPT:
|
case TAC_ENCRYPT:
|
||||||
return makeTermEncrypt (tacTerm (tc->t1.tac), tacTerm (tc->t2.tac));
|
return makeTermEncrypt (tacTerm (tc->t1.tac), tacTerm (tc->t2.tac));
|
||||||
case TAC_TUPLE:
|
case TAC_TUPLE:
|
||||||
|
@ -96,7 +96,7 @@ isIntruderChoice (const Term t)
|
|||||||
{
|
{
|
||||||
// Chosen by intruder
|
// Chosen by intruder
|
||||||
// However, if it is a rolename, this is not really what we mean
|
// However, if it is a rolename, this is not really what we mean
|
||||||
if (!(t->roleVar || isAgentType (t->stype)))
|
if (!(t->helper.roleVar || isAgentType (t->stype)))
|
||||||
{
|
{
|
||||||
// Not a role variable, and chosen by the intruder: that's it
|
// Not a role variable, and chosen by the intruder: that's it
|
||||||
return true;
|
return true;
|
||||||
@ -187,12 +187,12 @@ explainVariable (Term t)
|
|||||||
if (realTermVariable (t))
|
if (realTermVariable (t))
|
||||||
{
|
{
|
||||||
eprintf ("any ");
|
eprintf ("any ");
|
||||||
if (t->roleVar)
|
if (t->helper.roleVar)
|
||||||
{
|
{
|
||||||
eprintf ("agent ");
|
eprintf ("agent ");
|
||||||
}
|
}
|
||||||
termPrintRemap (t);
|
termPrintRemap (t);
|
||||||
if (!t->roleVar)
|
if (!t->helper.roleVar)
|
||||||
{
|
{
|
||||||
if (switches.match == 0 && t->stype != NULL)
|
if (switches.match == 0 && t->stype != NULL)
|
||||||
{
|
{
|
||||||
|
192
src/knowledge.c
192
src/knowledge.c
@ -30,19 +30,10 @@
|
|||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "specialterm.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Knowledge stuff
|
* Knowledge stuff
|
||||||
*
|
|
||||||
* Note that a really weird thing is going on involving unpropagated substitutions.
|
|
||||||
* Idea:
|
|
||||||
*
|
|
||||||
* 1. Substitute terms by filling in ->subst.
|
|
||||||
* Now, either:
|
|
||||||
* 2a. Undo this by knowledgeUndo.
|
|
||||||
* 2b. Propagate it, modifying the knowledge beyond repair by knowledgeSubstDo. Now inKnowledge works again.
|
|
||||||
* 2c. inKnowledge/knowledgeSet if something is in the knowledge: this does not consider the substitutions!, and
|
|
||||||
* they now have some overhead.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//! Open knowledge code.
|
//! Open knowledge code.
|
||||||
@ -81,7 +72,8 @@ emptyKnowledge ()
|
|||||||
know = makeKnowledge ();
|
know = makeKnowledge ();
|
||||||
know->basic = NULL;
|
know->basic = NULL;
|
||||||
know->encrypt = NULL;
|
know->encrypt = NULL;
|
||||||
know->inverses = NULL;
|
know->inversekeys = NULL;
|
||||||
|
know->inversekeyfunctions = NULL;
|
||||||
know->vars = NULL;
|
know->vars = NULL;
|
||||||
know->publicfunctions = NULL;
|
know->publicfunctions = NULL;
|
||||||
return know;
|
return know;
|
||||||
@ -110,7 +102,8 @@ knowledgeDuplicate (Knowledge know)
|
|||||||
newknow->basic = termlistShallow (know->basic);
|
newknow->basic = termlistShallow (know->basic);
|
||||||
newknow->encrypt = termlistShallow (know->encrypt);
|
newknow->encrypt = termlistShallow (know->encrypt);
|
||||||
newknow->vars = termlistShallow (know->vars);
|
newknow->vars = termlistShallow (know->vars);
|
||||||
newknow->inverses = know->inverses;
|
newknow->inversekeys = know->inversekeys;
|
||||||
|
newknow->inversekeyfunctions = know->inversekeyfunctions;
|
||||||
newknow->publicfunctions = termlistShallow (know->publicfunctions);
|
newknow->publicfunctions = termlistShallow (know->publicfunctions);
|
||||||
return newknow;
|
return newknow;
|
||||||
}
|
}
|
||||||
@ -147,7 +140,8 @@ knowledgeDestroy (Knowledge know)
|
|||||||
termlistDestroy (know->basic);
|
termlistDestroy (know->basic);
|
||||||
termlistDestroy (know->encrypt);
|
termlistDestroy (know->encrypt);
|
||||||
termlistDestroy (know->vars);
|
termlistDestroy (know->vars);
|
||||||
// termlistDestroy(know->inverses);
|
// termlistDestroy(know->inversekeys);
|
||||||
|
// termlistDestroy(know->inversekeyfunctions);
|
||||||
termlistDestroy (know->publicfunctions);
|
termlistDestroy (know->publicfunctions);
|
||||||
free (know);
|
free (know);
|
||||||
}
|
}
|
||||||
@ -195,7 +189,7 @@ knowledgeAddTerm (Knowledge know, Term term)
|
|||||||
}
|
}
|
||||||
if (term->type == ENCRYPT)
|
if (term->type == ENCRYPT)
|
||||||
{
|
{
|
||||||
Term invkey = inverseKey (know->inverses, TermKey (term));
|
Term invkey = inverseKey (know, TermKey (term));
|
||||||
if (inKnowledge (know, invkey))
|
if (inKnowledge (know, invkey))
|
||||||
{
|
{
|
||||||
/* we can decrypt it */
|
/* we can decrypt it */
|
||||||
@ -227,7 +221,7 @@ knowledgeSimplify (Knowledge know, Term key)
|
|||||||
{
|
{
|
||||||
Termlist tldecrypts = NULL;
|
Termlist tldecrypts = NULL;
|
||||||
Termlist scan = know->encrypt;
|
Termlist scan = know->encrypt;
|
||||||
Term invkey = inverseKey (know->inverses, key);
|
Term invkey = inverseKey (know, key);
|
||||||
|
|
||||||
while (scan != NULL)
|
while (scan != NULL)
|
||||||
{
|
{
|
||||||
@ -257,6 +251,7 @@ knowledgeAddTermlist (Knowledge know, Termlist tl)
|
|||||||
|
|
||||||
while (tl != NULL)
|
while (tl != NULL)
|
||||||
{
|
{
|
||||||
|
// Evil old fashioned code relies on lazy left-to-right parsing. Get rid of it.
|
||||||
flag = knowledgeAddTerm (know, tl->term) || flag;
|
flag = knowledgeAddTerm (know, tl->term) || flag;
|
||||||
tl = tl->next;
|
tl = tl->next;
|
||||||
}
|
}
|
||||||
@ -265,21 +260,18 @@ knowledgeAddTermlist (Knowledge know, Termlist tl)
|
|||||||
|
|
||||||
//! Add an inverse pair to the knowledge
|
//! Add an inverse pair to the knowledge
|
||||||
void
|
void
|
||||||
knowledgeAddInverse (Knowledge know, Term t1, Term t2)
|
knowledgeAddInverseKeys (Knowledge know, Term t1, Term t2)
|
||||||
{
|
{
|
||||||
know->inverses = termlistAdd (know->inverses, t1);
|
know->inversekeys = termlistAdd (know->inversekeys, t1);
|
||||||
know->inverses = termlistAdd (know->inverses, t2);
|
know->inversekeys = termlistAdd (know->inversekeys, t2);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Set an inverse pair list for the knowledge.
|
//! Add an inverse pair to the knowledge
|
||||||
/**
|
|
||||||
* List pointer is simply copied, so don't delete it later!
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
knowledgeSetInverses (Knowledge know, Termlist tl)
|
knowledgeAddInverseKeyFunctions (Knowledge know, Term t1, Term t2)
|
||||||
{
|
{
|
||||||
know->inverses = tl;
|
know->inversekeyfunctions = termlistAdd (know->inversekeyfunctions, t1);
|
||||||
|
know->inversekeyfunctions = termlistAdd (know->inversekeyfunctions, t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Is a term a part of the knowledge?
|
//! Is a term a part of the knowledge?
|
||||||
@ -341,6 +333,15 @@ knowledgePrint (Knowledge know)
|
|||||||
eprintf (" [Vars]: ");
|
eprintf (" [Vars]: ");
|
||||||
termlistPrint (know->vars);
|
termlistPrint (know->vars);
|
||||||
eprintf ("\n");
|
eprintf ("\n");
|
||||||
|
eprintf (" [Inversekeys]: ");
|
||||||
|
termlistPrint (know->inversekeys);
|
||||||
|
eprintf ("\n");
|
||||||
|
eprintf (" [Inversekeyfunctions]: ");
|
||||||
|
termlistPrint (know->inversekeyfunctions);
|
||||||
|
eprintf ("\n");
|
||||||
|
eprintf (" [Publicfunctions]: ");
|
||||||
|
termlistPrint (know->publicfunctions);
|
||||||
|
eprintf ("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Print a knowledge set, short version (no newline)
|
//! Print a knowledge set, short version (no newline)
|
||||||
@ -368,43 +369,6 @@ knowledgePrintShort (const Knowledge know)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Print the inverses list of a knowledge set.
|
|
||||||
void
|
|
||||||
knowledgeInversesPrint (Knowledge know)
|
|
||||||
{
|
|
||||||
Termlist tl;
|
|
||||||
int after = 0;
|
|
||||||
|
|
||||||
if (know == NULL)
|
|
||||||
{
|
|
||||||
eprintf ("Empty knowledge.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tl = knowledgeGetInverses (know);
|
|
||||||
if (tl == NULL)
|
|
||||||
{
|
|
||||||
eprintf ("None.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while (tl != NULL && tl->next != NULL)
|
|
||||||
{
|
|
||||||
if (after)
|
|
||||||
{
|
|
||||||
eprintf (",");
|
|
||||||
}
|
|
||||||
eprintf ("(");
|
|
||||||
termPrint (tl->term);
|
|
||||||
eprintf (",");
|
|
||||||
termPrint (tl->next->term);
|
|
||||||
eprintf (")");
|
|
||||||
after = 1;
|
|
||||||
tl = tl->next->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Yield the set of representatives for the knowledge.
|
//! Yield the set of representatives for the knowledge.
|
||||||
/**
|
/**
|
||||||
* Note: this is a shallow copy, and needs to be termlistDelete'd.
|
* Note: this is a shallow copy, and needs to be termlistDelete'd.
|
||||||
@ -420,17 +384,11 @@ knowledgeSet (const Knowledge know)
|
|||||||
return termlistConcat (tl1, tl2);
|
return termlistConcat (tl1, tl2);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Get the inverses pointer of the knowledge.
|
//! Check for elements in the knowledge set
|
||||||
/**
|
int
|
||||||
* Essentially the inverse function of knowledgeSetInverses()
|
inKnowledgeSet (const Knowledge know, Term t)
|
||||||
*/
|
|
||||||
Termlist
|
|
||||||
knowledgeGetInverses (const Knowledge know)
|
|
||||||
{
|
{
|
||||||
if (know == NULL)
|
return (inTermlist (know->basic, t) || inTermlist (know->encrypt, t));
|
||||||
return NULL;
|
|
||||||
else
|
|
||||||
return know->inverses;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! check whether any substitutions where made in a knowledge set.
|
//! check whether any substitutions where made in a knowledge set.
|
||||||
@ -457,37 +415,6 @@ knowledgeSubstNeeded (const Knowledge know)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Reconstruct a knowledge set.
|
|
||||||
/**
|
|
||||||
* This is useful after e.g. substitutions.
|
|
||||||
* Just rebuilds the knowledge in a new (shallow) copy.
|
|
||||||
*@return The pointer to the new knowledge.
|
|
||||||
*\sa knowledgeSubstNeeded()
|
|
||||||
*/
|
|
||||||
Knowledge
|
|
||||||
knowledgeReconstruction (const Knowledge know)
|
|
||||||
{
|
|
||||||
Knowledge newknow = emptyKnowledge ();
|
|
||||||
|
|
||||||
newknow->inverses = know->inverses;
|
|
||||||
knowledgeAddTermlist (newknow, know->basic);
|
|
||||||
knowledgeAddTermlist (newknow, know->encrypt);
|
|
||||||
return newknow;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Propagate any substitutions just made.
|
|
||||||
/**
|
|
||||||
* This usually involves reconstruction of the complete knowledge, which is
|
|
||||||
* 'cheaper' than a thorough analysis, so we always make a copy.
|
|
||||||
*\sa knowledgeReconstruction()
|
|
||||||
*/
|
|
||||||
Knowledge
|
|
||||||
knowledgeSubstDo (const Knowledge know)
|
|
||||||
{
|
|
||||||
/* otherwise a copy (for deletion) is returned. */
|
|
||||||
return knowledgeReconstruction (know);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Add public function
|
//! Add public function
|
||||||
void
|
void
|
||||||
knowledgeAddPublicFunction (const Knowledge know, const Term f)
|
knowledgeAddPublicFunction (const Knowledge know, const Term f)
|
||||||
@ -502,3 +429,62 @@ isKnowledgePublicFunction (const Knowledge know, const Term f)
|
|||||||
{
|
{
|
||||||
return inTermlist (know->publicfunctions, f);
|
return inTermlist (know->publicfunctions, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Give the inverse key term of a term.
|
||||||
|
/**
|
||||||
|
* Gives a duplicate of the inverse Key of some term (which is used to encrypt something), as is defined
|
||||||
|
* by the termlist, which is a list of key1,key1inv, key2, key2inv, etc...
|
||||||
|
*@param inverses The list of inverses, typically from the knowledge.
|
||||||
|
*@param key Any term of which the inverse will be determined.
|
||||||
|
*@return A pointer to a duplicate of the inverse key term. Use termDelete to remove it.
|
||||||
|
*\sa termDuplicate(), knowledge::inverses
|
||||||
|
*/
|
||||||
|
Term
|
||||||
|
inverseKey (Knowledge know, Term key)
|
||||||
|
{
|
||||||
|
Term f;
|
||||||
|
|
||||||
|
key = deVar (key);
|
||||||
|
|
||||||
|
/* inverse key function? */
|
||||||
|
f = getTermFunction (key);
|
||||||
|
if (f != NULL)
|
||||||
|
{
|
||||||
|
Termlist tl;
|
||||||
|
|
||||||
|
Term funKey (Term orig, Term f)
|
||||||
|
{
|
||||||
|
/* in: f'{op}, f
|
||||||
|
* out: f{op'} */
|
||||||
|
return makeTermFcall (termDuplicate (TermOp (orig)),
|
||||||
|
termDuplicate (f));
|
||||||
|
}
|
||||||
|
|
||||||
|
tl = know->inversekeyfunctions;
|
||||||
|
while (tl != NULL && tl->next != NULL)
|
||||||
|
{
|
||||||
|
if (isTermEqual (TermKey (key), tl->term))
|
||||||
|
return funKey (key, tl->next->term);
|
||||||
|
if (isTermEqual (TermKey (key), tl->next->term))
|
||||||
|
return funKey (key, tl->term);
|
||||||
|
tl = tl->next->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* scanning for a direct inverse */
|
||||||
|
Termlist tl;
|
||||||
|
|
||||||
|
/* scan the list */
|
||||||
|
tl = know->inversekeys;
|
||||||
|
while (tl != NULL && tl->next != NULL)
|
||||||
|
{
|
||||||
|
if (isTermEqual (key, tl->term))
|
||||||
|
return termDuplicate (tl->next->term);
|
||||||
|
if (isTermEqual (key, tl->next->term))
|
||||||
|
return termDuplicate (tl->term);
|
||||||
|
tl = tl->next->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return termDuplicate (key); /* defaults to symmetrical */
|
||||||
|
}
|
||||||
|
@ -33,8 +33,10 @@ struct knowledge
|
|||||||
Termlist basic;
|
Termlist basic;
|
||||||
//! A list of terms encrypted, such that the inverse is not in the knowledge set.
|
//! A list of terms encrypted, such that the inverse is not in the knowledge set.
|
||||||
Termlist encrypt;
|
Termlist encrypt;
|
||||||
//! List of inverse pairs (thus length of list is even)
|
//! List of inverse pairs (thus length of list is even) (add,sub)
|
||||||
Termlist inverses;
|
Termlist inversekeys;
|
||||||
|
//! List of inverse pairs (thus length of list is even) (pk,sk)
|
||||||
|
Termlist inversekeyfunctions;
|
||||||
//! List of open variables in the knowledge set.
|
//! List of open variables in the knowledge set.
|
||||||
/**
|
/**
|
||||||
* This list is used to determine whether the knowledge needs to be rewritten.
|
* This list is used to determine whether the knowledge needs to be rewritten.
|
||||||
@ -42,7 +44,7 @@ struct knowledge
|
|||||||
* and we need to reconstruct the knowledge set.
|
* and we need to reconstruct the knowledge set.
|
||||||
*/
|
*/
|
||||||
Termlist vars; // special: denotes unsubstituted variables
|
Termlist vars; // special: denotes unsubstituted variables
|
||||||
//! A list of public functions
|
//! A list of hash functions
|
||||||
Termlist publicfunctions;
|
Termlist publicfunctions;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,19 +60,19 @@ void knowledgeDelete (Knowledge know);
|
|||||||
void knowledgeDestroy (Knowledge know);
|
void knowledgeDestroy (Knowledge know);
|
||||||
int knowledgeAddTerm (Knowledge know, Term term);
|
int knowledgeAddTerm (Knowledge know, Term term);
|
||||||
int knowledgeAddTermlist (Knowledge know, Termlist tl);
|
int knowledgeAddTermlist (Knowledge know, Termlist tl);
|
||||||
void knowledgeAddInverse (Knowledge know, Term t1, Term t2);
|
void knowledgeAddInverseKeys (Knowledge know, Term t1, Term t2);
|
||||||
void knowledgeSetInverses (Knowledge know, Termlist tl);
|
void knowledgeAddInverseKeyFunctions (Knowledge know, Term t1, Term t2);
|
||||||
|
int inKnowledgeSet (const Knowledge know, Term t);
|
||||||
void knowledgeSimplify (Knowledge know, Term decryptkey);
|
void knowledgeSimplify (Knowledge know, Term decryptkey);
|
||||||
int inKnowledge (const Knowledge know, Term term);
|
int inKnowledge (const Knowledge know, Term term);
|
||||||
void knowledgePrint (Knowledge know);
|
void knowledgePrint (Knowledge know);
|
||||||
void knowledgePrintShort (const Knowledge know);
|
void knowledgePrintShort (const Knowledge know);
|
||||||
void knowledgeInversesPrint (Knowledge know);
|
|
||||||
Termlist knowledgeSet (const Knowledge know);
|
Termlist knowledgeSet (const Knowledge know);
|
||||||
Termlist knowledgeGetInverses (const Knowledge know);
|
|
||||||
int knowledgeSubstNeeded (const Knowledge know);
|
int knowledgeSubstNeeded (const Knowledge know);
|
||||||
Knowledge knowledgeSubstDo (const Knowledge know);
|
Knowledge knowledgeSubstDo (const Knowledge know);
|
||||||
void knowledgeAddPublicFunction (const Knowledge know, const Term f);
|
void knowledgeAddPublicFunction (const Knowledge know, const Term f);
|
||||||
int isKnowledgePublicFunction (const Knowledge know, const Term f);
|
int isKnowledgePublicFunction (const Knowledge know, const Term f);
|
||||||
|
Term inverseKey (Knowledge know, Term key);
|
||||||
|
|
||||||
//! Harnass macro for recursive procedures.
|
//! Harnass macro for recursive procedures.
|
||||||
#define mindwipe(k,recurse) \
|
#define mindwipe(k,recurse) \
|
||||||
|
@ -149,9 +149,6 @@ main (int argc, char **argv)
|
|||||||
termlistPrint (sys->untrusted);
|
termlistPrint (sys->untrusted);
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
knowledgePrint (sys->know);
|
knowledgePrint (sys->know);
|
||||||
printf ("inverses: ");
|
|
||||||
knowledgeInversesPrint (sys->know);
|
|
||||||
printf ("\n");
|
|
||||||
locVarPrint (sys->locals);
|
locVarPrint (sys->locals);
|
||||||
protocolsPrint (sys->protocols);
|
protocolsPrint (sys->protocols);
|
||||||
|
|
||||||
|
@ -82,6 +82,7 @@ List findMacroDefinition(Symbol s)
|
|||||||
%token SECRET
|
%token SECRET
|
||||||
%token COMPROMISED
|
%token COMPROMISED
|
||||||
%token INVERSEKEYS
|
%token INVERSEKEYS
|
||||||
|
%token INVERSEKEYFUNCTIONS
|
||||||
%token UNTRUSTED
|
%token UNTRUSTED
|
||||||
%token USERTYPE
|
%token USERTYPE
|
||||||
%token SINGULAR
|
%token SINGULAR
|
||||||
@ -356,6 +357,12 @@ declaration : secretpref CONST basictermlist typeinfo1 ';'
|
|||||||
t->t2.tac = $5;
|
t->t2.tac = $5;
|
||||||
$$ = t;
|
$$ = t;
|
||||||
}
|
}
|
||||||
|
| INVERSEKEYFUNCTIONS '(' term ',' term ')' ';'
|
||||||
|
{ Tac t = tacCreate(TAC_INVERSEKEYFUNCTIONS);
|
||||||
|
t->t1.tac = $3;
|
||||||
|
t->t2.tac = $5;
|
||||||
|
$$ = t;
|
||||||
|
}
|
||||||
| COMPROMISED termlist ';'
|
| COMPROMISED termlist ';'
|
||||||
{ Tac t = tacCreate(TAC_COMPROMISED);
|
{ Tac t = tacCreate(TAC_COMPROMISED);
|
||||||
t->t1.tac= $2;
|
t->t1.tac= $2;
|
||||||
@ -456,7 +463,7 @@ term : ID '(' termlist ')'
|
|||||||
{
|
{
|
||||||
Tac t = tacCreate(TAC_STRING);
|
Tac t = tacCreate(TAC_STRING);
|
||||||
t->t1.sym = $1;
|
t->t1.sym = $1;
|
||||||
$$ = tacJoin(TAC_ENCRYPT,tacTuple($3),t,NULL);
|
$$ = tacJoin(TAC_FCALL,tacTuple($3),t,NULL);
|
||||||
}
|
}
|
||||||
| '{' termlist '}' key
|
| '{' termlist '}' key
|
||||||
{
|
{
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
Passed wall time in seconds:
|
|
||||||
0
|
|
@ -1,2 +1,2 @@
|
|||||||
Passed wall time in seconds:
|
Passed wall time in seconds:
|
||||||
14
|
15
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
Passed wall time in seconds:
|
Passed wall time in seconds:
|
||||||
23
|
24
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
Passed wall time in seconds:
|
Passed wall time in seconds:
|
||||||
28
|
29
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
claim spliceAS-HC,I Secret_7 N2 Ok [no attack within bounds] time=60
|
claim spliceAS-HC,I Secret_7 N2 Fail [at least 7 attacks]
|
||||||
claim spliceAS-HC,I Niagree_9 - Ok [does not occur] time=60
|
claim spliceAS-HC,I Niagree_9 - Fail [at least 1 attack]
|
||||||
claim spliceAS-HC,I Nisynch_10 - Ok [does not occur] time=60
|
claim spliceAS-HC,I Nisynch_10 - Fail [at least 1 attack]
|
||||||
claim spliceAS-HC,R Secret_8 N2 Ok [no attack within bounds] time=60
|
claim spliceAS-HC,R Secret_8 N2 Fail [at least 7 attacks]
|
||||||
claim spliceAS-HC,R Niagree_11 - Ok [does not occur] time=60
|
claim spliceAS-HC,R Niagree_11 - Fail [at least 1 attack]
|
||||||
claim spliceAS-HC,R Nisynch_12 - Ok [does not occur] time=60
|
claim spliceAS-HC,R Nisynch_12 - Fail [at least 1 attack]
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
Passed wall time in seconds:
|
Passed wall time in seconds:
|
||||||
60
|
6
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
claim spliceAS,I Secret_7 N2 Ok [no attack within bounds] time=60
|
claim spliceAS,I Secret_7 N2 Fail [at least 7 attacks]
|
||||||
claim spliceAS,I Niagree_9 - Ok [does not occur] time=60
|
claim spliceAS,I Niagree_9 - Fail [at least 1 attack]
|
||||||
claim spliceAS,I Nisynch_10 - Ok [does not occur] time=60
|
claim spliceAS,I Nisynch_10 - Fail [at least 1 attack]
|
||||||
claim spliceAS,R Secret_8 N2 Ok [no attack within bounds] time=60
|
claim spliceAS,R Secret_8 N2 Fail [at least 7 attacks]
|
||||||
claim spliceAS,R Niagree_11 - Ok [does not occur] time=60
|
claim spliceAS,R Niagree_11 - Fail [at least 1 attack]
|
||||||
claim spliceAS,R Nisynch_12 - Ok [does not occur] time=60
|
claim spliceAS,R Nisynch_12 - Fail [at least 1 attack]
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
Passed wall time in seconds:
|
Passed wall time in seconds:
|
||||||
60
|
6
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
Passed wall time in seconds:
|
Passed wall time in seconds:
|
||||||
36
|
37
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
Passed wall time in seconds:
|
|
||||||
0
|
|
@ -415,7 +415,7 @@ Readable (Knowledge know, Term t)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Right disjunct
|
// Right disjunct
|
||||||
inv = inverseKey (know->inverses, TermKey (t));
|
inv = inverseKey (know, TermKey (t));
|
||||||
either = false;
|
either = false;
|
||||||
if (inKnowledge (know, inv))
|
if (inKnowledge (know, inv))
|
||||||
{
|
{
|
||||||
|
@ -171,6 +171,7 @@ claim { return CLAIMT; }
|
|||||||
run { return RUN; }
|
run { return RUN; }
|
||||||
secret { return SECRET; }
|
secret { return SECRET; }
|
||||||
inversekeys { return INVERSEKEYS; }
|
inversekeys { return INVERSEKEYS; }
|
||||||
|
inversekeyfunctions { return INVERSEKEYFUNCTIONS; }
|
||||||
untrusted { return UNTRUSTED; }
|
untrusted { return UNTRUSTED; }
|
||||||
compromised { return COMPROMISED; }
|
compromised { return COMPROMISED; }
|
||||||
usertype { return USERTYPE; }
|
usertype { return USERTYPE; }
|
||||||
|
@ -119,7 +119,7 @@ specialTermInit (const System sys)
|
|||||||
langcons (TERM_PK, "pk", TERM_Function);
|
langcons (TERM_PK, "pk", TERM_Function);
|
||||||
langcons (TERM_SK, "sk", TERM_Function);
|
langcons (TERM_SK, "sk", TERM_Function);
|
||||||
langcons (TERM_K, "k", TERM_Function);
|
langcons (TERM_K, "k", TERM_Function);
|
||||||
knowledgeAddInverse (sys->know, TERM_PK, TERM_SK);
|
knowledgeAddInverseKeyFunctions (sys->know, TERM_PK, TERM_SK);
|
||||||
knowledgeAddTerm (sys->know, TERM_PK);
|
knowledgeAddTerm (sys->know, TERM_PK);
|
||||||
|
|
||||||
/* Define a prefix for labels for the match function */
|
/* Define a prefix for labels for the match function */
|
||||||
|
@ -504,7 +504,7 @@ roleInstanceArachne (const System sys, const Protocol protocol,
|
|||||||
newt = makeTermType (GLOBAL, TermSymb (oldt), rid);
|
newt = makeTermType (GLOBAL, TermSymb (oldt), rid);
|
||||||
}
|
}
|
||||||
newt->stype = oldt->stype; // copy list of types
|
newt->stype = oldt->stype; // copy list of types
|
||||||
newt->roleVar = isrole; // set role status
|
newt->helper.roleVar = isrole; // set role status
|
||||||
|
|
||||||
// Add to copy list
|
// Add to copy list
|
||||||
TERMLISTADD (fromlist, oldt);
|
TERMLISTADD (fromlist, oldt);
|
||||||
|
@ -32,6 +32,7 @@ enum tactypes
|
|||||||
TAC_SYM,
|
TAC_SYM,
|
||||||
TAC_TUPLE,
|
TAC_TUPLE,
|
||||||
TAC_ENCRYPT,
|
TAC_ENCRYPT,
|
||||||
|
TAC_FCALL,
|
||||||
TAC_VAR,
|
TAC_VAR,
|
||||||
TAC_CONST,
|
TAC_CONST,
|
||||||
TAC_FRESH,
|
TAC_FRESH,
|
||||||
@ -48,6 +49,7 @@ enum tactypes
|
|||||||
TAC_ROLEREF,
|
TAC_ROLEREF,
|
||||||
TAC_SECRET,
|
TAC_SECRET,
|
||||||
TAC_INVERSEKEYS,
|
TAC_INVERSEKEYS,
|
||||||
|
TAC_INVERSEKEYFUNCTIONS,
|
||||||
TAC_HASHFUNCTION,
|
TAC_HASHFUNCTION,
|
||||||
TAC_UNTRUSTED,
|
TAC_UNTRUSTED,
|
||||||
TAC_COMPROMISED,
|
TAC_COMPROMISED,
|
||||||
|
68
src/term.c
68
src/term.c
@ -84,6 +84,9 @@ makeTerm ()
|
|||||||
|
|
||||||
//! Create a fresh encrypted term from two existing terms.
|
//! Create a fresh encrypted term from two existing terms.
|
||||||
/**
|
/**
|
||||||
|
* The first argument is the message,
|
||||||
|
* the second argument is the key.
|
||||||
|
*
|
||||||
*@return A pointer to the new term.
|
*@return A pointer to the new term.
|
||||||
*/
|
*/
|
||||||
Term
|
Term
|
||||||
@ -92,11 +95,32 @@ makeTermEncrypt (Term t1, Term t2)
|
|||||||
Term term = makeTerm ();
|
Term term = makeTerm ();
|
||||||
term->type = ENCRYPT;
|
term->type = ENCRYPT;
|
||||||
term->stype = NULL;
|
term->stype = NULL;
|
||||||
|
term->helper.fcall = false;
|
||||||
|
term->subst = NULL;
|
||||||
TermOp (term) = t1;
|
TermOp (term) = t1;
|
||||||
TermKey (term) = t2;
|
TermKey (term) = t2;
|
||||||
return term;
|
return term;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Term
|
||||||
|
makeTermFcall (Term t1, Term t2)
|
||||||
|
//! Create a fresh function application term from two existing terms.
|
||||||
|
/**
|
||||||
|
* The first argument is the function argument,
|
||||||
|
* the second argument is the function (name).
|
||||||
|
*
|
||||||
|
* These behave like encryptions in most cases.
|
||||||
|
*
|
||||||
|
*@return A pointer to the new term.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Term t;
|
||||||
|
|
||||||
|
t = makeTermEncrypt (t1, t2);
|
||||||
|
t->helper.fcall = true;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
//! Create a fresh term tuple from two existing terms.
|
//! Create a fresh term tuple from two existing terms.
|
||||||
/**
|
/**
|
||||||
*@return A pointer to the new term.
|
*@return A pointer to the new term.
|
||||||
@ -128,7 +152,8 @@ makeTermTuple (Term t1, Term t2)
|
|||||||
tt = makeTerm ();
|
tt = makeTerm ();
|
||||||
tt->type = TUPLE;
|
tt->type = TUPLE;
|
||||||
tt->stype = NULL;
|
tt->stype = NULL;
|
||||||
tt->roleVar = 0;
|
tt->helper.roleVar = 0;
|
||||||
|
tt->subst = NULL;
|
||||||
TermOp1 (tt) = t1;
|
TermOp1 (tt) = t1;
|
||||||
TermOp2 (tt) = t2;
|
TermOp2 (tt) = t2;
|
||||||
return tt;
|
return tt;
|
||||||
@ -145,7 +170,16 @@ makeTermType (const int type, const Symbol symb, const int runid)
|
|||||||
Term term = makeTerm ();
|
Term term = makeTerm ();
|
||||||
term->type = type;
|
term->type = type;
|
||||||
term->stype = NULL;
|
term->stype = NULL;
|
||||||
term->roleVar = 0;
|
if ((type == ENCRYPT) || (type == TUPLE))
|
||||||
|
{
|
||||||
|
// Non-leaf
|
||||||
|
term->helper.fcall = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Leaf
|
||||||
|
term->helper.roleVar = 0;
|
||||||
|
}
|
||||||
term->subst = NULL;
|
term->subst = NULL;
|
||||||
TermSymb (term) = symb;
|
TermSymb (term) = symb;
|
||||||
TermRunid (term) = runid;
|
TermRunid (term) = runid;
|
||||||
@ -381,8 +415,7 @@ termPrintCustom (Term term, char *leftvar, char *rightvar, char *lefttup,
|
|||||||
}
|
}
|
||||||
if (realTermEncrypt (term))
|
if (realTermEncrypt (term))
|
||||||
{
|
{
|
||||||
if (isTermLeaf (TermKey (term))
|
if (term->helper.fcall)
|
||||||
&& inTermlist (TermKey (term)->stype, TERM_Function))
|
|
||||||
{
|
{
|
||||||
/* function application */
|
/* function application */
|
||||||
termPrintCustom (TermKey (term), leftvar, rightvar, lefttup,
|
termPrintCustom (TermKey (term), leftvar, rightvar, lefttup,
|
||||||
@ -695,8 +728,12 @@ termRunid (Term term, int runid)
|
|||||||
/* anything else, recurse */
|
/* anything else, recurse */
|
||||||
if (realTermEncrypt (term))
|
if (realTermEncrypt (term))
|
||||||
{
|
{
|
||||||
return makeTermEncrypt (termRunid (TermOp (term), runid),
|
Term t;
|
||||||
termRunid (TermKey (term), runid));
|
|
||||||
|
t = makeTermEncrypt (termRunid (TermOp (term), runid),
|
||||||
|
termRunid (TermKey (term), runid));
|
||||||
|
t->helper.fcall = term->helper.fcall;
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1159,22 +1196,23 @@ term_encryption_level (const Term term)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int l, r;
|
||||||
|
|
||||||
if (realTermTuple (t))
|
if (realTermTuple (t))
|
||||||
{
|
{
|
||||||
int l, r;
|
|
||||||
|
|
||||||
l = iter_maxencrypt (TermOp1 (t));
|
l = iter_maxencrypt (TermOp1 (t));
|
||||||
r = iter_maxencrypt (TermOp2 (t));
|
r = iter_maxencrypt (TermOp2 (t));
|
||||||
if (l > r)
|
|
||||||
return l;
|
|
||||||
else
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// encrypt
|
// encrypt
|
||||||
return 1 + iter_maxencrypt (TermOp (t));
|
l = 1 + iter_maxencrypt (TermOp (t));
|
||||||
|
r = iter_maxencrypt (TermKey (t));
|
||||||
}
|
}
|
||||||
|
if (l > r)
|
||||||
|
return l;
|
||||||
|
else
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1418,9 +1456,9 @@ Term
|
|||||||
getTermFunction (Term t)
|
getTermFunction (Term t)
|
||||||
{
|
{
|
||||||
t = deVar (t);
|
t = deVar (t);
|
||||||
if (t != NULL)
|
if (realTermEncrypt (t))
|
||||||
{
|
{
|
||||||
if (realTermEncrypt (t) && isTermFunctionName (TermKey (t)))
|
if (t->helper.fcall)
|
||||||
{
|
{
|
||||||
return TermKey (t);
|
return TermKey (t);
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,11 @@ struct term
|
|||||||
//! Data Type termlist (e.g. agent or nonce)
|
//! Data Type termlist (e.g. agent or nonce)
|
||||||
/** Only for leaves. */
|
/** Only for leaves. */
|
||||||
void *stype; // list of types
|
void *stype; // list of types
|
||||||
int roleVar; //!< only for leaf, arachne engine: role variable flag
|
union
|
||||||
|
{
|
||||||
|
int roleVar; //!< only for leaf, arachne engine: role variable flag
|
||||||
|
int fcall; //!< only for 'encryption' to mark actual function call f(t)
|
||||||
|
} helper;
|
||||||
|
|
||||||
//! Substitution term.
|
//! Substitution term.
|
||||||
/**
|
/**
|
||||||
@ -96,6 +100,7 @@ typedef struct term *Term;
|
|||||||
void termsInit (void);
|
void termsInit (void);
|
||||||
void termsDone (void);
|
void termsDone (void);
|
||||||
Term makeTermEncrypt (Term t1, Term t2);
|
Term makeTermEncrypt (Term t1, Term t2);
|
||||||
|
Term makeTermFcall (Term t1, Term t2);
|
||||||
Term makeTermTuple (Term t1, Term t2);
|
Term makeTermTuple (Term t1, Term t2);
|
||||||
Term makeTermType (const int type, const Symbol symb, const int runid);
|
Term makeTermType (const int type, const Symbol symb, const int runid);
|
||||||
__inline__ Term deVarScan (Term t);
|
__inline__ Term deVarScan (Term t);
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "switches.h"
|
#include "switches.h"
|
||||||
|
#include "knowledge.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shared stuff
|
* Shared stuff
|
||||||
@ -618,68 +619,6 @@ termlistLength (Termlist tl)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Give the inverse key term of a term.
|
|
||||||
/**
|
|
||||||
* Gives a duplicate of the inverse Key of some term (which is used to encrypt something), as is defined
|
|
||||||
* by the termlist, which is a list of key1,key1inv, key2, key2inv, etc...
|
|
||||||
*@param inverses The list of inverses, typically from the knowledge.
|
|
||||||
*@param key Any term of which the inverse will be determined.
|
|
||||||
*@return A pointer to a duplicate of the inverse key term. Use termDelete to remove it.
|
|
||||||
*\sa termDuplicate(), knowledge::inverses
|
|
||||||
*/
|
|
||||||
|
|
||||||
Term
|
|
||||||
inverseKey (Termlist inverses, Term key)
|
|
||||||
{
|
|
||||||
key = deVar (key);
|
|
||||||
|
|
||||||
/* is this a function application? i.e. hash? */
|
|
||||||
if (isTermLeaf (key) && inTermlist (key->stype, TERM_Function))
|
|
||||||
{
|
|
||||||
/* functions cannot be inverted by default */
|
|
||||||
return termDuplicate (TERM_Hidden);
|
|
||||||
}
|
|
||||||
/* check for the special case first: when it is effectively a function application */
|
|
||||||
if (isTermEncrypt (key) && isTermLeaf (TermKey (key))
|
|
||||||
&& inTermlist (deVar (TermKey (key))->stype, TERM_Function))
|
|
||||||
{
|
|
||||||
/* we are scanning for functions */
|
|
||||||
/* scan the list */
|
|
||||||
/* key is function application kk(op), or {op}kk */
|
|
||||||
Term funKey (Term orig, Term newk)
|
|
||||||
{
|
|
||||||
/* in: {op}kk, nk
|
|
||||||
* out: {op'}nk */
|
|
||||||
return makeTermEncrypt (termDuplicate (TermOp (orig)),
|
|
||||||
termDuplicate (newk));
|
|
||||||
}
|
|
||||||
while (inverses != NULL && inverses->next != NULL)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (isTermEqual (TermKey (key), inverses->term))
|
|
||||||
return funKey (key, inverses->next->term);
|
|
||||||
if (isTermEqual (TermKey (key), inverses->next->term))
|
|
||||||
return funKey (key, inverses->term);
|
|
||||||
inverses = inverses->next->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* scanning for a direct inverse */
|
|
||||||
|
|
||||||
/* scan the list */
|
|
||||||
while (inverses != NULL && inverses->next != NULL)
|
|
||||||
{
|
|
||||||
if (isTermEqual (key, inverses->term))
|
|
||||||
return termDuplicate (inverses->next->term);
|
|
||||||
if (isTermEqual (key, inverses->next->term))
|
|
||||||
return termDuplicate (inverses->term);
|
|
||||||
inverses = inverses->next->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return termDuplicate (key); /* defaults to symmetrical */
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Create a term local to a run.
|
//! Create a term local to a run.
|
||||||
/*
|
/*
|
||||||
* We assume that at this point, no variables have been instantiated yet that occur in this term.
|
* We assume that at this point, no variables have been instantiated yet that occur in this term.
|
||||||
|
@ -66,7 +66,6 @@ Termlist termlistAddBasic (Termlist tl, Term t);
|
|||||||
Termlist termlistAddBasics (Termlist tl, Termlist scan);
|
Termlist termlistAddBasics (Termlist tl, Termlist scan);
|
||||||
Termlist termlistMinusTerm (Termlist tl, Term t);
|
Termlist termlistMinusTerm (Termlist tl, Term t);
|
||||||
int termlistLength (Termlist tl);
|
int termlistLength (Termlist tl);
|
||||||
Term inverseKey (Termlist inverses, Term key);
|
|
||||||
Term termLocal (const Term t, Termlist fromlist, Termlist tolist);
|
Term termLocal (const Term t, Termlist fromlist, Termlist tolist);
|
||||||
Termlist termlistLocal (Termlist tl, const Termlist fromlist,
|
Termlist termlistLocal (Termlist tl, const Termlist fromlist,
|
||||||
const Termlist tolist);
|
const Termlist tolist);
|
||||||
|
19
src/xmlout.c
19
src/xmlout.c
@ -438,7 +438,7 @@ xmlInverses (const System sys)
|
|||||||
|
|
||||||
xmlPrint ("<inversekeys>");
|
xmlPrint ("<inversekeys>");
|
||||||
xmlindent++;
|
xmlindent++;
|
||||||
invlist = sys->know->inverses;
|
invlist = sys->know->inversekeys;
|
||||||
while (invlist != NULL && invlist->next != NULL)
|
while (invlist != NULL && invlist->next != NULL)
|
||||||
{
|
{
|
||||||
xmlPrint ("<keypair>");
|
xmlPrint ("<keypair>");
|
||||||
@ -452,6 +452,23 @@ xmlInverses (const System sys)
|
|||||||
}
|
}
|
||||||
xmlindent--;
|
xmlindent--;
|
||||||
xmlPrint ("</inversekeys>");
|
xmlPrint ("</inversekeys>");
|
||||||
|
|
||||||
|
xmlPrint ("<inversekeyfunctions>");
|
||||||
|
xmlindent++;
|
||||||
|
invlist = sys->know->inversekeyfunctions;
|
||||||
|
while (invlist != NULL && invlist->next != NULL)
|
||||||
|
{
|
||||||
|
xmlPrint ("<keypair>");
|
||||||
|
xmlindent++;
|
||||||
|
xmlOutTerm (NULL, invlist->term);
|
||||||
|
xmlOutTerm (NULL, invlist->next->term);
|
||||||
|
xmlindent--;
|
||||||
|
xmlPrint ("</keypair>");
|
||||||
|
|
||||||
|
invlist = invlist->next->next;
|
||||||
|
}
|
||||||
|
xmlindent--;
|
||||||
|
xmlPrint ("</inversekeyfunctions>");
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Show initial knowledge
|
//! Show initial knowledge
|
||||||
|
Loading…
Reference in New Issue
Block a user