/***********************************************************************/
/*                                                                     */
/*             This is an experimental Implementation of a             */
/*             Selfmodifying Interconnection-Network (SINC)            */
/*             with X-display                                          */
/*                                                                     */
/*             This program is part of a Diploma-Work                  */
/*             Further informations see:                               */
/*                                                                     */
/*          Diplomarbeit:                                              */
/*             Kryptographische Aspekte Selbstmodifizierender          */
/*             Verbindungsnetzwerke                                    */
/*                                                                     */
/*          Author: Felix Holderied                                    */
/*                                                                     */
/*          Betreuer: Priv. Doz. Dr. P Horster                         */
/*                                                                     */
/*             Institut fuer Algorithmen und kognitive Systeme         */
/*             Universitaet Karlsruhe                                  */
/*                                                                     */
/*          Date:   February 1993                                      */
/*                                                                     */
/***********************************************************************/

#include <stdio.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>

extern Display* XOpendisplay();
Window ik_window, buttons_window, root;
Display* display;
GC gc_draw, gc_erase, gc_buttons_draw, gc_buttons_erase;
XSetWindowAttributes ik_atts, buttons_atts;
XEvent xevent;

/* These are the coos of the left two corners of the matrices */
#define xkm 35
#define ykm 20
#define xim 140
#define yim 20

void inversion_0(),inversion_1(),inversion_2(),inversion_3(),
    inversion_4(),inversion_5(),inversion_6();
void (*inversion_functions[7])()=
  { inversion_0, inversion_1, inversion_2, inversion_3,
    inversion_4, inversion_5, inversion_6 };

static keys[15][128];
static inversion[15][128];
static path[15];
static statistic[256];
static stat2[1000];
int net=1;
int inv=0;
int m=1;
static perms[15][256];           /* Last permutation must be identity */

static int randommode=1;

void clear_keys()                /* Sets the key-matrix to (0) */
{
  int i,j;

  for(i=0;i<15;i++)
    for(j=0;j<128;j++)
      keys[i][j]=0;
}

void clear_stat()                /* Sets both statistics to (0) */
{
  int i;
  for(i=0;i<256;i++)
    statistic[i]=0;
  for(i=0;i<1000;i++)
    stat2[i]=0;
}

void clear_inversion()           /* Sets the inversion-matrix to (0) */
{
  int i,j;

  for(i=0;i<15;i++)
    for(j=0;j<128;j++)
      inversion[i][j]=0;
}

void benes_perms()        /* sets the net-permutations Q to a benes net */
{
  int i,j;

  for(j=0;j<256;j++){
    perms[0][j]=(j/256)*256+(j%2)*128+(j%256)/2; 
    perms[1][j]=(j/128)*128+(j%2)* 64+(j%128)/2; 
    perms[2][j]=(j/ 64)* 64+(j%2)* 32+(j% 64)/2; 
    perms[3][j]=(j/ 32)* 32+(j%2)* 16+(j% 32)/2; 
    perms[4][j]=(j/ 16)* 16+(j%2)*  8+(j% 16)/2; 
    perms[5][j]=(j/  8)*  8+(j%2)*  4+(j%  8)/2;
    perms[6][j]=(j/  4)*  4+(j%2)*  2+(j%  4)/2;
  };
  for(i=7;i<14;i++)
    for(j=0;j<256;j++)
      perms[i][perms[13-i][j]]=j;
        
  for(j=0;j<256;j++)
    perms[14][j]=j;
}

