[comp.sources.unix] v10i005: Crypt Breaker's Workbench, Part05/11

rs@uunet.UU.NET (Rich Salz) (06/19/87)

Submitted by: Robert W. Baldwin <BALDWIN@XX.LCS.MIT.EDU>
Mod.sources: Volume 10, Issue 5
Archive-name: cbw/Part05

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 5 (of 11)."
# Contents:  Read.me cipher.c eclass.c knit.c zeecode.perm
# Wrapped by rs@uunet on Wed Jun 17 18:17:17 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f Read.me -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Read.me\"
else
echo shar: Extracting \"Read.me\" \(9793 characters\)
sed "s/^X//" >Read.me <<'END_OF_Read.me'
X
XUNPACKING NOTES [by Rich $alz]
X	There Usenet distribution of CBW includes six files that have
Xbeen UUENCODE'd because they contain non-printing characters:
X	    UU.foo UU.graphics UU.test UU.test1 UU.test2 UU.test3
XYou must first decode these files before using them; one of
Xthe command sets will do the trick:
X	for I in UU.* ; do uudecode $I ; done	-- /bin/sh
X	foreach I (UU.*)			-- C shell
X	    uudecode $I				--
X	end					--
X
X	This directory contains the source, documentation, and
Xauxilary files for the Crypt Breakers Workbench (cbw).  CBW is
Xa multi-window integrated workbench of tools that help a cryptanalist
Xread files encrypted with the BSD4.2 crypt command.  Anyone
Xmay copy, modify, use, or redistribute this system.  It was
Xoriginally written by Robert W. Baldwin at MIT.
X
X
XGETTING STARTED
X
X	A user's manual is provided in cbw.doc.  The scribe source
Xfor the user's manual is in cbw.mss.  The file Index briefly describes
Xthe various programs in this directory.
X
X	CBW is written in C and distributed with the source code to
Xencourage people to play with it.  It should run on any display
Xterminal.  Read the users manual for information on terminal
Xcompatibility.
X
X
X	
XTO COMPILE CBW
X
X	Execute "make" with no arguments.  CBW uses routines from the termcap
Xand curses libraries, but it does not use the full curses package.
X
X
XA FEW OTHER NOTES
X
X	Page 2 of the users manual mentions that CBW cannot work
X	against files that have been run through compress (1) before
Xencryption.  Personally, I would prefer to have a DES-based
Xself-inverse cipher.  Most DES programs need to be told whether they
Xare in encrypt or decrypt mode.  However, IBM only grants free use of
XDES if it is used according to NBS guidelines, and self-inverse is not
Xone of the accepted operating modes.
X
X
XTESTING
X
X     The following is a step by step sequence of commands to exercise
Xthe Crypt Breakers Workbench.  It demonstrates how easily crypt files
Xcan be broken.
X
X   1. Edit  stats.slice to set the name of the directory that contains the
X      statistics files.  Statistics for scribe documents are included with
X      the source files.
X
X      The  stats.slice  file  also  defines the location of the dictionary
X      used by the lookup-pattern  command.    The  default  dictionary  is
X      /usr/dict/words.    The  dictionary is just a list of words, one per
X      line.  Case does not matter.
X
X   2. Execute 'source  stats.slice'  to  initialize  the  necessary  shell
X      variables.
X
X   3. If there is a .slice file for your terminal type (e.g., vt100.slice,
X      or h19.slice), execute source on that file.   This  initializes  the
X      graphics map and key map.
X
X   4. Print  out  cbw.doc,  so you can read it after you have decided that
X      you can't figure out how the program works.
X
X   5. Copy test3.perm and .cipher to foo.perm and foo.cipher.    The  .txt
X      files contain the original plaintext.
X
X   6. Execute 'cbw foo'.
X
X   7. The  cursor  will  on the command line.  Use the arrow keys (or C-P,
X      C-N, C-F, C-B) to move the cursor to the upper lefthand position  of
X      the  decryption  window.   Try typing '@Device[Dover]'.  Notice that
X      most of the characters you type  deduced  other  characters  in  the
X      block.
X
X   8. The  'D'  in  'Dover'  is wrong.  Using the arrow keys, position the
X      cursor over the 'D' and type 'd'.
X
X   9. Advance to the position after the ']' and  type  C-T.    A  list  of
X      possible  characters  for this position will be displayed.  The list
X      is sorted with the most likely character on the left.   Notice  that
X      many characters are not possible because they would deduce non-ascii
X      characters elsewhere in the  block,  or  they  would  conflict  with
X      previously accepted guesses.
X
X      Try  guessing  tab,  comma  and linefeed for the character after the
X      ']'.  Use C-G to undo each guess.  Delete and C-D do not restore the
X      old  state,  they  just  erase  the  wiring  that  was  deduced by a
X      particular character.
X
X  10. Move the cursor down to the command line.  You can use emacs  cursor
X      characters  (C-N,  C-P, C-F, C-B) or the arrow keys.  Unfortunately,
X      C-U does not work as in emacs.  The C-X key or F4 will jump directly
X      to the command line.
X
X  11. Type  'pw  '.    The  space  will  cause  command completion for the
X      probable-word guessing command.  Type F2 (or C-S) to advance to  the
X      first  argument,  and  enter  the  file name 'mss.words'.  That file
X      contains a list of keywords used  by  the  Scribe  (Finalword)  text
X      formatter.    Press  F2  to  advance  to  the second argument, which
X      specifies a cut-off level for automatically accepting guesses.   The
X      level  is the maximum number of standard deviations that the scoring
X      function can be away from its expected value.  Enter 1.2, and  press
X      return to invoke the command.
X
X  12. A  partially filled in block will appear in the guessing window.  To
X      accept the result of this command, press F3 (or C-A).
X
X  13. Try the pword guess command again with a level of 3.   To  do  this,
X      just  move  to  the  command  line, change the 1.2 to a 3, and press
X      return.  Again F3 accepts the guess.  If  some  guesses  look  wrong
X      (such  as the 'F' on the second line under the '[Article]'), you can
X      correct them using the editor in the decryption block window.
X
X  14. Advance to block  1  of  the  file  by  moving  the  cursor  to  the
X      decryption  window and pressing F2 (or C-S).  F1 (or C-R) moves back
X      one block, F2 moves ahead one block.
X
X  15. The second block is likely to  be  plain  english  with  few  scribe
X      commands.    Move  to the command window, type C-U to erase the line
X      and type 'bi ' to  setup  the  bigram  guessing  command.    Try  an
X      acceptance  level  of  1.0  and  a minimum probability of 0.6.  Type
X      return to invoke the command.
X
X  16. After a short wait (~15  seconds),  a  partial  block  will  appear.
X      Accept the guess with the F3 key in the guessing window.
X
X  17. Try  looking  up a pattern in the dictionary.  In the command window
X      type 'look ', use F2 to advance to the  pattern,  and  type  in  the
X      pattern  '....llit.', and press return.  This will match against the
X      word 'satellite' if it is in you site's dictionary.
X
X  18. One could go on like this, but let's skip  ahead  by  loading  in  a
X      previously  saved state.  Invoke the load command (it loads the file
X      foo.perm, just as save dumps to foo.perm (making this command take a
X      filename  is  a  good implementation exercise)).  Type C-U, 'load ',
X      and return.  Notice that all the work so  far  is  replaced  by  the
X      information in the .perm file.  This can be considered a feature.
X
X  19. Use  the  F1 and F2 keys in the decryption window to view the blocks
X      that have been solved.  Notice that a fully solved  block  does  not
X      specify  all  the wirings of the block key (permutation).  Typically
X      only 105 of the 128 wires are used.
X
X  20. Lets try deducing the inter-block relationship (zee).   Execute  the
X      clear-zee command.
X
X  21. Execute  knit  blocks 0 through 3 with a min show count of 20.  This
X      means that the program should only show you guesses that  deduce  20
X      or more wirings of the zee permutation.  Press return to invoke this
X      guessing strategy.  The cursor will move  to  the  guessing  window.
X      Press F2 to start the first round of guessing.
X
X      The running time of the knit command is exponential in the number of
X      blocks knitted, and it will run for a very long time if any  of  the
X      blocks  are  decrypted incorrectly.  This means that it is better to
X      leave a position blank than to guess at it.
X
X  22. The program moves to block 4 and shows you the characters in block 4
X      that would be deduced from block 3 given the deduced wirings of zee.
X      If these look reasonable, press F3 to accept the guess, and press F2
X      to try the next guess.  To reject a guess, press F2 without pressing
X      F3.
X
X  23. Now that part of zee is known, try propagating the settings of block
X      1 into block 0 using zee.  The propagate command will do this.  Also
X      try propagating blocks 2, 3, and 4 to zero.
X
X      Notice that the number of known wires can increase without  deducing
X      additional characters in the block.
X
X  24. There should be a command that propagates information between groups
X      of blocks, but for now you must do this one block at a time.   After
X      propagating  block 1 - 4 to block zero, and block zero to blocks 1 -
X      4, et cetera, try the knit command again.
X
X  25. Propagate block 4 to 5  to  provide  a  framework  to  evaluate  new
X      guesses.
X
X  26. Knit block 0 through 4 with a minimum show level of 2.  You may want
X      to skip accepting guesses that do not deduce any characters.  Repeat
X      this process with a show level of 1.
X
X  27. The  program  should  now  know  all 256 wirings of zee.  Repeat the
X      process of propagating information  between  blocks  until  all  128
X      wires of the block zero are known.
X
X  28. Save  your  work  with the save-permutations command (on the command
X      line type 'sa ' and press return).  This writes the file foo.perm.
X
X  29. Exit the program with the quit command.
X
X  30. Copy foo.perm to zeecode.perm.
X
X  31. Execute 'zeecode < foo.cipher | more '.  This  program  reads  CBW's
X      save  file  to  find  the  permutation  for  block  zero and the Zee
X      permutation  that  describes  how  the  remaining  block  keys   are
X      generated.    Using  this  information it decodes standard input and
X      writes on standard output.
X
X  32. That's all.
END_OF_Read.me
if test 9793 -ne `wc -c <Read.me`; then
    echo shar: \"Read.me\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f cipher.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"cipher.c\"
