/* The IRAQI BLOCK CIPHER BSF-1.052.36*/
/* Iraqi cipher standard 1998 */
/* 160-bit keys, 256-bit block */

#include <stdio.h>

    unsigned char one_way_res[16];
    unsigned char rnd_perm[256][16],rnd_glob[256],ciphertext[32];
    int compt,i,y;
    unsigned char l[32][16],r[32][16];

  unsigned char chaos[256];

  unsigned char chaos1[256]={
173,84,240,67,1,53,254,36,41,172,115,109,223,199,152,189,90,46,
149,193,218,130,250,40,203,4,35,237,236,246,213,143,169,176,48,
23,61,206,69,34,97,155,4,109,183,220,42,64,21,123,29,233,253,
105,183,209,1,191,113,12,46,7,8,183,166,199,166,7,78,37,135,
252,174,84,140,164,152,94,22,185,59,68,181,60,176,67,51,25,28,
190,138,198,44,90,92,221,149,175,186,25,49,210,50,237,41,207,
31,226,114,121,230,15,58,25,142,58,98,232,59,3,189,28,8,116,
131,185,78,250,239,33,116,173,94,45,104,62,122,179,18,150,246,
250,17,8,79,157,225,238,47,10,133,58,8,126,82,68,153,141,2,158,
204,50,130,53,59,32,243,160,172,35,24,107,35,115,228,143,28,
224,77,55,25,28,120,89,186,152,49,84,117,180,30,138,134,77,182,
157,61,230,22,149,54,15,110,32,213,155,106,78,16,23,89,140,158,
169,96,136,186,104,30,199,67,35,218,159,210,109,28,238,33,150,
173,180,247,201,83,150,105,164,228,59,207,101,221,99,52,120,
199,31,6,144,202,215,209,49,42,195};

init_pbc1(unsigned char key[20])
{
  int w,err,ix,x;

  unsigned char fixed_key[32]={
  46,245,138,13,244,233,238,154,139,30,241,90,47,205,171,97,223,
  190,28,10,185,13,23,137,30,208,254,143,165,101,27,48};


  for (compt=0;compt<256;compt++)
  {
     chaos[compt]=chaos1[compt]^key[compt%20];
  }

 for (w=0;w<4;w++)
{

  round_init(fixed_key,32);

  for (compt=0;compt<256;compt++)
  {
     chaos[compt]=chaos[compt]^ciphertext[compt%32];
  }
  for (compt=0;compt<32;compt++)
  {

   fixed_key[compt]=ciphertext[compt];
  }

}

for (compt=0;compt<16;compt++)
{
    err=0;
    for (ix=0;ix<16;ix++)
    {
      round_init(ciphertext,4);

      for (x=0;x<ix;x++)
      {
	if (rnd_perm[compt][x] == (ciphertext[7]%16) )
	{
	  x=ix;
	  err=1;
	  round_init(ciphertext,4);
	}
      }
      if (err==0)
      {
	rnd_perm[compt][ix]=ciphertext[7]%16;
      }
      else
      {
	err=0;
	ix=ix-1;
      }

    }
}

    err=0;
    for (ix=0;ix<256;ix++)
    {
      round_init(ciphertext,4);

      for (x=0;x<ix;x++)
      {
	if (rnd_glob[x] == ( ciphertext[7]%256) )
	{
	  x=ix;
	  err=1;
	  round_init(ciphertext,4);
	}
      }
      if (err==0)
      {
	rnd_glob[ix]=ciphertext[7]%256;
      }
      else
      {
	err=0;
	ix=ix-1;
      }

    }
  for (compt=0;compt<256;compt++)
  {
     chaos[compt]=chaos[compt]^key[compt%20];
  }


 for (w=0;w<4;w++)
{

  round_init(fixed_key,32);

  for (compt=0;compt<256;compt++)
  {
     chaos[compt]=chaos[compt]^ciphertext[compt%32];
  }
  for (compt=0;compt<32;compt++)
  {

   fixed_key[compt]=ciphertext[compt];
  }

}

}

round_init(unsigned char plaintext[32],int nbround)
{

  for (i=0;i<16;i++)
  {
    l[0][i]=plaintext[i];
    r[0][i]=plaintext[i+16];
  }

  for (i=1;i<nbround;i++)
  {
     one_way_init(r[i-1]);

     for (y=0;y<16;y++)
     {
      l[i][y]=r[i-1][y];
      r[i][y]=l[i-1][y] ^ one_way_res[y];
     }
  }

  for (i=0;i<16;i++)
  {
    ciphertext[i]=l[nbround-1][i];
    ciphertext[i+16]=r[nbround-1][i];
  }

}


round(unsigned char plaintext[32],int nbround)
{

  for (i=0;i<16;i++)
  {
    l[0][i]=plaintext[i];
    r[0][i]=plaintext[i+16];
  }

  for (i=1;i<nbround;i++)
  {
     one_way(r[i-1]);
     for (y=0;y<16;y++)
     {
      l[i][y]=r[i-1][y];
      r[i][y]=l[i-1][y] ^ one_way_res[y];
     }
  }
  printf("\n");

  for (i=0;i<16;i++)
  {
    ciphertext[i+16]=l[nbround-1][i];
    ciphertext[i]=r[nbround-1][i];
  }

}