void benes_equiv_perms() 
                      /* sets the net-permutations Q to a benes-equivalent net */
                      /* every row of switching elements is shifted cyclic     */
{
  int i,j;

  for(j=0;j<256;j++){
    perms[0][j]           =((j/256)*256+(j%2)*128+(j%256)/2+ 10)%256;
    perms[1][(j+ 10)%256] =((j/128)*128+(j%2)* 64+(j%128)/2+180)%256;
    perms[2][(j+180)%256] =((j/ 64)* 64+(j%2)* 32+(j% 64)/2+ 70)%256;
    perms[3][(j+ 70)%256] =((j/ 32)* 32+(j%2)* 16+(j% 32)/2+120)%256;
    perms[4][(j+120)%256] =((j/ 16)* 16+(j%2)*  8+(j% 16)/2+ 60)%256;
    perms[5][(j+ 60)%256] =((j/  8)*  8+(j%2)*  4+(j%  8)/2+210)%256;
    perms[6][(j+210)%256] =((j/  4)*  4+(j%2)*  2+(j%  4)/2+110)%256;
  };
  for(i=7;i<14;i++)
    for(j=0;j<256;j++)
      perms[i][perms[13-i][j]]=j;
        
  for(j=0;j<256;j++)
    perms[14][j]=j;
}


void xinit()
{
  XGCValues gcvalue;
  XSizeHints* sizehints;

  if(! (display=XOpenDisplay(""))){
    printf("Sorry, could'nt open display\n");
    exit(1);
  };

  root = DefaultRootWindow(display);

  /* init window for displaying the key and inversion matrix*/
  ik_atts.event_mask        = ExposureMask|ButtonPressMask;
  ik_atts.background_pixel  = WhitePixel(display, DefaultScreen(display));
  ik_atts.backing_store     = Always;
  ik_window = XCreateWindow(display, root, 300, 0, 250, 680, 2, 0, 
			   InputOutput, CopyFromParent,
			   CWEventMask |  CWBackPixel | CWBackingStore, 
			   &ik_atts);
  XStoreName(display, ik_window, "key and inversion matrix");
  XMapWindow(display, ik_window);


  /* init button window */
  buttons_atts.event_mask        = ExposureMask|ButtonPressMask;
  buttons_atts.background_pixel  = WhitePixel(display, DefaultScreen(display));
  buttons_atts.backing_store     = Always;
  buttons_window = XCreateWindow(display, root, 0, 0, 113, 443, 2, 0,
				 InputOutput, CopyFromParent,
				 CWEventMask |  CWBackPixel | CWBackingStore, 
				 &buttons_atts);
  XStoreName(display,buttons_window,"menu");
  XMapWindow(display, buttons_window);

  /* Set the graphical context */
  gcvalue.function          = GXcopy;
  gcvalue.plane_mask        = AllPlanes;
  gcvalue.background        = WhitePixel(display,DefaultScreen(display));
  gcvalue.foreground        = BlackPixel(display,DefaultScreen(display));
  gcvalue.line_width        = 1;
  gcvalue.line_style        = LineSolid;
  gcvalue.fill_style        = FillSolid;
  gc_draw = XCreateGC(display, ik_window,
			 GCFunction|GCPlaneMask|GCForeground|GCBackground|
			 GCLineWidth|GCFillStyle|GCLineStyle, &gcvalue);
  gc_buttons_draw = XCreateGC(display, buttons_window,
			      GCFunction|GCPlaneMask|GCForeground|GCBackground|
			      GCLineWidth|GCFillStyle|GCLineStyle, &gcvalue);
  gcvalue.foreground        = WhitePixel(display,DefaultScreen(display));
  gc_erase = XCreateGC(display, ik_window,
			  GCFunction|GCPlaneMask|GCForeground|GCBackground|
			  GCLineWidth|GCFillStyle|GCLineStyle, &gcvalue);
  gc_buttons_erase = XCreateGC(display, buttons_window,
			       GCFunction|GCPlaneMask|GCForeground|GCBackground|
			       GCLineWidth|GCFillStyle|GCLineStyle, &gcvalue);

  XFlush(display);
}

void draw_key_pixel(int row,int column)
{
  if( (row<0) || (row>127) || (column<1) || (column>15) ) return;

  XFillRectangle(display,ik_window,gc_draw,xkm+1+5*(column-1),ykm+1+5*row,4,4);
  XFlush(display);
}