else
echo shar: Extracting \"cipher.c\" \(9641 characters\)
sed "s/^X//" >cipher.c <<'END_OF_cipher.c'
X/* 
X * Routines for operating on cipher blocks.
X *
X * Robert W. Baldwin, January 1985.
X */
X
X
X#include	<stdio.h>
X#include	<math.h>
X#include	"window.h"
X#include	"specs.h"
X#include	"cipher.h"
X
X
X#define	DEBUG	FALSE
X
X
X/* Decode the cblock into pblock using perm.
X * Return FALSE if find a non-ascii character, else 1.
X */
Xdecode(cblock, pblock, perm)
Xchar	cblock[];
Xint		pblock[];
Xint		perm[];
X{
Xint iplace;		/* Index into ciphertext block. */
Xint spchar;		/* Plaintext char not unshifted. */
Xint pchar;		/* Plaintext char. */
Xint	good;		/* Plaintext doesn't have any unacceptable chars in it. */
X
Xgood = TRUE;
Xfor (iplace = 0 ; iplace < BLOCKSIZE ; iplace++) {
X	spchar = perm[(iplace+cblock[iplace])&MODMASK];
X	if (spchar == -1) {
X		pchar = -1;
X		}
X	else {
X		pchar = (spchar-iplace) & MODMASK;
X		if (notascii(pchar))  {
X			good = FALSE;
X			}
X		}
X	pblock[iplace] = pchar;
X	}
Xreturn(good);
X}
X
X
X/* Searches for string in block.
X * Returns position it found that didn't have conflicts, or -1.
X * If found, it will add to perm all the deduced wirings.
X * If perm is not initially all -1, search will not accept any
X * position that conflicts with the initial wirings, nor will
X * it mutate any of those wirings.
X */
Xint	search(cipher, perm, initpos, thing)
Xchar	*cipher;
Xint		*perm;
Xint		initpos;
Xchar	*thing;		/* NULL terminated string. */
X{
X	int	iplace;		/* Current placement of trigram in plaintext block. */
X	int i;			/* Index for initializing arrays. */
X	int	pchar;		/* Plaintext character. */
X	int	spchar;		/* Plaintext character cyclically shifted by its pos. */
X	int	*spstkp;
X	int	spstack[BLOCKSIZE];
X	int	*scstkp;
X	int	scstack[BLOCKSIZE];
X	int	scchar;		/* Ciphertext character cyclically shifted by its pos. */
X	int	offset;
X	int	thinglen;
X	char *p;
X
X	p = thing;
X	for (thinglen = 0 ; *p++ != 0 ; thinglen++) ;
X
X  for (iplace = initpos ; iplace < BLOCKSIZE-thinglen ; iplace++) {
X	spstkp = spstack;
X	scstkp = scstack;
X	for (offset = 0 ; offset < thinglen ; offset++) {
X		pchar = ((int) thing[offset]);
X		spchar = (pchar + iplace + offset) & MODMASK;
X		scchar = (cipher[iplace + offset] + iplace + offset) & MODMASK;
X		if ((perm[spchar] != -1  ||  perm[scchar] != -1)
X		 && (perm[spchar] != scchar))  {
X				while (spstkp > &spstack[0]) perm[*(--spstkp)] = -1;
X				while (scstkp > &scstack[0]) perm[*(--scstkp)] = -1;
X				goto nextplace;
X				}
X		perm[spchar] = scchar;
X		*spstkp++ = spchar;
X		perm[scchar] = spchar;
X		*scstkp++ = scchar;
X		}
X	return(iplace);
X	nextplace: ;
X	}
X  return(-1);
X}
X
X
X/* Fill in the pvec with the characters decoded from assuming
X * that the ciphertext character at position firstpos maps to
X * the plaintext character firstplain.
X * Return the number of characters added to pvec not counting
X * the termination character (NONE) that we always add.
X * If any of the characers decoded to non-ascii values, then
X * return ERROR (a negative number).
X * Also return ERROR if the guess would conflict with the ones already
X * in eci->perm.
X */
Xint	decode_class(eci, firstpos, firstplain, pvec)
Xecinfo	*eci;
Xint		firstpos;
Xint		firstplain;
Xint		*pvec;
X{
X	int		x,y;
X
X	firstpos = MODMASK & firstpos;
X	firstplain = CHARMASK & firstplain;
X
X	x = eci->scipher[firstpos];
X	y = MODMASK & (firstplain + firstpos);
X
X	return(decode_wire(eci, x, y, pvec));
X}
X
X
X/* Fill in the pvec with the characters decoded from assuming
X * that the permutation for this block maps x to y and vice-versa.
X * Return the number of characters added to pvec not counting
X * the termination character (NONE) that we always add (but not if
X * we return ERROR).
X * If any of the characers decoded to non-ascii values, then
X * return ERROR (a negative number).
X * Also return ERROR if the guess would conflict with the ones already
X * in eci->perm.
X * Also return ERROR if x == y.
X */
Xint	decode_wire(eci, x, y, pvec)
Xecinfo	*eci;
Xint		x;
Xint		y;
Xint		*pvec;
X{
X	decode_wire_but(eci, x, y, pvec, NONE, NONE);
X}
X
X
X/* Fill in the pvec with the characters decoded from assuming
X * that the permutation for this block maps x to y and vice-versa.
X * Return the number of characters added to pvec not counting
X * the termination character (NONE) that we always add (but not if
X * we return ERROR).
X * If any of the characers decoded to non-ascii values, then
X * return ERROR (a negative number).
X * Also return ERROR if the guess would conflict with the ones already
X * in eci->perm.
X * Also return ERROR if x == y.
X * DO NOT include any characters in the postions ranging from
X * first to last inclusive.
X */
Xint	decode_wire_but(eci, x, y, pvec, first, last)
Xecinfo	*eci;
Xint		x;
Xint		y;
Xint		*pvec;
Xint		first, last;
X{
X	int		delta;
X	int		pos, firstflag;
X	int		c,i;
X	int		firstpos;
X	int		otherpos;
X	int		pvecindex;
X
X
X	pvecindex = 0;
X	pvec[pvecindex] = NONE;
X	x = x & MODMASK;
X	y = y & MODMASK;
X	if (first > last)  {
X		printf("\ndecode_wire_but called with first > last.\n");
X		exit(0);
X		}
X
X	if (perm_conflict(eci->perm,x,y)  ||  x == y) {
X#if DEBUG
X		printf("CANNOT accept the guess of %d wired to %d.\n",
X				x, y);
X#endif
X		return(ERROR);
X		}
X
X	firstpos = eci->permmap[x];
X	if (firstpos != NONE) {
X		delta = y - x;
X		for_pos_in_class(pos, firstpos) {
X			if (first <= pos && pos <= last)  continue;
X			c = MODMASK & (eci->scipher[pos] + delta - pos);
X			if (c != (c & CHARMASK))  return(ERROR);
X			pvec[pvecindex++] = c;
X			}
X		}
X
X	otherpos = eci->permmap[y];
X	if (otherpos != NONE) {
X		delta = x - y;
X		for_pos_in_class(pos, otherpos) {
X			if (first <= pos && pos <= last)  continue;
X			c = MODMASK & (eci->scipher[pos] + delta - pos);
X			if (c != (c & CHARMASK))  return(ERROR);
X			pvec[pvecindex++] = c;
X			}
X		}
X
X	pvec[pvecindex] = NONE;
X	return(pvecindex);
X}
X
X
X
X/* Fill in an interger buffer from the characters of a byte buffer.
X * The buffers must have equal lengths.
X */
Xchar2buf(cptr, iptr, length)
Xchar	*cptr;
Xint		*iptr;
Xint		length;
X{
X	int		i;
X
X	for (i = 0 ; i < length ; i++)  {
X		*iptr++ = MODMASK & (*cptr++);
X		}
X}
X
X
X/* Fill in a character buffer from the integers of a byte buffer.
X * If the integer value is NONE, use nonechar instead.
X * The buffers must have equal lengths.
X */
Xbuf2char(cptr, iptr, length, nonechar)
Xchar	*cptr;
Xint		*iptr;
Xint		length;
Xint		nonechar;
X{
X	int		i;
X
X	for (i = 0 ; i < length ; i++)  {
X		if (*iptr != NONE)  {
X			*cptr++ = MODMASK & (*iptr++);
X			}
X		else {
X			*cptr++ = nonechar;
X			}
X		}
X}
X
X
X
X/* Fill in an interger vector with the characters from a null
X * terminated string.  The interger vector is terminated by the
X * value NONE.
X */
Xstr2pvec(cptr, iptr)
Xchar	*cptr;
Xint	*iptr;
X{
X	while (*iptr++ = (MODMASK & *cptr++));
X	*(--iptr) = NONE;
X}
X
X
X/* Fill in a null terminated string with the integers from a NONE
X * terminated vector.
X */
Xpvec2str(cptr, iptr)
Xchar	*cptr;
Xint		*iptr;
X{
X	while (*iptr != NONE)  {
X		*cptr++ = (MODMASK & *iptr++);
X		}
X	*cptr = 0;
X}
X
X
X/* Print a pvec on a stream.
X */
Xprint_pvec(out, pvec)
XFILE	*out;
Xint		*pvec;
X{
X	int		i,c;
X
X	i = 0;
X	while (*pvec != NONE)  {
X		c = *pvec++;
X		if (i++ % 20 == 0) fprintf(out,"\n");
X		write_char(out, c);
X		}
X	fprintf(out,"\n");
X}
X
X
X/* Returns number of wires added to permvec assuming
X * that plaintext str occurs at pos.
X * Fills in permvec.  Returns -1 if conflict.
X * Note that the last entry in permvec is marked by x == -1.
X * The permvec will not have duplicates and will not conflict
X * with the perm specified by eci->perm.
X */
Xint		permvec_from_string(eci, str, pos, permvec)
Xecinfo	*eci;
Xchar	*str;
Xint		pos;
Xperment	permvec[];
X{
X	int		wcount;
X	int		i, c, tmp;
X	int		x,y;
X	char	*cp;
X	int		curpos;
X
X	if (pos < 0 || pos >= BLOCKSIZE)  {return(ERROR);}
X
X	wcount = 0;
X	curpos = pos;
X	cp = str;
X	while ((c = (*cp & MODMASK)) != 0  &&  (curpos < BLOCKSIZE))  {
X		x = eci->scipher[curpos];
X		y = MODMASK & (c + curpos);
X		if (perm_conflict(eci->perm, x, y))  {
X			permvec[0].x = NONE;
X			return(ERROR);
X			}
X		for (i = 0 ; i < wcount ; i++) {
X			if ( (permvec[i].x == x  &&  permvec[i].y != y)
X			  || (permvec[i].x == y  &&  permvec[i].y != x)
X			  || (permvec[i].y == x  &&  permvec[i].x != y)
X			  || (permvec[i].y == y  &&  permvec[i].x != x) )  {
X#if DEBUG
X				printf("Conflict within permvec.\n");
X#endif
X				permvec[0].x = NONE;
X				return(ERROR);
X				}
X			if ( (permvec[i].x == x  &&  permvec[i].y == y)
X			  || (permvec[i].x == y  &&  permvec[i].y == x) )
X			    break;
X			}
X		permvec[i].x = x;
X		permvec[i].y = y;
X		if (i >= wcount)  wcount++;
X	 	curpos++;
X		cp++;
X		}
X
X	permvec[wcount].x = NONE;
X	return(wcount);
X}
X
X
X
X/* Copy routine for permvecs.
X */
Xpermvec_copy(from, to, maxnum)
Xperment	from[];
Xperment	to[];
Xint		maxnum;
X{
X	int		i;
X
X	for (i = 0 ; i < maxnum ; i++)  {
X		to[i] = from[i];
X		if (from[i].x == NONE) break;
X		}
X}
X
X
X/* Copy routine for pvecs.
X */
Xpvec_copy(from, to, maxnum)
Xint		from[];
Xint		to[];
Xint		maxnum;
X{
X	int		i;
X
X	for (i = 0 ; i < maxnum ; i++)  {
X		to[i] = from[i];
X		if (from[i] == NONE) break;
X		}
X}
X
X
X
X/* Fills in pvec with the plaintext characters deduced
X * from the wires in permvec that are not in the positions
X * ranging from butfirst to butlast.  Returns -1 if any
X * non-ascii chars are deduced, else count of chars.
X */
Xint		permvec2pvec(eci, permvec, pvec, butfirst, butlast)
Xecinfo	*eci;
Xperment	permvec[];
Xint		pvec[];
Xint		butfirst;
Xint		butlast;
X{	int		i, x, y;
X	int		ccount;
X	int		added;
X
X	ccount = 0;
X
X	for (i = 0 ; permvec[i].x != NONE ; i++)  {
X		if (ccount >= BLOCKSIZE-1) break;
X		x = permvec[i].x;
X		y = permvec[i].y;
X		added = decode_wire_but(eci, x, y, &(pvec[ccount]), butfirst, butlast);
X		if (added < 0)  {
X#if DEBUG
X			printf("permvec wire decodes to non-ascii.\n");
X#endif
X			pvec[0] = -1;
X			return(ERROR);
X			}
X		ccount += added;
X		}
X	pvec[ccount] = -1;
X	return(ccount);
X}
END_OF_cipher.c
if test 9641 -ne `wc -c <cipher.c`; then
    echo shar: \"cipher.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f eclass.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"eclass.c\"
