scyther/src/latex.c

798 lines
17 KiB
C
Raw Normal View History

2004-04-23 11:58:43 +01:00
/*
* LaTeX output component
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
#include "runs.h"
#include "memory.h"
#include "modelchecker.h"
#include "tracebuf.h"
#include "varbuf.h"
#include "output.h"
#define EVENTSPACE 1
#define LINKTHRESHOLD 0.95
extern const char *progname;
extern const char *releasetag;
extern int globalLatex;
extern Term TERM_Function;
/* struct for additional info */
struct traceinfo {
int match;
int position;
};
/* global variables for this module */
struct traceinfo *tinfo;
int width;
int landscape = 0;
int *runPerm;
/* code */
void latexInit(const System sys, int argc, char **argv)
{
int i;
printf("\\documentclass{article}\n");
printf("\\usepackage{msc}\n");
printf("%%\n");
printf("%% LaTeX output generated by %s\n", progname);
printf("%% Input:\n");
/* print command line */
printf("%% $");
for (i = 0; i < argc; i++)
printf(" %s", argv[i]);
printf("\n");
printf("%%\n");
printf("\\begin{document}\n\n");
/* comment macro (used for debugging) */
printf("\\newcommand{\\comment}[1]{}\n");
/* preamble */
printf("\\input{preamble}\n");
}
void latexDone(const System sys)
{
printf("\\input{postamble}\n");
printf("\n\\end{document}\n\n");
}
void
latexTermPrint (Term term, Termlist highlight)
{
if (term == NULL)
{
printf ("Empty term");
return;
}
#ifdef DEBUG
if (!DEBUGL (1))
{
term = deVar (term);
}
#else
term = deVar (term);
#endif
if (realTermLeaf (term))
{
if (inTermlist(highlight, term))
printf("\\mathbf{");
symbolPrint (term->symb);
if (realTermVariable (term))
printf ("V");
if (term->runid >= 0)
{
printf ("\\sharp%i", term->runid);
}
if (term->subst != NULL)
{
printf ("\\rightarrow");
latexTermPrint (term->subst, highlight);
}
if (inTermlist(highlight, term))
printf("}");
}
if (realTermTuple (term))
{
printf ("(");
while (realTermTuple (term))
{
latexTermPrint (term->op1, highlight);
printf (",");
term = term->op2;
if (!realTermTuple (term))
latexTermPrint (term, highlight);
}
printf (")");
return;
}
if (realTermEncrypt (term))
{
if (isTermLeaf (term->key)
&& inTermlist (term->key->stype, TERM_Function))
{
/* function application */
latexTermPrint (term->key, highlight);
printf ("(");
latexTermPrint (term->op, highlight);
printf (")");
}
else
{
/* normal encryption */
printf ("\\{");
latexTermPrint (term->op, highlight);
printf ("\\}_{");
latexTermPrint (term->key, highlight);
printf ("}");
}
}
}
void
latexTermlistPrint (Termlist tl, Termlist highlight)
{
if (tl == NULL)
{
printf ("[Empty]");
return;
}
printf ("[");
while (tl != NULL)
{
latexTermPrint (tl->term, highlight);
tl = tl->next;
if (tl != NULL)
printf(", ");
}
printf ("]");
}
void latexTimers(const System sys)
{
void endline(void) {
printf("\\\\ \\hline\n");
}
printf("\\begin{tabular}{|r|r|c|r|} \\hline\n");
/* display stats, header first */
printf("Time & States & Attack & st/sec");
endline();
/* print time */
double seconds;
seconds = (double) clock() / CLOCKS_PER_SEC;
printf("$%.3e$ &", seconds);
/* states traversed */
printf("$");
statesPrintShort(sys);
printf("$ &");
/* flag
*
* L n Attack of length <n>
* None failed claim
* NoClaim no claims
*/
if (sys->claims == 0) {
printf("NoClaim & ");
} else {
if (sys->failed > 0)
printf("L:%i & ", attackLength(sys->attack));
else
printf("None & ");
}
/*
printf("%.3e (%li) claims encountered.\n",(double)
sys->claims, sys->claims);
printf("%.3e (%li) claims failed.\n",(double)
sys->failed, sys->failed);
*/
/* states per second */
if (seconds > 0) {
printf("$%.3e$ ",
(double) (sys->statesLow +
(sys->statesHigh * ULONG_MAX)) / seconds);
} else {
printf("$\\infty$ ");
}
endline();
printf("\\end{tabular}\n\n");
}
void latexMSCStart()
{
if (landscape)
printf("\\begin{landscape}\n");
printf("\\begin{msc}{attack}\n");
}
void latexMSCEnd()
{
printf("\\end{msc}\n");
if (landscape)
printf("\\end{landscape}\n");
}
void latexDeclInst(const System sys, int run)
{
Term bar = NULL;
bar = agentOfRun(sys, run);
printf("\\declinst{run%d}{$", run);
termPrint(bar);
printf("\\sharp%i$}{$", run);
agentsOfRunPrint(sys, run);
printf("$}\n");
}
void latexEventSpace(int amount)
{
int i;
//printf("%% number of newlines: %d\n",amount);
for (i = 0; i < EVENTSPACE * amount; i++)
printf("\\nextlevel\n");
}
void latexMessagePrint(struct tracebuf *tb, int from, int to)
{
Term sendTerm = NULL;
Term readTerm = NULL;
if (from == -1 && to == -1) {
return;
}
if (from != -1) {
sendTerm = tb->event[from]->message;
}
if (to != -1) {
readTerm = tb->event[to]->message;
}
if (from == -1 && to != -1) {
printf("\\found{$");
termPrint(readTerm);
printf("$}{}{run%d}\n", tb->run[to]);
} else if (from != -1 && to == -1) {
printf("\\lost{$");
termPrint(sendTerm);
printf("$}{}{run%d}\n", tb->run[from]);
} else if (from != -1 && to != -1) {
printf("\\mess{$");
termPrint(sendTerm);
if (!isTermEqual(sendTerm, readTerm)) {
printf("\\rightarrow");
termPrint(readTerm);
}
printf("$}{run%d", tb->run[from]);
printf("}{run%d}[%d]", tb->run[to],
EVENTSPACE * (tinfo[to].position -
tinfo[from].position));
printf("\n");
}
}
void latexMessagePrintHighlight(struct tracebuf *tb, int from, int to, Termlist highlight)
{
Term sendTerm = NULL;
Term readTerm = NULL;
if (from == -1 && to == -1) {
return;
}
if (from != -1) {
sendTerm = tb->event[from]->message;
}
if (to != -1) {
readTerm = tb->event[to]->message;
}
if (from == -1 && to != -1) {
printf("\\found{$");
latexTermPrint(readTerm, highlight);
printf("$}{}{run%d}\n", tb->run[to]);
} else if (from != -1 && to == -1) {
printf("\\lost{$");
latexTermPrint(sendTerm, highlight);
printf("$}{}{run%d}\n", tb->run[from]);
} else if (from != -1 && to != -1) {
printf("\\mess{$");
latexTermPrint(sendTerm, highlight);
if (!isTermEqual(sendTerm, readTerm)) {
printf("\\rightarrow");
latexTermPrint(readTerm, highlight);
}
printf("$}{run%d", tb->run[from]);
printf("}{run%d}[%d]", tb->run[to],
EVENTSPACE * (tinfo[to].position -
tinfo[from].position));
printf("\n");
}
}
void latexLearnComment(struct tracebuf *tb, int index, Termlist tl)
{
printf("\\msccomment[4ex]{$I_%d=I_%d\\oplus ", index + 1,
index);
termlistPrint(tl);
printf("$}{envright}\n");
}
void latexAction(struct tracebuf *tb, int te)
{
printf("\\action{$");
termPrint(tb->event[te]->message);
printf("$}{run%d}\n", tb->run[te]);
//printf("\\nextlevel\n");
}
void latexClaim(struct tracebuf *tb, int run, Termlist tl)
{
printf("\\condition{$");
printf("\\neg secret ");
termlistPrint(tl);
printf("$}{run%d}\n", run);
}
int latexCorrespondingSend(struct tracebuf *tb, int rd)
{
int labelMatch = 0;
int toMatch = 0;
int fromMatch = 0;
int tofromMatch = 0;
int messageMatch = 0;
int nMatches = 0;
int maxNMatches = 0;
int readEvent = rd;
int sendEvent = -1;
int bestSendEvent = -1;
for (sendEvent = readEvent; sendEvent >= 0; sendEvent--) {
if (tb->event[sendEvent]->type == SEND) {
/* do all the different kind of matchings first */
labelMatch =
isTermEqual(tb->event[sendEvent]->label,
tb->event[readEvent]->label);
toMatch =
isTermEqual(tb->event[sendEvent]->to,
tb->event[readEvent]->to);
fromMatch =
isTermEqual(tb->event[sendEvent]->from,
tb->event[readEvent]->from);
tofromMatch = toMatch || fromMatch;
messageMatch =
isTermEqual(tb->event[sendEvent]->message,
tb->event[readEvent]->message);
/* calculate the score */
nMatches = labelMatch + tofromMatch + messageMatch;
if (nMatches == 3) {
/* bingo! success on all matches */
//printf("Found perfect match: %d\n", s);
bestSendEvent = sendEvent;
break;
}
if (nMatches > maxNMatches) {
if (labelMatch && messageMatch) {
/* strongest restriction: message and label should match */
maxNMatches = nMatches;
bestSendEvent = sendEvent;
} else if (messageMatch) {
/* if label AND message don't match: */
/* at least message should match */
maxNMatches = nMatches;
bestSendEvent = sendEvent;
} else if (labelMatch) {
/* if message doesn't match */
/* the label should matches */
maxNMatches = nMatches;
bestSendEvent = sendEvent;
}
}
}
}
//bestSendEvent = NULL;
if (bestSendEvent == -1) {
int u;
for (u = 0; u < rd; u++) {
if (tb->event[u]->type == SEND) {
//knowledgePrint(sys->traceKnow[u]);
if (inKnowledge
(tb->know[u + 1], tb->event[readEvent]->message)) {
bestSendEvent = u;
break;
}
}
}
}
if (bestSendEvent == -1) {
printf("%% Could not find a matching SEND\n");
}
return bestSendEvent;
}
int
newInKnowledge (const Knowledge know, Term term)
{
/* if there is no term, then it's okay 'fur sure' */
if (term == NULL)
return 1;
/* if there is a term, but no knowledge, we're in trouble */
if (know == NULL)
return 0;
mindwipe (know, inKnowledge (know, term));
term = deVar (term);
if (isTermLeaf (term))
{
return inTermlist (know->basic, term);
}
if (term->type == ENCRYPT)
{
return inTermlist (know->encrypt, term) ||
(inKnowledge (know, term->key) || inKnowledge (know, term->op));
}
if (term->type == TUPLE)
{
return (inTermlist (know->encrypt, term) ||
(inKnowledge (know, term->op1) ||
inKnowledge (know, term->op2)));
}
return 0; /* unrecognized term type, weird */
}
int latexCorrespondingSend2(struct tracebuf *tb, int readEvent)
{
int u;
for (u = tb->length - 1; u>=0 ; u--)
{
if (tb->event[u]->type == SEND)
{
if (!inKnowledge (tb->know[u], tb->event[readEvent]->message))
{
/*
printf("%% term[");
printf("]#%d is introduced at traceEvent[%d] ",readEvent,u);
printf("\n");
*/
return u;
}
}
}
return -1;
}
/*
* Display knowledge in LaTeX format.
*/
void knowledgePrintLatex(Knowledge know)
{
Termlist tl;
if (know == NULL)
{
printf("\\emptyset");
}
else
{
tl = knowledgeSet(know);
termlistPrint(tl);
termlistDelete(tl);
}
}
void attackDisplayLatex(System sys)
{
int i;
struct tracebuf *tb;
int *runPosition;
int currRun;
int position;
int eventSize;
Termlist tl;
Termlist newtl;
Termlist claimDetails;
Termlist highlights = NULL;
int cKnowledge;
int bestSend;
tb = sys->attack;
if (tb == NULL) {
printf("Attack pointer empty: nothing to display.\n");
exit(1);
}
/* set variables */
varbufSet (sys, tb->variables);
/* Rebuild knowledge. Strange, this ought to be good.
* Maybe reconstruct dependencies as well. */
tracebufRebuildKnow(tb);
/* Make a comment in which the trace is displayed, for debugging etc. */
printf("\n\\comment{ TRACE\n\n");
printf("Length: %i\n",tb->length);
printf("Reallength: %i\n",tb->reallength);
printf("\n");
i = 0;
while (i <= tb->length)
{
printf("Knowledge %i:\n",i);
knowledgePrint(tb->know[i]);
printf(" [Inverses]: ");
knowledgeInversesPrint(tb->know[i]);
printf("\n\n");
if (i < tb->length)
{
printf("Event %i\t[",i);
switch (tb->status[i])
{
case S_UNK:
printf("?");
break;
case S_RED:
printf("redundant");
break;
case S_TOD:
printf("to do");
break;
case S_OKE:
printf("okay");
break;
default:
printf("illegal status code");
break;
}
printf("]\t");
termPrint(tb->event[i]->message);
printf("\t#%i",tb->run[i]);
printf("\n");
roledefPrint(tb->event[i]);
printf("\n\n");
}
i++;
}
printf("}\n\n");
/* display initial knowledge */
printf("$I_0 = \\emptyset \\oplus ");
knowledgePrintLatex(tb->know[0]);
printf("$\n\n");
tinfo =
(struct traceinfo *) memAlloc((tb->length+1) *
sizeof(struct traceinfo));
width = 1;
for (i = 0; i < tb->length; i++) {
if (tb->run[i] >= width)
width = tb->run[i] + 1;
}
for (i = 0; i < tb->length; i++) {
tb->link[i] = -1;
tinfo[i].match = -1;
tinfo[i].position = i;
}
tinfo[i].match = -1;
tinfo[i].position = i;
runPosition = (int *) memAlloc(width * sizeof(int));
for (i = 0; i < width; i++) {
runPosition[i] = 0;
}
for (i = tb->length - 1; i >= 0; i--)
{
if (tb->status[i] != S_RED)
{
if (tb->event[i]->type == READ && !tb->event[i]->internal)
{
bestSend = latexCorrespondingSend2(tb, i);
printf("%% match: %d <-> %d\n",i, bestSend);
if (bestSend == -1)
continue;
tb->link[i] = bestSend;
tb->link[bestSend] = i;
}
if (tb->event[i]->type == CLAIM)
{
claimDetails = claimViolationDetails(sys, tb->run[i], tb->event[i], tb->know[i]);
}
}
}
printf("\\comment{ claimDetails :\n");
termlistPrint(claimDetails);
printf("\n}\n");
// landscape = (width > 4); // not for the time being
position = 0;
currRun = 0;
eventSize = 0;
for (i = 0; i < tb->length; i++)
{
if (tb->status[i] != S_RED)
{
tinfo[i].position = position;
eventSize = 1;
currRun = tb->run[i];
switch (tb->event[i]->type) {
case SEND:
position++;
tinfo[i].position++;
break;
case READ:
if (tb->link[i] != -1) {
if (termDistance(tb->event[i]->message,tb->event[tb->link[i]]->message) < LINKTHRESHOLD)
{
/* disconnect read-send */
tb->link[tb->link[i]] = -1;
tb->link[i] = -1;
} else {
if (runPosition[currRun] <= tinfo[tb->link[i]].position &&
currRun != tb->run[tb->link[i]])
{
printf("\\comment{\n");
termPrint(tb->event[i]->message);
printf("\n");
termPrint(tb->event[tb->link[i]]->message);
printf("\n");
printf("%% termDistance: %f\n",
termDistance(tb->event[i]->message,
tb->event[tb->link[i]]->message));
printf("}\n");
tinfo[i].position = tinfo[tb->link[i]].position;
eventSize = 0;
}
}
}
if (tb->event[i]->internal) {
eventSize = 0;
}
break;
case CLAIM:
if (claimDetails != NULL && claimDetails != (Termlist) -1) {
eventSize = 2;
} else {
eventSize = 0;
}
break;
default:
break;
}
if (!(tb->event[i]->type == READ && tb->event[i]->internal))
runPosition[currRun] = tinfo[i].position + eventSize;
/* printf("%% Event %d at %d\n", i, position); */
position += eventSize;
}
}
latexMSCStart();
for (i = 0; i < width; i++) {
if (runPosition[i] > 0)
latexDeclInst(sys, i);
}
//for (j=-1; j<=sys->step; j++)
position = 0;
cKnowledge = 0;
for (i = 0; i < tb->length; i++)
{
if (tb->status[i] != S_RED)
{
latexEventSpace(tinfo[i].position - position);
if (tinfo[i].position >= position)
{
position = tinfo[i].position;
}
switch (tb->event[i]->type) {
case SEND:
newtl = knowledgeNew(tb->know[i], tb->know[i + 1]);
highlights = NULL;
/* Build a Termlist of terms that from the claimViolationDetails,
that appear in the knowledge */
if (newtl != NULL)
{
tl = claimDetails;
while (tl != NULL)
{
if (inTermlist(newtl, tl->term))
{
highlights = termlistAdd(highlights, tl->term);
}
tl = tl->next;
}
printf("\\msccomment[4ex]{$I_%d=I_%d\\oplus ", cKnowledge + 1,
cKnowledge);
cKnowledge++;
latexTermlistPrint(newtl, highlights);
printf("$}{envright}\n");
}
if (tb->link[i] != -1 && i < tb->length) {
latexMessagePrintHighlight(tb, i, tb->link[i], highlights);
} else {
latexMessagePrintHighlight(tb, i, -1, highlights); //lost message
}
termlistDelete(highlights);
break;
case READ:
if (tb->event[i]->internal) {
} else if (tb->link[i] == -1) {
latexMessagePrint(tb, -1, i); //found message
}
break;
case CLAIM:
if (claimDetails != NULL && claimDetails != (Termlist) -1) {
latexClaim(tb, tb->run[i], claimDetails);
}
break;
default:
break; //kannie!
}
}
}
latexEventSpace(2);
latexMSCEnd();
memFree(runPosition, width * sizeof(int));
memFree(tinfo, (tb->length+1) * sizeof(struct traceinfo));
}