void erase_key_pixel(int row,int column)
{
  if( (row<0) || (row>127) || (column<1) || (column>15) ) return;

  XFillRectangle(display,ik_window,gc_erase,xkm+1+5*(column-1),ykm+1+5*row,4,4);
  XFlush(display);
}

void draw_inversion_pixel(int row,int column)
{
  if( (row<0) || (row>127) || (column<1) || (column>15) ) return;

  XFillRectangle(display,ik_window,gc_draw,xim+1+5*(column-1),yim+1+5*row,4,4);
  XFlush(display);
}

void erase_inversion_pixel(int row,int column)
{
  if( (row<0) || (row>127) || (column<1) || (column>15) ) return;
  XFillRectangle(display,ik_window,gc_erase,xim+1+5*(column-1),yim+1+5*row,4,4);
  XFlush(display);
}

void flip_key_pixel(int row,int column)
{
  if( (row<0) || (row>127) || (column<1) || (column>15) ) return;
  if(keys[column-1][row]){
    keys[column-1][row]=0;
    XFillRectangle(display,ik_window,gc_erase,xkm+1+5*(column-1),ykm+1+5*row,4,4);
  } else {
    keys[column-1][row]=1;
    XFillRectangle(display,ik_window,gc_draw,xkm+1+5*(column-1),ykm+1+5*row,4,4);
  };
  XFlush(display);
}

void draw_keys_matrix()
{
  int x,y;

  for(x=0;x<15;x++)
    for(y=0;y<128;y++)
      if(keys[x][y])
	draw_key_pixel(y,x+1);
      else
	erase_key_pixel(y,x+1);
  XFlush(display);
}

void draw_inversion_matrix()
{
  int x,y;

  for(x=0;x<15;x++)
    for(y=0;y<128;y++)
      if(inversion[x][y])
	draw_inversion_pixel(y,x+1);
      else
	erase_inversion_pixel(y,x+1);
  XFlush(display);
}

void draw_matrices()
{
  int x,y;

  XDrawRectangle(display,ik_window,gc_draw,xkm-1,ykm-1,77,642);
  XDrawRectangle(display,ik_window,gc_draw,xim-1,yim-1,77,642);

  for(x=0; x<=75; x+=5){
    XDrawLine(display,ik_window,gc_draw,x+xkm,ykm,x+xkm,ykm+640);
    XDrawLine(display,ik_window,gc_draw,x+xim,yim,x+xim,yim+640);
  }
  for(y=0;y<=640; y+=5){
    XDrawLine(display,ik_window,gc_draw,xkm,y+ykm,xkm+76,y+ykm);
    XDrawLine(display,ik_window,gc_draw,xim,y+yim,xim+76,y+yim);
  }

  XDrawString(display,ik_window,gc_draw,xkm+31,ykm+652,"key",3);
  XDrawString(display,ik_window,gc_draw,xim+11,yim+652,"inversion",9);

  for(y=0;y<=640;y+=32*5){
    XDrawLine(display,ik_window,gc_draw,xkm-1,ykm-1+y,xkm-13,ykm-1+y);
    XDrawLine(display,ik_window,gc_draw,xkm-1,ykm+y,xkm-13,ykm+y);
    XDrawLine(display,ik_window,gc_draw,xkm-1,ykm+1+y,xkm-13,ykm+1+y);

    XDrawLine(display,ik_window,gc_draw,xim+77,yim-1+y,xim+88,yim-1+y);
    XDrawLine(display,ik_window,gc_draw,xim+77,yim+y,xim+88,yim+y);
    XDrawLine(display,ik_window,gc_draw,xim+77,yim+1+y,xim+88,yim+1+y);
  }

  for(y=0;y<=640;y+=16*5){
    XDrawLine(display,ik_window,gc_draw,xkm-1,ykm+y,xkm-13,ykm+y);
    XDrawLine(display,ik_window,gc_draw,xim+77,yim+y,xim+88,yim+y);
  }

  for(y=0;y<=640;y+=8*5){
    XDrawLine(display,ik_window,gc_draw,xkm-1,ykm+y,xkm-10,ykm+y);
    XDrawLine(display,ik_window,gc_draw,xim+77,yim+y,xim+85,yim+y);
  }

  for(y=0;y<=640;y+=4*5){
    XDrawLine(display,ik_window,gc_draw,xkm-1,ykm+y,xkm-7,ykm+y);
    XDrawLine(display,ik_window,gc_draw,xim+77,yim+y,xim+82,yim+y);
  }

  draw_keys_matrix();
  draw_inversion_matrix();

  XFlush(display);
}