else
echo shar: Extracting \"eclass.c\" \(9192 characters\)
sed "s/^X//" >eclass.c <<'END_OF_eclass.c'
X/*
X * Equivalence class information about a cipher block.
X *
X * Bob Baldwin, January 1985.
X */
X
X#include	<stdio.h>
X#include	<math.h>
X#include	"window.h"
X#include	"terminal.h"
X#include	"layout.h"
X#include	"specs.h"
X#include	"cipher.h"
X
X
X#define	DEBUG	FALSE
X
X#define	MIN_SHOW_SCORE	(0.7)
X#define	ECBLABEL1	"Equiv class guessing at level %6.3f  -- Please Wait"
X#define	ECBLABEL2	"Equiv class guessing at level %6.3f  -- Done"
X#define	ECBHELP "F3 enters guess, ^G undoes it."
X
X
Xextern	char	mcbuf[];
Xextern	ecinfo	gecinfo;
Xextern	ecbdraw(), ecbfirst(), ecbenter(), ecbundo();
X
X/* Gloabal State. */
Xfloat	ec_accept_level = 0.0;
Xkeyer	ecbktab[] = {
X		{CACCEPT, ecbenter},
X		{CUNDO, ecbundo},
X		{CGO_UP, jogup},
X		{CGO_DOWN, jogdown},
X		{CGO_LEFT, jogleft},
X		{CGO_RIGHT, jogright},
X		{0, NULL},
X};
X
X
X/* Routine invoked by user to put up the equivalence class
X * guessing window.
X * The window is drawn empty, and then filled in with the guess.
X * Return NULL if command completes ok.
X */
Xchar	*ecbguess(str)
Xchar	*str;			/* Command line */
X{
X	ecinfo	*ecbi;
X	int		i;
X	gwindow	*ecb;
X
X	ecb = &gbstore;
X	ecbi = &gecinfo;
X	ec_init(mcbuf, refperm(dbsgetblk(&dbstore)), ecbi);
X
X	if ((i = sscanf(str, "%*[^:]: %f", &ec_accept_level)) != 1)  {
X		return("Could not parse acceptance level.");
X		}
X
X	gbsswitch(ecb, ((char *) ecbi), ecbktab, ecbfirst, wl_noop, ecbdraw);
X
X	sprintf(statmsg, ECBLABEL1, ec_accept_level);
X	gblset(&gblabel, statmsg);
X
X	ecbdraw(ecb);
X	fflush(stdout);
X
X	ec_autoguess(ecbi, ec_accept_level);
X	decode(ecbi->ciphertext, ecbi->plaintext, ecbi->perm);
X
X	sprintf(statmsg, ECBLABEL2, ec_accept_level);
X	gblset(&gblabel, statmsg);
X	ecbdraw(ecb);
X
X	return(NULL);
X}
X
X
X/*  (re) Draw the window.
X */
Xecbdraw(ecb)
Xgwindow	*ecb;
X{
X	int			i;
X	int			row, col;
X	ecinfo		*ecbi;
X
X	ecbi = ((ecinfo *) ecb->wprivate);
X	row = 1;
X	col = 1;
X
X	for (i = 0 ; i < BLOCKSIZE ; i++)  {
X		if (i%LINELEN == 0) {
X			wl_setcur(ecb, gbspos2row(i), gbspos2col(i));
X			}
X		plnchars(1, char2sym(ecbi->plaintext[i]));
X		}
X
X	for (i = gbspos2row(BLOCKSIZE) ; i <= GBHEIGHT ; i++) {
X		wl_setcur(ecb, i, 1);
X		plnchars(LINELEN, ' ');
X		}
X
X	for (i = 1 ; i <= GBHEIGHT ; i++) {
X		wl_setcur(ecb, i, LINELEN+1);
X		plnchars(ecb->wwidth - LINELEN, ' ');
X		}
X
X	wl_setcur(ecb, row, col);
X}
X
X
X/* First time cursor enters window.
X */
Xecbfirst(ecb, row, col)
Xgwindow	*ecb;
Xint			row, col;
X{
X	usrhelp(&user, ECBHELP);
X	wl_setcur(ecb, row, col);
X}
X
X
X/* Enter the guess into the decryption block.
X */
Xecbenter(ecb)
Xgwindow	*ecb;
X{
X	ecinfo		*ecbi;
X
X	ecbi = ((ecinfo *) ecb->wprivate);
X	dbsmerge(&dbstore, ecbi->perm);
X	wl_rcursor(ecb);
X}
X
X
X/* Undo the last guess.
X */
Xecbundo(ecb)
Xgwindow	*ecb;
X{
X	ecinfo		*ecbi;
X
X	ecbi = ((ecinfo *) ecb->wprivate);
X	dbsundo(&dbstore);
X	wl_rcursor(ecb);
X}
X
X
X
X
X/* Dump plaintext chars onto stream.
X */
Xec_dplain(out, eci)
XFILE	*out;
Xecinfo	*eci;
X{
X	int		i,c;
X	int		*pbuf;
X
X	pbuf = &eci->plaintext[0];
X	for (i = 0 ; i < BLOCKSIZE ; i++) {
X		c = *pbuf++;
X		if (i % 20 == 0)  fprintf(out,"\n");
X		if (c != NONE)
X			write_char(out, c);
X		else
X			write_char(out, '.');
X		}
X	fprintf(out,"\n");
X}
X
X
X/* Dump shifted cipher chars onto stream.
X */
Xec_dscipher(out, eci)
XFILE	*out;
Xecinfo	*eci;
X{
X	int		i,c;
X	int		*pbuf;
X
X	pbuf = &eci->scipher[0];
X	for (i = 0 ; i < BLOCKSIZE ; i++) {
X		c = *pbuf++;
X		if (i++ % 20 == 0)  fprintf(out,"\n");
X		if (c != NONE)
X			write_char(out, c);
X		else
X			write_char(out, '.');
X		}
X	fprintf(out,"\n");
X}
X
X
X/* Dump table of next pointers onto a stream.
X */
Xec_dnext(out, eci)
XFILE	*out;
Xecinfo	*eci;
X{
X	writeperm(out, &(eci->next[0]));
X}
X
X
X/* Dump size table onto a stream.
X */
Xec_dsizetab(out, eci)
XFILE	*out;
Xecinfo	*eci;
X{
X	int		i;
X
X	fprintf(out, "\nThere are %d classes longer than 1 character.\n",
X			eci->sizelast);
X	for (i = 0 ; i < eci->sizelast ; i++)  {
X		fprintf(out, "Size: %d,  First member: %d.\n",
X				eci->sizelist[i].size, eci->sizelist[i].firstpos);
X		}
X}
X
X
X/* Dump our permutation onto a stream.
X */
Xec_dperm(out, eci)
XFILE	*out;
Xecinfo	*eci;
X{
X	writeperm(out, &(eci->perm[0]));
X}
X
X
X/* Dump the permutation map onto a stream.
X */
Xec_dpmap(out, eci)
XFILE	*out;
Xecinfo	*eci;
X{
X	writeperm(out, &(eci->permmap[0]));
X}
X
X
X
X/* Update ecbi to reflect the automatic guesses.
X */
Xec_autoguess(ecbi, alevel)
Xecinfo	*ecbi;
Xfloat	alevel;
X{	int		i, c;
X	int		classpos;
X	int		x, y;
X
X	for (i = 0 ; i < ecbi->sizelast ; i++)  {
X		classpos = ecbi->sizelist[i].firstpos;
X		c = ec_best(ecbi, classpos, alevel);
X		if (c != NONE) {
X			x = ecbi->scipher[classpos];
X			y = MODMASK & (c + classpos);
X			if (!perm_conflict(ecbi->perm, x, y)) {
X				ecbi->perm[x] = y;
X				ecbi->perm[y] = x;
X				}
X#if DEBUG
X			else {
X				printf("ec_autoguess: Best guess conflicts");
X				printf(" with an accepted.\n");
X				}
X#endif
X			}
X		}
X}
X
X
X/* Score a single equivalence class.
X * Bigger scores are better scores.  They range from 0 to 1.
X * A score of zero means the choice is not possible.
X */
Xfloat	ec_cscore(eci, firstpos, plainchar)
Xecinfo	*eci;
Xint		firstpos;
Xint		plainchar;
X{
X	extern	float	logvar;
X	float	score;
X	int		pvec[BLOCKSIZE+1];
X	int		ccount;
X	char	str[BLOCKSIZE+1];
X
X
X	if (decode_class(eci, firstpos, plainchar, pvec) == ERROR)  {
X		return(0.0);
X		}
X
X	score = pvec_1score(pvec);
X	if (score < 0.0)  return(0.0);
X	score = exp(-(score * score) / 2.0);
X	for (ccount = 0 ; pvec[ccount] != NONE ; ccount++);
X	score = score / sqrt(2*PI*logvar/ccount);
X
X#if DEBUG
X	if (score > MIN_SHOW_SCORE) {
X		pvec2str(str, pvec);
X		printf("Derived characters are '%s", str);
X		printf("', their score is %7.4f\n", score);
X		}
X#endif
X	return(score);
X}
X
X
X/* Select best plaintext value for a ciphertext equiv class.
X * The class is identified by the position in the block of one
X * of the characters in the class.  The plaintext value for
X * an entire class can be specified by the plaintext value of
X * one of its members.  This routine returns the best plaintext
X * value for the ciphertext character at position firstpos.
X * If there is not a clear best value, NONE is returned.
X */
Xint	ec_best(eci, firstpos, alevel)
Xecinfo	*eci;
Xint		firstpos;
Xfloat	alevel;
X{
X	float	total_score, score;
X	float	best_score;
X	int		best_char;
X	int		c;
X	int		x,y;
X	float	count;
X
X#if DEBUG
X	int		pvec[BLOCKSIZE+1];
X	char	str[BLOCKSIZE+1];
X
X	printf("\n");
X	printf("The first position of this class is %d.\n", firstpos);
X#endif
X	total_score = 0.0;
X	best_score = 0.0;
X	count = 0.0;
X	best_char = NONE;
X
X	for (c = 0 ; c <= MAXCHAR  ; c++)  {
X		score = ec_cscore(eci, firstpos, c);
X		if (score > 0.0)  {
X			count += 1.0;
X			total_score += score;
X			}
X		if (score > best_score) {
X			best_score = score;
X			best_char = c;
X			}
X		}
X
X#if DEBUG
X	printf("Total score is %7.4f", total_score);
X	printf(".  Count is %4.0f.\n", count);
X#endif
X	if (total_score == 0.0  ||  count == 0.0  ||  best_char == NONE) {
X#if DEBUG
X		printf("NO GUESSES\n");
X#endif
X		return(NONE);
X		}
X#if DEBUG
X	printf("Best score is %7.4f", best_score);
X	printf(", which is %7.4f fraction of total", best_score/total_score);
X	printf(".\n");
X
X	decode_class(eci, firstpos, best_char, pvec);
X	pvec2str(str, pvec);
X	printf("The best chars are '%s.\n", str);
X#endif
X
X	if (best_score  >  alevel * (total_score - best_score)) {
X		return(best_char);
X		}
X	else {
X		return(NONE);
X		}
X}
X
X
X/* Fill in equiv class info from given ciphertext block
X * and permutation.
X */
Xec_init(cipher, perm, eci)
Xchar	cipher[];
Xint		perm[];
Xecinfo	*eci;
X{
X	int		i,j;
X	int		lastmember;
X	int		firstpos, size;
X
X	eci->sizelast = 0;
X	eci->sizemin = 2;
X	for (i = 0 ; i < BLOCKSIZE ; i++)  {
X		eci->ciphertext[i] = cipher[i];
X		eci->scipher[i] = (cipher[i] + i)&MODMASK;
X		eci->perm[i] = perm[i];
X		eci->permmap[i] = NONE;
X		}
X	decode(eci->ciphertext, eci->plaintext, eci->perm);
X
X
X	/* The permmap points to the most recent member we have seen */
X	/* of each known class, or a NONE.  Ptrs are array indexes. */
X	for (i = BLOCKSIZE-1 ; i >= 0 ; i--) {
X		eci->next[i] = i;
X		if ((lastmember = eci->permmap[eci->scipher[i]]) != NONE) {
X			eci->next[i] = eci->next[lastmember];
X			eci->next[lastmember] = i;
X			}
X		eci->permmap[eci->scipher[i]] = i;
X		}
X
X	for (i = 0 ; i < BLOCKSIZE ; i++)  {
X		firstpos = eci->permmap[i];
X		if (firstpos != NONE)  {
X			size = ec_compsize(eci, firstpos);
X			ec_addsize(eci, size, firstpos);
X			}
X		}
X}
X
X
X/* Add an entry to the size list.
X * Implementation:  Find the first slot before sizelast+1 that
X * has a size less than the size arg.  Shuffle down the list
X * to create a hole and insert the new entry.
X */
Xec_addsize(eci, size, firstmember)
Xregister	ecinfo	*eci;
Xint		size;
Xint		firstmember;
X{
X	int		k;		/* Slot where new entry will go. */
X	int		i;
X	ecsize	sizeinfo;
X
X	if (size < eci->sizemin) return;
X
X	sizeinfo.size = size;
X	sizeinfo.firstpos = firstmember;
X	for (k = 0 ; k < eci->sizelast ; k++)  {
X		if (eci->sizelist[k].size < size)  break;
X		}
X	if (k >= SZMAX) return;
X
X	for (i = eci->sizelast ; i > k ; i--)  {
X		eci->sizelist[i] = eci->sizelist[i-1];
X		}
X	eci->sizelast++;
X
X	eci->sizelist[k] = sizeinfo;
X}
X
X
X/* Compute the size of a clas given a pointer to one of its members.
X */
Xint	ec_compsize(eci, member)
Xecinfo	*eci;
Xint		member;
X{
X	int		size;
X	int		position;
X	int		firstflag;
X
X	size = 0;
X	for_pos_in_class(position, member) {
X		size++;
X		}
X	return(size);
X}
END_OF_eclass.c
if test 9192 -ne `wc -c <eclass.c`; then
    echo shar: \"eclass.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f knit.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"knit.c\"
