home *** CD-ROM | disk | FTP | other *** search
- /*
- * Equivalence class information about a cipher block.
- *
- * 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"
-
-
- #define DEBUG FALSE
-
- #define MIN_SHOW_SCORE (0.7)
- #define ECBLABEL1 "Equiv class guessing at level %6.3f -- Please Wait"
- #define ECBLABEL2 "Equiv class guessing at level %6.3f -- Done"
- #define ECBHELP "F3 enters guess, ^G undoes it."
-
-
- extern char mcbuf[];
- extern ecinfo gecinfo;
- extern ecbdraw(), ecbfirst(), ecbenter(), ecbundo();
-
- /* Gloabal State. */
- float ec_accept_level = 0.0;
- keyer ecbktab[] = {
- {CACCEPT, ecbenter},
- {CUNDO, ecbundo},
- {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 *ecbguess(str)
- char *str; /* Command line */
- {
- ecinfo *ecbi;
- int i;
- gwindow *ecb;
-
- ecb = &gbstore;
- ecbi = &gecinfo;
- ec_init(mcbuf, refperm(dbsgetblk(&dbstore)), ecbi);
-
- if ((i = sscanf(str, "%*[^:]: %f", &ec_accept_level)) != 1) {
- return("Could not parse acceptance level.");
- }
-
- gbsswitch(ecb, ((char *) ecbi), ecbktab, ecbfirst, wl_noop, ecbdraw);
-
- sprintf(statmsg, ECBLABEL1, ec_accept_level);
- gblset(&gblabel, statmsg);
-
- ecbdraw(ecb);
- fflush(stdout);
-
- ec_autoguess(ecbi, ec_accept_level);
- decode(ecbi->ciphertext, ecbi->plaintext, ecbi->perm);
-
- sprintf(statmsg, ECBLABEL2, ec_accept_level);
- gblset(&gblabel, statmsg);
- ecbdraw(ecb);
-
- return(NULL);
- }
-
-
- /* (re) Draw the window.
- */
- ecbdraw(ecb)
- gwindow *ecb;
- {
- int i;
- int row, col;
- ecinfo *ecbi;
-
- ecbi = ((ecinfo *) ecb->wprivate);
- row = 1;
- col = 1;
-
- for (i = 0 ; i < BLOCKSIZE ; i++) {
- if (i%LINELEN == 0) {
- wl_setcur(ecb, gbspos2row(i), gbspos2col(i));
- }
- plnchars(1, char2sym(ecbi->plaintext[i]));
- }
-
- for (i = gbspos2row(BLOCKSIZE) ; i <= GBHEIGHT ; i++) {
- wl_setcur(ecb, i, 1);
- plnchars(LINELEN, ' ');
- }
-
- for (i = 1 ; i <= GBHEIGHT ; i++) {
- wl_setcur(ecb, i, LINELEN+1);
- plnchars(ecb->wwidth - LINELEN, ' ');
- }
-
- wl_setcur(ecb, row, col);
- }
-
-
- /* First time cursor enters window.
- */
- ecbfirst(ecb, row, col)
- gwindow *ecb;
- int row, col;
- {
- usrhelp(&user, ECBHELP);
- wl_setcur(ecb, row, col);
- }
-
-
- /* Enter the guess into the decryption block.
- */
- ecbenter(ecb)
- gwindow *ecb;
- {
- ecinfo *ecbi;
-
- ecbi = ((ecinfo *) ecb->wprivate);
- dbsmerge(&dbstore, ecbi->perm);
- wl_rcursor(ecb);
- }
-
-
- /* Undo the last guess.
- */
- ecbundo(ecb)
- gwindow *ecb;
- {
- ecinfo *ecbi;
-
- ecbi = ((ecinfo *) ecb->wprivate);
- dbsundo(&dbstore);
- wl_rcursor(ecb);
- }
-
-
-
-
- /* Dump plaintext chars onto stream.
- */
- ec_dplain(out, eci)
- FILE *out;
- ecinfo *eci;
- {
- int i,c;
- int *pbuf;
-
- pbuf = &eci->plaintext[0];
- for (i = 0 ; i < BLOCKSIZE ; i++) {
- c = *pbuf++;
- if (i % 20 == 0) fprintf(out,"\n");
- if (c != NONE)
- write_char(out, c);
- else
- write_char(out, '.');
- }
- fprintf(out,"\n");
- }
-
-
- /* Dump shifted cipher chars onto stream.
- */
- ec_dscipher(out, eci)
- FILE *out;
- ecinfo *eci;
- {
- int i,c;
- int *pbuf;
-
- pbuf = &eci->scipher[0];
- for (i = 0 ; i < BLOCKSIZE ; i++) {
- c = *pbuf++;
- if (i++ % 20 == 0) fprintf(out,"\n");
- if (c != NONE)
- write_char(out, c);
- else
- write_char(out, '.');
- }
- fprintf(out,"\n");
- }
-
-
- /* Dump table of next pointers onto a stream.
- */
- ec_dnext(out, eci)
- FILE *out;
- ecinfo *eci;
- {
- writeperm(out, &(eci->next[0]));
- }
-
-
- /* Dump size table onto a stream.
- */
- ec_dsizetab(out, eci)
- FILE *out;
- ecinfo *eci;
- {
- int i;
-
- fprintf(out, "\nThere are %d classes longer than 1 character.\n",
- eci->sizelast);
- for (i = 0 ; i < eci->sizelast ; i++) {
- fprintf(out, "Size: %d, First member: %d.\n",
- eci->sizelist[i].size, eci->sizelist[i].firstpos);
- }
- }
-
-
- /* Dump our permutation onto a stream.
- */
- ec_dperm(out, eci)
- FILE *out;
- ecinfo *eci;
- {
- writeperm(out, &(eci->perm[0]));
- }
-
-
- /* Dump the permutation map onto a stream.
- */
- ec_dpmap(out, eci)
- FILE *out;
- ecinfo *eci;
- {
- writeperm(out, &(eci->permmap[0]));
- }
-
-
-
- /* Update ecbi to reflect the automatic guesses.
- */
- ec_autoguess(ecbi, alevel)
- ecinfo *ecbi;
- float alevel;
- { int i, c;
- int classpos;
- int x, y;
-
- for (i = 0 ; i < ecbi->sizelast ; i++) {
- classpos = ecbi->sizelist[i].firstpos;
- c = ec_best(ecbi, classpos, alevel);
- if (c != NONE) {
- x = ecbi->scipher[classpos];
- y = MODMASK & (c + classpos);
- if (!perm_conflict(ecbi->perm, x, y)) {
- ecbi->perm[x] = y;
- ecbi->perm[y] = x;
- }
- #if DEBUG
- else {
- printf("ec_autoguess: Best guess conflicts");
- printf(" with an accepted.\n");
- }
- #endif
- }
- }
- }
-
-
- /* Score a single equivalence class.
- * Bigger scores are better scores. They range from 0 to 1.
- * A score of zero means the choice is not possible.
- */
- float ec_cscore(eci, firstpos, plainchar)
- ecinfo *eci;
- int firstpos;
- int plainchar;
- {
- extern float logvar;
- float score;
- int pvec[BLOCKSIZE+1];
- int ccount;
- char str[BLOCKSIZE+1];
-
-
- if (decode_class(eci, firstpos, plainchar, pvec) == ERROR) {
- return(0.0);
- }
-
- score = pvec_1score(pvec);
- if (score < 0.0) return(0.0);
- score = exp(-(score * score) / 2.0);
- for (ccount = 0 ; pvec[ccount] != NONE ; ccount++);
- score = score / sqrt(2*PI*logvar/ccount);
-
- #if DEBUG
- if (score > MIN_SHOW_SCORE) {
- pvec2str(str, pvec);
- printf("Derived characters are '%s", str);
- printf("', their score is %7.4f\n", score);
- }
- #endif
- return(score);
- }
-
-
- /* Select best plaintext value for a ciphertext equiv class.
- * The class is identified by the position in the block of one
- * of the characters in the class. The plaintext value for
- * an entire class can be specified by the plaintext value of
- * one of its members. This routine returns the best plaintext
- * value for the ciphertext character at position firstpos.
- * If there is not a clear best value, NONE is returned.
- */
- int ec_best(eci, firstpos, alevel)
- ecinfo *eci;
- int firstpos;
- float alevel;
- {
- float total_score, score;
- float best_score;
- int best_char;
- int c;
- int x,y;
- float count;
-
- #if DEBUG
- int pvec[BLOCKSIZE+1];
- char str[BLOCKSIZE+1];
-
- printf("\n");
- printf("The first position of this class is %d.\n", firstpos);
- #endif
- total_score = 0.0;
- best_score = 0.0;
- count = 0.0;
- best_char = NONE;
-
- for (c = 0 ; c <= MAXCHAR ; c++) {
- score = ec_cscore(eci, firstpos, c);
- if (score > 0.0) {
- count += 1.0;
- total_score += score;
- }
- if (score > best_score) {
- best_score = score;
- best_char = c;
- }
- }
-
- #if DEBUG
- printf("Total score is %7.4f", total_score);
- printf(". Count is %4.0f.\n", count);
- #endif
- if (total_score == 0.0 || count == 0.0 || best_char == NONE) {
- #if DEBUG
- printf("NO GUESSES\n");
- #endif
- return(NONE);
- }
- #if DEBUG
- printf("Best score is %7.4f", best_score);
- printf(", which is %7.4f fraction of total", best_score/total_score);
- printf(".\n");
-
- decode_class(eci, firstpos, best_char, pvec);
- pvec2str(str, pvec);
- printf("The best chars are '%s.\n", str);
- #endif
-
- if (best_score > alevel * (total_score - best_score)) {
- return(best_char);
- }
- else {
- return(NONE);
- }
- }
-
-
- /* Fill in equiv class info from given ciphertext block
- * and permutation.
- */
- ec_init(cipher, perm, eci)
- char cipher[];
- int perm[];
- ecinfo *eci;
- {
- int i,j;
- int lastmember;
- int firstpos, size;
-
- eci->sizelast = 0;
- eci->sizemin = 2;
- for (i = 0 ; i < BLOCKSIZE ; i++) {
- eci->ciphertext[i] = cipher[i];
- eci->scipher[i] = (cipher[i] + i)&MODMASK;
- eci->perm[i] = perm[i];
- eci->permmap[i] = NONE;
- }
- decode(eci->ciphertext, eci->plaintext, eci->perm);
-
-
- /* The permmap points to the most recent member we have seen */
- /* of each known class, or a NONE. Ptrs are array indexes. */
- for (i = BLOCKSIZE-1 ; i >= 0 ; i--) {
- eci->next[i] = i;
- if ((lastmember = eci->permmap[eci->scipher[i]]) != NONE) {
- eci->next[i] = eci->next[lastmember];
- eci->next[lastmember] = i;
- }
- eci->permmap[eci->scipher[i]] = i;
- }
-
- for (i = 0 ; i < BLOCKSIZE ; i++) {
- firstpos = eci->permmap[i];
- if (firstpos != NONE) {
- size = ec_compsize(eci, firstpos);
- ec_addsize(eci, size, firstpos);
- }
- }
- }
-
-
- /* Add an entry to the size list.
- * Implementation: Find the first slot before sizelast+1 that
- * has a size less than the size arg. Shuffle down the list
- * to create a hole and insert the new entry.
- */
- ec_addsize(eci, size, firstmember)
- register ecinfo *eci;
- int size;
- int firstmember;
- {
- int k; /* Slot where new entry will go. */
- int i;
- ecsize sizeinfo;
-
- if (size < eci->sizemin) return;
-
- sizeinfo.size = size;
- sizeinfo.firstpos = firstmember;
- for (k = 0 ; k < eci->sizelast ; k++) {
- if (eci->sizelist[k].size < size) break;
- }
- if (k >= SZMAX) return;
-
- for (i = eci->sizelast ; i > k ; i--) {
- eci->sizelist[i] = eci->sizelist[i-1];
- }
- eci->sizelast++;
-
- eci->sizelist[k] = sizeinfo;
- }
-
-
- /* Compute the size of a clas given a pointer to one of its members.
- */
- int ec_compsize(eci, member)
- ecinfo *eci;
- int member;
- {
- int size;
- int position;
- int firstflag;
-
- size = 0;
- for_pos_in_class(position, member) {
- size++;
- }
- return(size);
- }
-