void process_quit()
{
  exit(0);
}

void process_clear()
{
  clear_stat();
  clear_keys();
  clear_inversion();
  XClearWindow(display,ik_window);
  draw_matrices();
}

void inversion_0()           /* simple path modifikation  */
{
  int i;
  
  clear_inversion();
  for(i=0;i<15;i++)
    inversion[i][path[i]]=1; 
}
 
void inversion_1()           /* diagonal path modifikation  */ 
{
  int i,s;
  
  clear_inversion();
  for(i=0;i<15;i++)
    for(s=0;s<15;s++)
      {
	inversion[s][path[i]]=1;
	inversion[s][(path[i]+i-s+128)%128]=1; 
	inversion[s][(path[i]-i+s+128)%128]=1; 
      } 
}
 
void inversion_2()           /* invert leftright-neighbours of path */ 
{
  int i;
  
  clear_inversion();

  for(i=0;i<15;i++)
      {
	inversion[(i+14)%15][path[i]]=1;	
	inversion[(i+1)%15][path[i]]=1;
      }  
}

void inversion_3()           /* inverty all (eight) path-neighbours  */ 
{
  int i,s,z;
  
  clear_inversion();

    for(i=0;i<15;i++)
      for(s=0;s<3;s++)
	for(z=0;z<3;z++) 
	    inversion[(i+14+s)%15][(path[i]+127+z)%128]=1;	
}

void inversion_4()          /* Matrix inversion as in  game of life  */ 
                            /* makes no sense in kryptology          */ 
{
  int i,j,sum;
  
  for(i=0;i<15;i++) 
    for(j=0;j<128;j++)
      {
	sum = keys[(i+14)%15][(j+127)%128] + keys[(i+14)%15][(j)%128] 
            + keys[(i+14)%15][(j+1)%128]   + keys[(i)][(j+127)%128] 
            + keys[(i)%15][(j+1)%128     ] + keys[(i+1)%15][(j+127)%128]
            + keys[(i+1)%15][(j)%128]      + keys[(i+1)%15][(j+1)%128] ;
	if(sum==2)
	  inversion[i][j]=0;
	else
	  if(sum==3)
	    inversion[i][j]=1-keys[i][j];
	  else
	    inversion[i][j]=keys[i][j];;
      }
  for(i=0;i<15;i++)
    inversion[i][path[i]]=1- inversion[i][path[i]]; 
}

void inversion_5()          /*  Modified game of life  */ 
{
  int i,j,sum;
  
  for(i=0;i<15;i++) 
    for(j=0;j<128;j++)
      {
	sum = keys[(i+14)%15][(j+127)%128] + keys[(i+14)%15][(j)%128] 
            + keys[(i+14)%15][(j+1)%128]   + keys[(i)][(j+127)%128] 
            + keys[(i)%15][(j+1)%128     ] + keys[(i+1)%15][(j+127)%128]
            + keys[(i+1)%15][(j)%128]      + keys[(i+1)%15][(j+1)%128] ;
	switch(sum)
	  {
	  case 0: inversion[i][j]=1; break;
	  case 1: inversion[i][j]=0; break;
	  case 2: inversion[i][j]=1; break;
	  case 3: inversion[i][j]=keys[i][j]; break;
	  case 4: inversion[i][j]=1-keys[i][j]; break;
	  case 5: inversion[i][j]=keys[i][j]; break;
	  case 6: inversion[i][j]=0; break;
	  case 7: inversion[i][j]=1; break;
	  case 8: inversion[i][j]=0; break;
	  }
      }
}