else
echo shar: Extracting \"knit.c\" \(10707 characters\)
sed "s/^X//" >knit.c <<'END_OF_knit.c'
X/*
X * Use serveral mostly solved blocks to solve the knitting equation
X * and deduce the rotor and reflector wirings.
X *
X * Robert W. Baldwin, December 1984.
X */
X
X
X#include	<stdio.h>
X#include	"window.h"
X#include	"terminal.h"
X#include	"layout.h"
X#include	"specs.h"
X
X
Xextern	char	gcbuf[];		/* All guess displays use same buffers. */
Xextern	int		gpbuf[];
Xextern	int		gperm[];
X
X
X#define KNTHELP	"F2 = next guess, F3 = enter guess, ^G = Undo enter."
X#define STARTMSG "Knitting from %d to %d.   Known Zee: %d of 256."
X#define GUESSMSG "guesscount = %d, xi=%d, yi=%d.   Known Zee: %d of 256."
X#define UNDOMSG  "Undone.  Current known Zee: %d of 256"
X#define	BIG		1000		/* Size of try stack in kntadvance(). */
X
X
X/* Pack and unpack two bytes into an integer. */
X#define pack(x,y)		(((x&0377)<<8) + y)
X#define unpack(x,y,v)	tmpv = v; x = ((tmpv>>8)&0377);  y = (tmpv&0377);
X
X
X/* Keystroke handler table. */
X
Xextern	int	kntadvance();
Xextern	kntundo();
Xextern	kntnextg();
Xextern	kntenter();
X
Xkeyer	kntktab[] = {
X		{CNEXTGUESS, kntnextg},
X		{CACCEPT, kntenter},
X		{CUNDO, kntundo},
X		{CGO_UP, jogup},
X		{CGO_DOWN, jogdown},
X		{CGO_LEFT, jogleft},
X		{CGO_RIGHT, jogright},
X		{0, NULL},
X};
X
X
X
X/* Private data structure for guess blocks. */
X
X#define	kntinfo		struct	xkntinfo
Xstruct	xkntinfo	{
X		char	*cbuf;		/* The cipher block. */
X		int		*pbuf;		/* The derived guess plaintext, -1 = none. */
X		int		*perm;		/* Permutation of block highbnum+1. */
X		int		xindex;		/* Starting position of next x guess. */
X		int		yindex;		/* Starting position of next y guess. */
X		int		*zee;		/* Knitting matrix. */
X		int		*zeeinv;	/* Its inverse. */
X		int		*ustkp;		/* Undo stack pointer. */
X		int		*savedustkp;	/* Undo stack pointer. */
X		int		*undostk;	/* Undo stack. */
X		int		lowbnum;	/* Block number of lowest source. */
X		int		highbnum;	/* Block number of highest source. */
X		int		min_show;	/* Smallest count to show. */
X		};
X
X
X/* Private buffers. */
Xint		kzee[BLOCKSIZE+1];
Xint		kzeeinv[BLOCKSIZE+1];
Xint		kustk[BLOCKSIZE+1];
X
Xkntinfo	kntprivate;
X
Xint		kntinit	= FALSE;
X
X
Xextern	kntdraw(), kntfirst();		/* Defined below. */
X
X
X/* This routine is called by the user command to clear the zee matrix.
X */
Xchar	*clearzee(str)
Xchar	*str;		/* Command line */
X{
X	int		i;
X	kntinfo	*knti;
X
X	knti = &kntprivate;
X	initknt();
X	kntclrzee(knti);
X
X	if (&kntprivate == ((kntinfo *) gbstore.wprivate)) {
X		for (i = 0 ; i < BLOCKSIZE ; i++)  {
X			knti->perm[i] = -1;
X			}
X		decode(knti->cbuf, knti->pbuf, knti->perm);
X		sprintf(statmsg, GUESSMSG,
X				0, knti->xindex, knti->yindex, zeecount(knti));
X		gblset(&gblabel, statmsg);
X		wl_draw(&gbstore);
X		}
X
X	wl_rcursor(&user);
X	return(NULL);
X}
X
X
X
X/* This routine is called to set up the guess block window
X * to be used for guessing the zee matrix.
X * It can be directly invoked by the command interpreter.
X * Set up dbstore to show the block after the last block
X * the the user says to consider complete.
X */
Xchar	*kntguess(str)
Xchar	*str;		/* Command line */
X{
X	int		i;
X	int		from,to;
X	gwindow	*knt;
X	kntinfo	*knti;
X
X	knt = &gbstore;
X	knti = &kntprivate;
X	initknt();
X
X	if (!kntinit) {
X		kntinit = TRUE;
X		kntclrzee(knti);
X		}
X
X	for (i = 0 ; i < BLOCKSIZE ; i++)  {
X		knti->perm[i] = -1;
X		}
X
X	from = to = 0;
X	if ((i = sscanf(str,"%*[^:]: %d %*[^:]: %d %*[^:]: %d",
X					&from, &to, &knti->min_show)) != 3) {
X		return("Could not parse all arguments.");
X		}
X	else {
X		if (to <= from)
X			return("To: must be less than From:");
X		}
X	
X	dbssetblk(&dbstore, to+1);
X	if (!fillcbuf(to+1, knti->cbuf)) {
X		return("Bad to: value");
X		}
X	decode(knti->cbuf, knti->pbuf, knti->perm);
X	knti->xindex = 0;
X	knti->yindex = 0;
X	knti->lowbnum = from;
X	knti->highbnum = to;
X
X	gbsswitch(knt,((char *) knti), kntktab, kntfirst, wl_noop, kntdraw);
X	sprintf(statmsg, STARTMSG, from, to, zeecount(knti));
X	gblset(&gblabel, statmsg);
X	kntdraw(knt);
X
X	wl_setcur(knt, 1, 1);
X	return(NULL);
X}
X
X
X
X/* Clear the zee permutation and update any display info.
X */
Xkntclrzee(knti)
Xkntinfo	*knti;
X{
X	int		i;
X
X	for (i = 0 ; i < BLOCKSIZE ; i++)  {
X		knti->zee[i] = -1;
X		knti->zeeinv[i] = -1;
X		}
X}
X
X
X/* Compute the next successful guess of a wiring of ZEE.
X * Show it to the user for acceptance/rejection.
X */
Xkntnextg(knt)
Xgwindow	*knt;
X{
X	int		guesscnt;
X	kntinfo	*knti;
X	knti = ((kntinfo *) knt->wprivate);
X
X	kntclrlast(knti);
X	while (TRUE) {
X		guesscnt = kntadvance(knti);
X		if ((guesscnt == 0) || (guesscnt >= knti->min_show))  break;
X		kntclrlast(knti);
X		}
X	if (guesscnt == 0)  {
X		gblset(&gblabel, "No more guesses");
X		return;
X		}
X	decode(knti->cbuf, knti->pbuf, knti->perm);
X
X	sprintf(statmsg, GUESSMSG,
X			guesscnt, knti->xindex, knti->yindex, zeecount(knti));
X	gblset(&gblabel, statmsg);
X	kntdraw(knt);
X}
X
X
X
X/* Clear last guess in zee, zeeinv, perm.
X * Note that perm only holds the results of the last guess.
X */
Xkntclrlast(knti)
Xkntinfo	*knti;
X{
X	int		tmpv;	/* For unpack. */
X	int		x,y;
X	int		i;
X
X	while (knti->ustkp > knti->undostk)  {
X		unpack(x, y, *(--(knti->ustkp)));
X		knti->zee[x] = -1;
X		knti->zeeinv[y] = -1;
X		}
X	knti->ustkp = knti->savedustkp = knti->undostk;
X		
X	for (i = 0 ; i < BLOCKSIZE ; i++) {
X		knti->perm[i] = -1;
X		}
X}
X
X
X
X/* Advance to the next acceptable guess at a wiring for Zee.
X * This modifies zee, zeeinv, and perm.  Perm only contains the
X * info derived from this guess, while zee and zeeinv accumulate
X * information from all preceeding accepted guesses.
X * Returns the number of guesses that we derived from the initial one.
X * If out of acceptable guesses, returns 0.
X * Perm must be cleared before calling this.
X */
Xint	kntadvance(knti)
Xkntinfo	*knti;
X{
X	int		guesscount;
X	int		i;
X	int		tmpv;		/* For unpack. */
X	int		x,y;
X	int		tx,ty;
X	int		u,v;
X	int		tu,tv;
X	int		*a2;		/* The permutation as in u = A2 x */
X	int		*a1;		/* The permutation as in v = A1 y */
X	int		*propp;		/* Temp for undo stack propagation. */
X	int		*highperm;	/* Perm used to derive next perm. */
X	int		trycount;	/* Size of trystk. */
X	int		*tstkp;		/* Stack of guesses to check. */
X	int		trystk[BIG];
X
X/* kntadvance(knti)
X */
X	guesscount = 0;		/* In case loop body never executes. */
X
X	if (knti->xindex >= BLOCKSIZE)  return(0);
X	if (knti->yindex >= BLOCKSIZE)  {
X		knti->yindex = 0;
X		knti->xindex++;
X		}
X
X	for (x = knti->xindex ; x < BLOCKSIZE ; x++) {
X		if (knti->zee[x] != -1)  {
X			knti->yindex = 0;
X			continue;
X			}
X		for (y = knti->yindex ; y < BLOCKSIZE ; y++) {
X			if (knti->zeeinv[y] != -1)  continue;
X			guesscount = 0;
X			tstkp = trystk;					/* Assume ustkp == undostk. */
X			trycount = 0;
X			*(tstkp++) = pack(x,y);
X			trycount++;
X
X			while (tstkp > trystk) {
X				unpack(tx, ty, *(--tstkp));
X				trycount--;
X				if (knti->zee[tx] == -1 && knti->zeeinv[ty] == -1) {
X					knti->zee[tx] = ty;
X					knti->zeeinv[ty] = tx;
X					*((knti->ustkp)++) = pack(tx,ty);
X					guesscount++;
X					for (i = knti->lowbnum ; (i+1) <= knti->highbnum ; i++) {
X						a1 = refperm(i);
X						a2 = refperm(i+1);
X						tu = a2[tx];
X						tv = a1[ty];
X						if (tu != -1 && tv != -1 && trycount < BIG) {
X							*(tstkp++) = pack(tu, tv);
X							trycount++;
X							}
X						}
X					}
X				else if (knti->zee[tx] != ty
X					  || knti->zeeinv[ty] != tx) {		/* If conflict. */
X						while (knti->ustkp > knti->undostk)  {
X							unpack(tx, ty, *(--(knti->ustkp)));
X							knti->zee[tx] = -1;
X							knti->zeeinv[ty] = -1;
X							guesscount--;
X							}
X						knti->ustkp = knti->undostk;
X						goto nxtguess;
X					  }
X				else continue;		/* Already know about it. */
X				}
X
X			knti->xindex = x;		/* Zee[x] = y was a good guess. */
X			knti->yindex = y+1;
X			propp = knti->ustkp;
X			highperm = refperm(knti->highbnum);
X			while (propp > knti->undostk) {  /* Update perm. */
X				unpack(tx, ty, *(--propp));
X				v = highperm[ty];
X				if (v != -1  &&  (tmpv = knti->zeeinv[v]) != -1)  {
X					knti->perm[tx] = tmpv;
X					knti->perm[tmpv] = tx;
X					}
X				}
X			return (guesscount);
X			nxtguess: ;
X			}
X		knti->yindex = 0;
X		}
X
X	knti->yindex = 0;
X	knti->xindex = 0;
X	return(guesscount);
X}
X			 
X
X/* Enter our current guess into the decryption block.
X * Clear out the undo stack.
X */
Xkntenter(knt)
Xgwindow	*knt;
X{
X	kntinfo	*knti;
X
X	knti = ((kntinfo *) knt->wprivate);
X	knti->savedustkp = knti->ustkp;		/* If we change our mind. */
X	knti->ustkp = knti->undostk;
X	if (knti->highbnum+1 != dbsgetblk(&dbstore))
X		dbssetblk(&dbstore, knti->highbnum+1);
X	dbsmerge(&dbstore, knti->perm);
X	wl_rcursor(knt);
X}
X
X
X/* Undo the last guess.
X */
Xkntundo(knt)
Xgwindow	*knt;
X{
X	kntinfo	*knti;
X
X	knti = ((kntinfo *) knt->wprivate);
X	knti->ustkp = knti->savedustkp;
X	kntclrlast();
X	dbsundo(&dbstore);
X
X	sprintf(statmsg, UNDOMSG, zeecount(knti));
X	gblset(&gblabel, statmsg);
X	wl_rcursor(knt);
X}
X
X
X/* Behavior when first enter the window.
X * Put up a help message.
X * Accept the cursor where it is.
X */
Xkntfirst(knt, row, col)
Xgwindow	*knt;
Xint		row,col;	/* Current coordinates. */
X{
X	usrhelp(&user, KNTHELP);
X	wl_setcur(knt, row, col);
X}
X
X
X
X/* (re)Draw the window.
X */
Xkntdraw(knt)
Xgwindow	*knt;
X{
X	int			i;
X	int			row, col;		/* Original row and column. */
X	kntinfo		*knti;
X
X	knti = ((kntinfo *) knt->wprivate);
X	row = knt->wcur_row;
X	col = knt->wcur_col;
X
X	for (i = 0 ; i < BLOCKSIZE ; i++)  {
X		if (i%LINELEN == 0) {
X			wl_setcur(knt, gbspos2row(i), gbspos2col(i));
X			}
X		plnchars(1, char2sym(knti->pbuf[i]));
X		}
X
X	for (i = gbspos2row(BLOCKSIZE) ; i <= GBHEIGHT ; i++) {
X		wl_setcur(knt, i, 1);
X		plnchars(LINELEN, ' ');
X		}
X
X	for (i = 1 ; i <= GBHEIGHT ; i++) {
X		wl_setcur(knt, i, LINELEN+1);
X		plnchars(knt->wwidth - LINELEN, ' ');
X		}
X
X	wl_setcur(knt, row, col);
X}
X
X
X/* Return number of known wires in Zee.
X * Max is 256.
X */
Xint	zeecount(knti)
Xkntinfo	*knti;
X{
X	return(permcount(knti->zee));
X}
X
X
X/* Store Zee permutation on a file.
X */
Xstorezee(fd)
XFILE	*fd;
X{
X	writeperm(fd, kzee);
X}
X
X
X/* Load the Zee permutation from a file.
X * Update display if necessary.
X */
Xloadzee(fd)
XFILE	*fd;
X{
X	int		i;
X	kntinfo	*knti;
X
X	knti = &kntprivate;
X	initknt();
X	kntinit = TRUE;
X	kntclrzee(knti);		/* Clear zeeinv */
X
X	readperm(fd, kzee);	
X	for (i = 0 ; i < BLOCKSIZE ; i++) {
X		if (kzee[i] != -1)  {kzeeinv[kzee[i]] = i;}
X		}
X
X	if (knti == ((kntinfo *) gbstore.wprivate)) {
X		for (i = 0 ; i < BLOCKSIZE ; i++)  {
X			knti->perm[i] = -1;
X			}
X		decode(knti->cbuf, knti->pbuf, knti->perm);
X		sprintf(statmsg, GUESSMSG,
X				0, knti->xindex, knti->yindex, zeecount(knti));
X		gblset(&gblabel, statmsg);
X		wl_draw(&gbstore);
X		wl_setcur(&gbstore, 1, 1);
X		}
X}
X
X
X/* Set up all the pointers in kntprivate.
X */
Xinitknt()
X{
X	int		i;
X	gwindow	*knt;
X	kntinfo	*knti;
X
X	knt = &gbstore;
X	knti = &kntprivate;
X
X	knti->zee = kzee;
X	knti->zeeinv = kzeeinv;
X
X	knti->cbuf = gcbuf;
X	knti->pbuf = gpbuf;
X	knti->perm = gperm;
X
X	knti->undostk = kustk;
X	knti->ustkp = knti->savedustkp = knti->undostk;
X}
END_OF_knit.c
if test 10707 -ne `wc -c <knit.c`; then
    echo shar: \"knit.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f zeecode.perm -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"zeecode.perm\"