one_way_init(unsigned char matrix[16])
{
    int z;
    unsigned char permut[16][16]={

    {5,10,1,3,0,4,15,2,7,9,13,8,11,14,12,6},
    {5,7,15,13,3,8,1,11,10,0,9,12,2,6,14,4},
    {4,6,12,14,1,0,13,5,7,9,10,11,2,15,8,3},
    {3,4,2,12,13,9,1,8,5,15,14,6,10,0,11,7},
    {9,8,3,5,4,6,0,2,13,15,14,1,12,11,7,10},
    {14,13,3,11,0,2,1,10,7,9,4,5,15,6,12,8},
    {8,4,0,5,7,3,12,11,13,9,6,1,15,10,2,14},
    {11,14,13,1,9,8,4,5,12,6,7,3,10,0,15,2},
    {13,12,2,1,6,9,14,11,3,10,8,15,4,5,7,0},
    {1,14,12,7,8,0,11,9,6,5,4,2,10,3,15,13},
    {6,0,10,8,5,2,11,13,14,1,4,9,3,12,15,7},
    {12,0,5,13,2,4,8,6,3,15,9,10,14,7,1,11},
    {7,10,8,11,9,2,0,3,5,4,12,15,14,1,6,13},
    {8,4,15,7,10,9,3,12,6,14,0,2,1,5,13,11},
    {11,13,14,3,5,12,7,6,2,0,10,8,1,15,4,9},
    {1,6,3,8,7,4,11,14,0,10,9,2,15,12,5,13}};


    for (z=0;z<16;z++)
    {

    one_way_res[z]=( ( chaos[matrix[permut[z][0]]] | chaos[matrix[permut[z][1]]])+
    ( chaos[matrix[permut[z][2]]] | chaos[matrix[permut[z][3]]]) ) ^ ( (chaos[matrix[permut[z][4]]] +
    chaos[matrix[permut[z][5]]] )+( chaos[matrix[permut[z][6]]] ^ chaos[matrix[permut[z][7]]]) );

    one_way_res[z]=one_way_res[z] + ( ( (~chaos[matrix[permut[z][8]]] ^ chaos[matrix[permut[z][9]]]) +
    (chaos[matrix[permut[z][10]]] & ~chaos[matrix[permut[z][11]]]) ) ^ ( (chaos[matrix[permut[z][12]]] ^
     ~chaos[matrix[permut[z][13]]]) + (chaos[matrix[permut[z][14]]] ^ chaos[matrix[permut[z][15]]]) ) );

    }

}

one_way(unsigned char matrix[16])
{
    int z;

    for (z=0;z<16;z++)
    {

    one_way_res[z]=( ( chaos[matrix[rnd_perm[z][0]]] | chaos[matrix[rnd_perm[z][1]]])+
    ( chaos[matrix[rnd_perm[z][2]]] | chaos[matrix[rnd_perm[z][3]]]) ) ^ ( (chaos[matrix[rnd_perm[z][4]]] +
    chaos[matrix[rnd_perm[z][5]]] )+( chaos[matrix[rnd_perm[z][6]]] ^ chaos[matrix[rnd_perm[z][7]]]) );

    one_way_res[z]=one_way_res[z] + ( ( (~chaos[matrix[rnd_perm[z][8]]] ^ chaos[matrix[rnd_perm[z][9]]]) +
    (chaos[matrix[rnd_perm[z][10]]] & ~chaos[matrix[rnd_perm[z][11]]]) ) ^ ( (chaos[matrix[rnd_perm[z][12]]] ^
     ~chaos[matrix[rnd_perm[z][13]]]) + (chaos[matrix[rnd_perm[z][14]]] ^ chaos[matrix[rnd_perm[z][15]]]) ) );

     one_way_res[z]=one_way_res[z]+rnd_glob[one_way_res[z]]+rnd_glob[z];
    }


}


main()
{
  int tt;

  unsigned char key[20]={0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0};

  unsigned char text[32]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0};

  printf("Plaintext :");
  for (tt=0;tt<32;tt++)
  {
   printf("%X ",text[tt]);
  }


  /* ENCRYPT */
  init_pbc1(key);

  round(text,6); /* 5 rounds */

  printf("Ciphertext :");
  for (tt=0;tt<32;tt++)
  {
   printf("%X ",ciphertext[tt]);
   text[tt]=ciphertext[tt];
  }

  /* DECRYPT */

  init_pbc1(key);

  round(text,6); /* 5 rounds */

  printf("Plaintext :");
  for (tt=0;tt<32;tt++)
  {
   printf("%X ",ciphertext[tt]);
  }

  printf("\n\n");


}

/*
key :      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Plaintext :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Ciphertext :B 58 52 F 6A 3C 1E 63 70 46 16 73 57 BC 68 CD BF 7C E0 8F 15 54 3A E5 59 96 55 54 83 43 E 86

key :      1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Plaintext :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Ciphertext :D9 48 EE 9C 33 94 7A A3 F F0 1E F9 CB E2 32 50 BA 43 E1 18 47 D3 24 89 4A 63 14 E5 D B6 9E 2B

key :      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Plaintext :1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Ciphertext :4 CF B 24 E9 A8 3A AD C1 53 6A 7C 46 E1 3D CD 8C A8 9B 3D 10 B9 DC A1 D3 F 44 A6 D5 1F 93 83

key :      1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Plaintext :1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Ciphertext :4E 43 60 1B 4F 57 D2 CA DA BB 9D E0 F5 61 3 D3 55 6B C5 DD C4 8F 48 65 16 A1 3A 15 B1 B8 19 58
*/