void inversion_6()    /* simple path modifikation with cyclic row-shift  */
{
  int i,j;
  
  clear_inversion();
  for(i=0;i<15;i++)
    inversion[i][path[i]]=1; 
  for(i=0;i<15;i++)
    for(j=0;j<128;j++)
      inversion[i][j] = (inversion[i][j] + keys[i][j] + keys[i][(j+127)%128]) %2 ;
}

void modify_keys()    /* adds inversion matrix to key matrix */
{
  int i,j;
  (*inversion_functions[inv])(); 
  
  for(i=0;i<15;i++)
    for(j=0;j<128;j++)
      keys[i][j]=(keys[i][j]+inversion[i][j])%2; 
  if(m==1)
    {
      draw_keys_matrix();
      draw_inversion_matrix();
    }
}

void draw_buttons()   /* Draws buttons in  menu-window */
{ char buf[10];

  XClearWindow(display,buttons_window);
  
  XDrawRectangle(display,buttons_window,gc_buttons_draw,5,5,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,14,27,"Manual",6);
  XDrawString(display,buttons_window,gc_buttons_draw,17,42,"Input",5);

  XDrawRectangle(display,buttons_window,gc_buttons_draw,60,5,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,69,27,"Random",6);
  XDrawString(display,buttons_window,gc_buttons_draw,72,42,"Input",5);

  if(randommode) 
    {XDrawRectangle(display,buttons_window,gc_buttons_draw,62,7,46,46);}
  else 
    {XDrawRectangle(display,buttons_window,gc_buttons_draw,7,7,46,46);}
  
  XDrawRectangle(display,buttons_window,gc_buttons_draw,5,60,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,20,82,"Save",4);
  XDrawString(display,buttons_window,gc_buttons_draw,23,97,"Key",3);

  XDrawRectangle(display,buttons_window,gc_buttons_draw,60,60,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,75,82,"Save",4);
  XDrawString(display,buttons_window,gc_buttons_draw,65,97,"Invert.",7);

  XDrawRectangle(display,buttons_window,gc_buttons_draw,5,115,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,20,145,"Step",4);

  XDrawRectangle(display,buttons_window,gc_buttons_draw,60,115,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,75,137,"Step",4);
  XDrawString(display,buttons_window,gc_buttons_draw,84,152,"8",1);

  XDrawRectangle(display,buttons_window,gc_buttons_draw,5,170,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,20,192,"Step",4);
  XDrawString(display,buttons_window,gc_buttons_draw,26,207,"64",2);

  XDrawRectangle(display,buttons_window,gc_buttons_draw,60,170,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,75,192,"Step",4);
  XDrawString(display,buttons_window,gc_buttons_draw,75,207,"8192",4);

  XDrawRectangle(display,buttons_window,gc_buttons_draw,5,225,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,20,247,"Save",4);
  XDrawString(display,buttons_window,gc_buttons_draw,17,262,"Stat.",5);

  XDrawRectangle(display,buttons_window,gc_buttons_draw,60,225,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,72,247,"Clear",5);
  XDrawString(display,buttons_window,gc_buttons_draw,72,262,"Stat.",5);

  XDrawRectangle(display,buttons_window,gc_buttons_draw,5,280,50,50);
  XDrawRectangle(display,buttons_window,gc_buttons_draw,7,282,46,46);
  XDrawString(display,buttons_window,gc_buttons_draw,23,302,"Net",3);
  sprintf(buf,"Nr.%.1d",net);
  XDrawString(display,buttons_window,gc_buttons_draw,20,317,buf,strlen(buf));
 
  XDrawRectangle(display,buttons_window,gc_buttons_draw,60,280,50,50);
  XDrawRectangle(display,buttons_window,gc_buttons_draw,62,282,46,46);
  XDrawString(display,buttons_window,gc_buttons_draw,65,302,"Invert.",7);
  sprintf(buf,"Nr.%.1d",inv);
  XDrawString(display,buttons_window,gc_buttons_draw,75,317,buf,strlen(buf));

  XDrawRectangle(display,buttons_window,gc_buttons_draw,5,335,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,20,357,"Show",4);
  XDrawString(display,buttons_window,gc_buttons_draw,17,372,"Matr.",5);

  if(m==1) 
    {XDrawRectangle(display,buttons_window,gc_buttons_draw,7,337,46,46);}

  XDrawRectangle(display,buttons_window,gc_buttons_draw,5,390,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,17,422,"Clear",5);

  XDrawRectangle(display,buttons_window,gc_buttons_draw,60,390,50,50);
  XDrawString(display,buttons_window,gc_buttons_draw,75,422,"Quit",4);

  XFlush(display);
}