else
echo shar: Extracting \"zeecode.perm\" \(11550 characters\)
sed "s/^X//" >zeecode.perm <<'END_OF_zeecode.perm'
X 28 146 116 150 159  64 172 249 200 232 
X 90 149  63 239 238  95  49 254 143   8 
X191 231 123 117 243 210 179 186 119  17 
X107  46 174 203  21  12  97  53 135  71 
X 52  78 204  31 220  77 211  24 225 121 
X 74 228 202 171  11  81  67  69 141 213 
X 66  94 195 217  29 154   3  15  59  76 
X205 155  25  93 209 160 212  36 173  68 
X221 193 176 196   4 138  99 222  70  57 
X  7 252  41  43  62  79  48  61 145  38 
X 20 216 166 208  40 187   0 153   5 137 
X 55 130 241   6 207 128 227 190 142 125 
X177  75 226 105   2 175  51 120  96  13 
X139  47 127 246 248  18  44  16 136 167 
X132 113 151  98 244 114 182 198 201 189 
X144  22 140 122 109  83 131 180 253  58 
X162  50 250 134  37   1  35 242  23 214 
X194 112 157 223 165 233 156 161 188 104 
X124 103  54 234  89  80 101  26  19  85 
X192 147 181  65 199   9 247 245 129  60 
X169 102  32  88 224 106 235  45 236  84 
X255  92 178 215 230  33 115 185  27  39 
X237 251  30  14 163 126 219  87 206  73 
X158  56 110 168  91 152 197 108 133 148 
X 72 118 184 240 100 164 111 170 183 229 
X 42  10 218  82  86  34 
X 96 114 124 223  97  19  10  13  43  44 
X  6  38 231   7 200 207 179 134 133   5 
X100 230  48 160 152  93 162 168 191 127 
X 65 103 183  90 252 193 243 242  11 180 
X 87 173 154   8   9  99 112  58  22 108 
X199  95  77  66 163  62 128 190  47  79 
X215 109  55 245  73  30  53 178 214  82 
X201 138 206  64 240 182 228  52 140  59 
X197 248  69 203 175 111 137  40 153 139 
X 33 195 212  25 217  51   0   4 251  45 
X 20 122 148  31 227 234 167 202  49  61 
X219  85  46 246   1 135 142 254 211 249 
X144 255 101 218   2 150 186  29  56 169 
X185 247 164  18  17 115 250  86  71  89 
X 78 205 116 222 120 216 226 158 102 189 
X125 225  24  88  42 159 221 188 147 155 
X 23 210  26  54 132 232 184 106  27 129 
X236 196 253  41 204  84 238 235  67  16 
X 39 192  75  32 166 130 126 224 157 149 
X 57  28 181  35 241  91 171  80 208  50 
X 14  70 107  83 174 141  72  15 198 233 
X161 118  92 244  68  60 145  94 123 110 
X237 156 143   3 187 151 146 104  76 239 
X 21  12 165 209 105 177 170 220 176 229 
X 74 194  37  36 213  63 113 131  81 119 
X136  98  34 172 117 121 
X 20 122 118 119  71 229 158  28 223 174 
X215  -1 197 249  82 126 237  23  87  93 
X  0  35 252  17  77 177 137 225   7 163 
X 52 171  42 155 214  21  84  60 216  85 
X 45 152  32 181 220  40 241 235 142 210 
X243  69  30  83  99 134 212 253  70 144 
X 37  63 234  61 132 250 173 114  95  51 
X 58   4  73  72 175 168 211  24  92 169 
X176 166  14  53  36  39 207  18 148 117 
X129 255  78  19 110  68 151 154 101  54 
X244  98 242 147 227 204 128 203 188 254 
X 94 217 170 251  67 231  -1  89   2   3 
X206 146   1 183  -1 209  15 150 106  90 
X184 159  64 141  55 238 195  26 162 205 
X245 133  48 221  59 165 121 103  88  -1 
X127  96  41 186  97  33 196  -1   6 131 
X187 194 138  29 167 145  81 164  75  79 
X112  31 178  66   9  74  80  25 172  -1 
X -1  43 224 123 130 236 153 160 108 246 
X192 230 190 222 161 136 156  12 200 213 
X198 239 248 107 105 139 120  86 247 125 
X 49  76  56 199  34  10  38 111 233  -1 
X 44 143 193   8 182  27 232 104 240   5 
X191 115 226 218  62  47 185  16 135 201 
X228  46 102  50 100 140 189 208 202  13 
X 65 113  22  57 109  91 
X 90  49  26 132 156 140 212 129 147 122 
X198  -1  97 148  38  79  25 154  80 173 
X214 216 248 184 161  16   2 107  66 168 
X 33 112 195  30 166 236  65 155  14  84 
X222 211 123  53 136  47  69  45 218   1 
X125 243 134  43  -1 102 145 126 238 194 
X 78 232 138 246 224  36  28 225 150  46 
X130 215 120 188 119 105 231 209  60  15 
X 18  87 185 176  39 160 182  81 159 158 
X  0 151 235 192 183 200 118  12 174  -1 
X106  -1  55 196 207  75 100  27 249 187 
X163 242  31 230 254 205 179 190  96  74 
X 72 233   9  42 241  50  57 228 142   7 
X 70 206   3 149  52 227  44 220  62 245 
X  5 221 128 186 244  56 204   8  13 133 
X 68  91 197 165  17  37   4 180  89  88 
X 85  24 193 110 199 153  34 201  29 255 
X177 247 226  19  98 252  83 170 237 116 
X157 191  86  94  23  82 143 109  73 219 
X117 181  93 162  59  32 103 152  10 164 
X 95 167 250 239 146 115 131 104 217  77 
X234  41   6 251  20  71  21 208  48 189 
X137 141  40 253  64  67 172 135 127 240 
X113  76  61 121 210  92  35 178  58 203 
X229 124 111  51 144 139  63 171  22 108 
X202 213 175 223 114 169 
X 60  42  26  79 203 204 122 237  15  97 
X106 238 133  33 159   8 165 145  27 191 
X192  69 250 117 126 183   2  18  50  65 
X218  57 143  13 101  36  35  93 116 213 
X163 199   1 171 109  74  92 177  56 175 
X 28 132 162 196  -1 227  48  31  80 221 
X  0 248 202 103 233  29 140  95 170  21 
X216 164 137 190  45 189 113 193 188   3 
X 58 160 155 181 176  94 186 104 111 225 
X198 125  46  37  85  67 252   9 231 223 
X169  34 255  63  87 154  10 174 152  44 
X201  88  -1  76 179 118  38  23 115 161 
X247 123   6 121 187  91  24 240 241 239 
X197 207  51  12 151 185 138  72 136 148 
X 66 214 234  32 150  17 254  -1 139 226 
X144 134 108 195 105  82 228 172 173  14 
X 81 119  52  40  71  16 208 246 242 100 
X 68  43 157 158 107  49  84  47 229 114 
X -1  83  -1  25 230 135  86 124  78  75 
X 73  19  20  77 245 153  53 130  90  41 
X210 110  62   4   5 244 211 131 166 219 
X200 206 220  39 141 222  70 253  30 209 
X212  59 215  99 232  89 149  55 156 178 
X184  98 224  64 142 236 235   7  11 129 
X127 128 168 249 205 194 167 120  61 243 
X 22  -1  96 217 146 102 
X161  17  99 150 223 175 172  24  25 204 
X147 122 181 198  54  56 125   1 202  67 
X188 143  49 168   7   8 145 254 177  98 
X 32 211  30  84  57 238 195  83 217 245 
X160 178 108  89  76  81 228 225 184  22 
X207 176  94  93  14  75  15  34 169 219 
X152 189 107 158 193 123  95  19  80 141 
X144 253 248 164 226  55  44 166 230 247 
X 68  45 209  37  33 138  -1 213 101  43 
X220 128 194  53  52  66 231 134  29   2 
X190  88 103 102 224 180 199  62  42 240 
X116 236 115 153 156 112 110 229 183 234 
X131 149  11  65 187  16 140 196  91 215 
X239 120 243 139  97 218 154 174  85 133 
X126  69 163  21  70  26 182  10 232 121 
X  3 162  60 113 136 192 114 171  63 185 
X 40   0 151 142  73 250  77 233  23  58 
X197 157   6  -1 137   5  51  28  41 227 
X105  12 146 118  48 159 255 124  20  61 
X100  -1 155  64  92  36 127 170  13 106 
X244 210  18 246   9 251 208  50 206  82 
X201  31 249  87 242 129 241  38 135  59 
X 90  -1 252   4 104  47  74 179  46 117 
X 78  96 148 167 119 237 111 235  35 130 
X109 216 214 132 200  39 203  79  72 212 
X165 205 222  71  27 186 
X120 146 232  66 217  81 113  76 144 239 
X 44  49 230 111 166  60 151 218  34  72 
X 80 128 193 249 140 148 116 210 183 165 
X 94  51 109 133  18 192 163  73 252 158 
X 61 214 195  46  10 102  43  90 131  11 
X122  31 135 172 153 207 188  58  57 227 
X 15  40  77  99 143 138   3 231 226 136 
X221 190  19  37 253 104   7  62 254 185 
X 20   5 126 132 173 189 124  91 150 255 
X 47  87 212 184  30 196 242 149 187  63 
X178 112  45 228  75 180 177 141 125  32 
X121  13 101   6 161 234  26 244 224 137 
X  0 110  50 157  86 108  82 156  21 147 
X238  48  83  33 240  52  69 119  65 175 
X 24 107 160  64   8 176   1 129  25  97 
X 88  16 225  54 243 164 127 123  39 200 
X142 114 174  36 155  29  14 169 233 167 
X211 216  53  84 162 139 145 106 100 204 
X105 201 223  28  93  79 203  98  56  85 
X 71 251  35  22 205  42  95 219 213 235 
X159 181 222 186 179 194 220  55 246 215 
X 27 170  92 198  41 209 171   4  17 197 
X206  70 202 182 118 152  68  59 103 245 
X 12  67   2 168 115 199 247 250 130   9 
X134 248  96 154 117 229 208 236 241  23 
X237 191  38  74  78  89 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
X -1  -1  -1  -1  -1  -1 
END_OF_zeecode.perm
if test 11550 -ne `wc -c <zeecode.perm`; then
    echo shar: \"zeecode.perm\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 5 \(of 11\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 11 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
gazee[i