home *** CD-ROM | disk | FTP | other *** search
- /*
- * Automatic guessing based on trigrams.
- *
- * Bob Baldwin, January 1985.
- */
-
- #include <stdio.h>
- #include <math.h>
- #include "window.h"
- #include "terminal.h"
- #include "layout.h"
- #include "specs.h"
- #include "cipher.h"
- #include "autotri.h"
-
-
- #define DEBUGP FALSE /* Perm building */
- #define DEBUGB FALSE /* Best guess */
-
- #define ATRLABEL1 \
- "Auto Trigram, max SD: %4.2f total: %d wire: %d -- Please Wait"
- #define ATRLABEL2 \
- "Auto Trigram, max SD: %4.2f total: %d wire: %d -- Done"
- #define ATRHELP "F3 enters guess, ^G undoes it."
-
-
- extern char mcbuf[];
- extern ecinfo gecinfo;
- extern atrdraw(), atrfirst(), atrenter(), atrundo();
-
- /* Gloabal State. */
- char *trigramstats; /* Filename for statistics. */
- atrinfo gatrinfo;
- keyer atrktab[] = {
- {CACCEPT, atrenter},
- {CUNDO, atrundo},
- {CGO_UP, jogup},
- {CGO_DOWN, jogdown},
- {CGO_LEFT, jogleft},
- {CGO_RIGHT, jogright},
- {0, NULL},
- };
-
- /* Routine invoked by user to put up the equivalence class
- * guessing window.
- * The window is drawn empty, and then filled in with the guess.
- * Return NULL if command completes ok.
- */
- char *atrguess(str)
- char *str; /* Command line */
- {
- gwindow *atr;
- atrinfo *atri;
- ecinfo *ecbi;
- int *dbsperm;
- int i, c;
- int classpos;
- int x, y;
-
- atr = &gbstore;
- atri = &gatrinfo;
- dbsperm = refperm(dbsgetblk(&dbstore));
- atr_init(mcbuf, dbsperm, atri);
- ecbi = atri->eci;
- atri->min_total_chars = 123;
- atri->min_wire_chars = 456;
-
- if ((i = sscanf(str, "%*[^:]: %f %*[^:]: %d %*[^:]: %d",
- &atri->max_score, &atri->min_total_chars,
- &atri->min_wire_chars)) != 3) {
- return("Could not parse all three arguments.");
- }
-
- gbsswitch(atr, ((char *) atri), atrktab, atrfirst, wl_noop, atrdraw);
-
- sprintf(statmsg, ATRLABEL1,
- atri->max_score, atri->min_total_chars, atri->min_wire_chars);
- gblset(&gblabel, statmsg);
- atrdraw(atr);
- fflush(stdout);
-
- atr_autoguess(atri);
- decode(ecbi->ciphertext, ecbi->plaintext, ecbi->perm);
-
- sprintf(statmsg, ATRLABEL2,
- atri->max_score, atri->min_total_chars, atri->min_wire_chars);
- gblset(&gblabel, statmsg);
- atrdraw(atr);
-
- return(NULL);
- }
-
-
- /* (re) Draw the window.
- */
- atrdraw(atr)
- gwindow *atr;
- {
- int i;
- int row, col;
- atrinfo *atri;
- ecinfo *ecbi;
-
- atri = ((atrinfo *) atr->wprivate);
- ecbi = atri->eci;
- row = 1;
- col = 1;
-
- for (i = 0 ; i < BLOCKSIZE ; i++) {
- if (i%LINELEN == 0) {
- wl_setcur(atr, gbspos2row(i), gbspos2col(i));
- }
- plnchars(1, char2sym(ecbi->plaintext[i]));
- }
-
- for (i = gbspos2row(BLOCKSIZE) ; i <= GBHEIGHT ; i++) {
- wl_setcur(atr, i, 1);
- plnchars(LINELEN, ' ');
- }
-
- for (i = 1 ; i <= GBHEIGHT ; i++) {
- wl_setcur(atr, i, LINELEN+1);
- plnchars(atr->wwidth - LINELEN, ' ');
- }
-
- wl_setcur(atr, row, col);
- }
-
-
- /* First time cursor enters window.
- */
- atrfirst(atr, row, col)
- gwindow *atr;
- int row, col;
- {
- usrhelp(&user, ATRHELP);
- wl_setcur(atr, row, col);
- }
-
-
- /* Enter the guess into the decryption block.
- */
- atrenter(atr)
- gwindow *atr;
- {
- atrinfo *atri;
-
- atri = ((atrinfo *) atr->wprivate);
- dbsmerge(&dbstore, atri->eci->perm);
- wl_rcursor(atr);
- }
-
-
- /* Undo the last guess.
- */
- atrundo(atr)
- gwindow *atr;
- {
- dbsundo(&dbstore);
- wl_rcursor(atr);
- }
-
-
- /* Fill in auto-trigram info from given ciphertext block.
- * The filter parameters are not set by this routine.
- */
- atr_init(cipher, perm, atri)
- char cipher[];
- int perm[];
- atrinfo *atri;
- {
- extern int *trig_loaded;
- int i;
-
- atri->eci = &gecinfo;
- if (!trig_loaded)
- load_tri_from(trigramstats);
- ec_init(cipher, perm, atri->eci);
- atr_guess_init(atri);
- }
-
-
- /* Per guess initialization.
- */
- atr_guess_init(atri)
- atrinfo *atri;
- {
- atri->best_trigram = NULL;
- atri->best_score = 10.0;
- atri->gcount = 0;
- atri->total_score = 0;
- atri->best_pvec[0] = NONE;
- atri->best_permvec[0].x = NONE;
- }
-
-
-
- /* Score a trigram at a given position.
- * It also looks in atri for filtering parameters (total number
- * of chars must not be less than min_total_chars, and the minimum number
- * of chars deduced per wire must not be less than min_wire_chars).
- * This routine fills in permvec and pvec.
- * Returns -1.0 if guess is unacceptable.
- */
- float atr_score(atri, trigent, pos, permvec, pvec)
- atrinfo *atri;
- trig_ent *trigent;
- int pos;
- perment permvec[];
- int pvec[];
- {
- int length;
- int i, x, y;
- int ccount;
- int added;
- extern float logvar;
- float score;
- ecinfo *eci;
- int butfirst;
- int butlast;
-
- for (length = 0 ; trigent->trigram[length] != 0 ; length++);
- eci = atri->eci;
- added = permvec_from_string(atri->eci, trigent->trigram, pos, permvec);
- if (added < 0) return(-1.0);
-
- butfirst = pos;
- butlast = pos + length -1;
- ccount = 0;
-
- for (i = 0 ; i < PERMSZ && permvec[i].x != NONE ; i++) {
- if (ccount >= BLOCKSIZE-1) break;
- x = permvec[i].x;
- y = permvec[i].y;
- /* added = decode_wire_but(eci, x, y, &pvec[ccount], -1, -1);*/
- added = decode_wire_but(eci, x, y, &pvec[ccount], butfirst, butlast);
- if (added < 0) {
- ccount = 0;
- break;
- }
- if (added < atri->min_wire_chars) {
- ccount = 0;
- break;
- }
- ccount += added;
- }
- pvec[ccount] = -1;
-
- if (ccount <= 0) return(-1.0);
- if (ccount < atri->min_total_chars) return(-1.0);
-
- score = pvec_1score(pvec);
- if (score < 0.0) return(-1.0);
- /*
- score = exp(-(score * score) / 2.0);
- score = score / sqrt(2*PI*logvar/ccount);
- score = score * trigent->prob;
- */
- return(score);
- }
-
-
- /* Select the best trigram for a given position.
- * Returns pointer to trigram string, or NULL.
- * Fills in atri with additional information.
- * Filtering parameters are in atri.
- */
- char *atr_best(atri, pos)
- atrinfo *atri;
- int pos;
- {
- int tgram;
- float score;
- perment permvec[PERMSZ];
- int pvec[BLOCKSIZE+1];
- #if DEBUGB
- char str[BLOCKSIZE+1];
- #endif
-
- atr_guess_init(atri);
-
- for (tgram = 0 ; trig_tab[tgram].trigram != NULL ; tgram++) {
- score = atr_score(atri, &trig_tab[tgram], pos, permvec, pvec);
- if (score < 0.0) continue;
- atri->total_score += score;
- atri->gcount++;
- if (score < atri->best_score) {
- atri->best_score = score;
- atri->best_trigram = trig_tab[tgram].trigram;
- pvec_copy(pvec, atri->best_pvec);
- permvec_copy(permvec, atri->best_permvec, PERMSZ);
- }
- }
-
- #if DEBUGB
- if (atri->best_score < atri->max_score) {
- printf("\nTrigram '%s' at %d", atri->best_trigram, pos);
- pvec2str(str, atri->best_pvec);
- printf(" deduces '%s'", str);
- printf(" which scores as %g", atri->best_score);
- printf(".\n");
- }
- #endif
-
- if (atri->best_score < atri->max_score)
- {return(atri->best_trigram);}
- else
- {return(NULL);}
- }
-
-
- /* Merge the given permvector into the permutation table.
- * Return ERROR if there is a conflict, otherwise TRUE.
- */
- int accept_permvec(atri, permvec)
- atrinfo *atri;
- perment permvec[];
- {
- int i, x, y;
- ecinfo *ecbi;
-
- ecbi = atri->eci;
- for (i = 0 ; i < PERMSZ && permvec[i].x != NONE ; i++) {
- x = MODMASK & permvec[i].x;
- y = MODMASK & permvec[i].y;
- if (perm_conflict(ecbi->perm, x, y)) {
- #if DEBUGP
- printf("CONFLICT trying to wire %d to %d.\n", x, y);
- #endif
- return(ERROR);
- }
- }
-
-
- /* Now know that there are no conflicts. */
- for (i = 0 ; i < PERMSZ && permvec[i].x != NONE ; i++) {
- #if DEBUGP
- printf("ACCEPTING wiring of %d to %d.\n", x, y);
- #endif
- x = MODMASK & permvec[i].x;
- y = MODMASK & permvec[i].y;
- ecbi->perm[x] = y;
- ecbi->perm[y] = x;
- }
-
- return(TRUE);
- }
-
-
-
- /* Perform automatic guessing given a set of
- * filter parameters in an atrinfo structure.
- */
- atr_autoguess(atri)
- atrinfo *atri;
- {
- int pos;
- char *trigram;
-
- for (pos = 0 ; pos < BLOCKSIZE ; pos++) {
- trigram = atr_best(atri, pos);
- if (trigram != NULL) {
- accept_permvec(atri, atri->best_permvec);
- }
- }
- }
-