static int encrypt(int plaintext);

void process_step()
{
  int plaintext, ciphertext;
  if(randommode){
    plaintext=random()&0xff;
  printf("Plaintext : %d\n",plaintext);
  } else
    do {
      printf("Plaintext : ");
      scanf("%d",&plaintext);
    } while ( (plaintext<0) || (plaintext>255) );
  ciphertext=encrypt(plaintext);
  modify_keys();
  printf("Ciphertext: %d\n",ciphertext);
}

void process_step1()
{
  XDrawRectangle(display,buttons_window,gc_buttons_draw,7,117,46,46);
  XFlush(display);
  process_step();
}

void process_step8()
{
  int i;
  XDrawRectangle(display,buttons_window,gc_buttons_draw,62,117,46,46);
  for(i=0;i<8;i++){
    if(XCheckWindowEvent(display,ik_window,ButtonPressMask,&xevent))
      break;
    process_step();
  }
}

void process_step64()
{
  int i;
  XDrawRectangle(display,buttons_window,gc_buttons_draw,7,172,46,46);
  for(i=0;i<64;i++){
    if(XCheckWindowEvent(display,ik_window,ButtonPressMask,&xevent))
      break;
    process_step();
  }
}

void process_step8192()
{
  int i;
  XDrawRectangle(display,buttons_window,gc_buttons_draw,62,172,46,46);
  for(i=0;i<8192;i++){
    if(XCheckWindowEvent(display,ik_window,ButtonPressMask,&xevent))
      break;
    process_step();
  }
}

void process_save_k()      /* saves all black pixels (i,j) of key matrix */
                           /* for LaTex-picture environment              */
                           /* format: \put(i,127-j){\rule{1.5mm}{1.5mm}} */
                           /* not very efficently !!!                    */
{
  int i,j; 
  FILE *fopen(),*fp;
  XDrawRectangle(display,buttons_window,gc_buttons_draw,7,62,46,46);
  XFlush(display);
  fp = fopen("matrix","w");
  fprintf(fp," This is a keymatrix of invertion %d, with net %d  \n",inv,net);
  for(i=0;i<15;i++)
    for(j=0;j<128;j++)
      if(keys[i][j])
	{  
	  fprintf(fp,"\\put(%d,%d){\\rule{1.5mm}{1.5mm}}\n",i,127-j);
	}
  fclose(fp); 
}

void process_save_i()       /* saves all black pixels of inversion matrix */
{
  int i,j;
  FILE *fopen(),*fp;
  XDrawRectangle(display,buttons_window,gc_buttons_draw,62,62,46,46);
  XFlush(display);
  fp = fopen("matrix","w");
  fprintf(fp," This is a inversionmatrix of inv %d, with net %d  \n",inv,net);
  for(i=0;i<15;i++)
    for(j=0;j<128;j++)
      if(inversion[i][j])
	{  
	  fprintf(fp,"\\put(%d,%d){\\rule{1.5mm}{1.5mm}}\n",i,127-j);
	}
  fclose(fp);
}

void process_save_stat()       /* saves the statistic in Latex-tabular c column */
{
  int i,j,c;
  FILE *fopen(),*fp;
  XDrawRectangle(display,buttons_window,gc_buttons_draw,7,227,46,46);
  XFlush(display);
  fp = fopen("statistic","w");
  fprintf(fp,"%% This is a statistic of the output with inversion %d  \n",inv);
  c=8;
  for(i=0;i<(256/c);i++)
    { 
      for(j=0;j<c;j++) 
	{
	  fprintf(fp,"%d & %d ",i+256/c*j,statistic[i+256/c*j]);
	  if(j<7)  
	    fprintf(fp," &");
	}
      fprintf(fp,"\\\\\n");
    }
  for(i=0;i<1000;i++)
    stat2[i]==0;
  for(i=0;i<256;i++)
    if(statistic[i]<1000)  
      stat2[statistic[i]]++;
  for(i=0;i<1000;i++)
    fprintf(fp,"%% %d :  %d \n",i,stat2[i]);
  fclose(fp);
}

void process_choose_n()    /* select benes-net or benes-equiv. net */
{
  net=1-net;
   if(net)
     {
       benes_equiv_perms();
     }
   else
     { 
       benes_perms();
     }
}

void process_choose_i()    /* select inversion-function */
{
  inv=(inv+1)%7;
}

void process_display_m()    /* m=1 z display matrices */
{
  m=1-m;
  if(m==1)
    {
      draw_keys_matrix();
      draw_inversion_matrix();   
    }
}

void process_manual()
{ randommode=0; }

void process_random()
{ randommode=1; } 

void process_clear_stat()
{ clear_stat(); }

void process_void()
{}
   
                           /* menu */   
static void (*dispatch_table[2][8])()={
  { process_manual, process_save_k,   process_step1,  process_step64, 
      process_save_stat, process_choose_n, process_display_m,   process_clear},
  { process_random, process_save_i,   process_step8,  process_step8192,
      process_clear_stat, process_choose_i, process_void,   process_quit}};
     
int encrypt(int p)
{
  int i;
  for(i=0; i<15; i++){
    path[i]=p/2;
    if(keys[i][p/2]){
      p=perms[i][2*(p/2)+(1-p%2)];
    } else {
      p=perms[i][p];
    }
  };
  statistic[p]++;
  return p;
}
  
void flip_key_row(int row)
{
  int x;
  for(x=1;x<16;x++)
    flip_key_pixel(row,x);
}

void flip_key_column(int column)
{
  int y;
  for(y=0;y<128;y++)
    flip_key_pixel(y,column);
}

void dispatcher()
{
  int x,y;

  XNextEvent(display, &xevent);
  if( xevent.xbutton.window==buttons_window) {
    if(xevent.type == Expose) {
      draw_buttons();
    } else if(xevent.type == ButtonPress) {
      if((xevent.xbutton.x-5)%55 > 50 ||
	 (xevent.xbutton.y-5)%55 > 50) return;
      x=(xevent.xbutton.x-5)/55;
      y=(xevent.xbutton.y-5)/55; 
      if( (x<0) || (x>1) || (y<0) || (y>7) ) return;
      (*dispatch_table[x][y])();
      draw_buttons();
    }
  } else {
    if(xevent.type == ButtonPress) {
      x=(xevent.xbutton.x-xkm)/5+1;
      y=(xevent.xbutton.y-ykm)/5;
      if(xevent.xbutton.button == 1)
	flip_key_pixel(y,x);
      else if(xevent.xbutton.button == 2)
	flip_key_row(y);
      else if(xevent.xbutton.button == 3)
	flip_key_column(x);
    } else if(xevent.type == Expose) {
      draw_matrices();
    }
  }
}     
  
main()
{
  xinit();
  process_clear();
  process_choose_n();
  draw_buttons();
  while(1)
    dispatcher();
}









