#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <inttypes.h>
#include "fealclient.h"

#define MAXENCRYPT 25 /* Maximale Anzahl von Verschluesselungen */
#define SAMPLES 25

#define DEBUG_STATUS 
//#define DEBUG_VERBOSE 
#define DEBUG_DOUBLECHECK

//helpful macros:
#define Rot2(x) Rot2Results[(x)]         //rotate byte by 2, implemented using lookup table
#define S0(a, b) Rot2((a + b) & 255)     //S0 function, as defined in skript
#define S1(a, b) Rot2((a + b + 1) & 255) //S1 function, as defined in skript
#define BIT(a, b) (((a) >> (b)) & 1)     //return bit #b of a
//#define BIT(a, b) ()
ByteType Rot2Results[256];

struct MSG
{
  ByteType block[8];
};

struct halfMSG
{
  ByteType block[4];
};

void MSGToBinary(struct MSG message)
{
  for (int i = 8; i > 0; i--)
  {
    for (int j = 8; j > 0; j--)
    {
      if (j == 4)
        printf(" ");
      printf("%i", BIT(message.block[i - 1], j - 1));
    }
    printf("\t");
  }
  printf("\n");
}

void MSGToString(struct MSG message)
{
  printf("%02x%02x %02x%02x %02x%02x %02x%02x",
         message.block[7],
         message.block[6],
         message.block[5],
         message.block[4],
         message.block[3],
         message.block[2],
         message.block[1],
         message.block[0]);
}

void halfMSGToString(struct halfMSG message)
{
  printf("%02x%02x %02x%02x",
         message.block[3],
         message.block[2],
         message.block[1],
         message.block[0]);
}

struct MSG plaintexts[SAMPLES];
struct MSG ciphertexts[SAMPLES];
struct MSG partlyDecrypted[SAMPLES];
struct MSG partlyEncrypted[SAMPLES];

unsigned char carrayk0[1 << 16] = {0};
unsigned char carrayk3[1 << 16] = {0};
unsigned char carrayk1[1 << 16] = {0};
unsigned char carrayk2[1 << 16] = {0};

short numCandidatesK0 = 0;
short numCandidatesK3 = 0;
short numCandidatesK1 = 0;
short numCandidatesK2 = 0;

void initRot2(void)
{
  int i;
  for (i = 0; i < 256; i++)
  {
    Rot2Results[i] = (ByteType)(i << 2 | ((i >> 6) & 3));
  }
}

/* Rundenfunktion des FEAL. x ist die Eingabe, k ist der Rundenschluessel,
 * y ist die Ausgabe. (y und x darf dasselbe Array sein)
 */
void F(ByteType x[4], ByteType k[2], ByteType y[4])
{
  ByteType a, b, c, d;
  a = x[0];
  b = x[0] ^ x[1];
  c = x[2] ^ x[3];
  d = x[3];
  b ^= k[0];
  c ^= k[1];
  b = S1(b, c);
  c = S0(b, c);
  a = S0(a, b);
  d = S1(c, d);
  y[0] = a;
  y[1] = b;
  y[2] = c;
  y[3] = d;
}

void u_int16_2ByteType(uint16_t Q, ByteType *B)
/*
     Disassemble a quarterword into two Bytes.
*/
{
  union {
    uint16_t All;
    ByteType Byte[2];
  } QQ;

  QQ.All = Q;
  *B++ = QQ.Byte[0];
  *B = QQ.Byte[1];
}

uint16_t RoundKeyToShort(ByteType *RoundKey)
{
  union {
    uint16_t asShort;
    ByteType Bytes[2];
  } toShort;

  toShort.Bytes[0] = *RoundKey++;
  toShort.Bytes[1] = *RoundKey;
  return toShort.asShort;
}

void swap(struct MSG *msg)
{
  ByteType t;
  t = msg->block[0];
  msg->block[0] = msg->block[4];
  msg->block[4] = t;
  t = msg->block[1];
  msg->block[1] = msg->block[5];
  msg->block[5] = t;
  t = msg->block[2];
  msg->block[2] = msg->block[6];
  msg->block[6] = t;
  t = msg->block[3];
  msg->block[3] = msg->block[7];
  msg->block[7] = t;
}

/* in key[i][2] soll der i-te Rundenschluessel stehen.
 * in der Aufgabe sind key[4] bis key[11] immer 0!!!
 * Dies wird im Rahmenprogramm automatisch gesetzt.
 */
ByteType key[12][2];
ByteType key_real[12][2];
ByteType key_ges[4];

/* Die Funktion attacke soll sich gewaehlte plaintext/ciphertext-Paare
 * vom Daemonen holen (mit der Funktion feal_encrypt()).
 * Dann soll sie die 4 Rundenschluessel berechnen und in
 * key[i] (i von 0 bis 3) speichern.
 */

//===================================================================================
//F0[2]: mL[0, 2, 8] mR[0] R3[2, 8] L3[0]
//F0[10]: mL[0, 8, 10, 16, 24] mR[0, 8, 16, 24] L3[0, 8, 16, 24] R3[10] K2[0, 8] K0[0, 8]
//F0[18]: mL[8, 16, 18, 24] mR[16, 24] R3[8, 18] L3[16, 24] K0[8] K2[8]
//F0[26]: mL[16, 24, 26] mR[24] R3[16, 26] L3[24]
//===================================================================================

int f2(struct MSG plaintext, struct MSG partlyDecrypted)
{
  return (BIT(plaintext.block[4], 0) ^       //mR[0]
          BIT(plaintext.block[0], 0) ^       //mL[0]
          BIT(plaintext.block[0], 2) ^       //mL[2]
          BIT(plaintext.block[1], 0) ^       //mL[8]
          BIT(partlyDecrypted.block[0], 0) ^ //L3[0]
          BIT(partlyDecrypted.block[4], 2) ^ //R3[2]
          BIT(partlyDecrypted.block[5], 0)   //R3[8]
  );
}

int f10(struct MSG plaintext, struct MSG partlyDecrypted)
{
  return (BIT(plaintext.block[4], 0) ^       //mR[0]
          BIT(plaintext.block[5], 0) ^       //mR[8]
          BIT(plaintext.block[6], 0) ^       //mR[16]
          BIT(plaintext.block[7], 0) ^       //mR[24]
          BIT(plaintext.block[0], 0) ^       //mL[0]
          BIT(plaintext.block[1], 0) ^       //mL[8]
          BIT(plaintext.block[1], 2) ^       //mL[10]
          BIT(plaintext.block[2], 0) ^       //mL[16]
          BIT(plaintext.block[3], 0) ^       //mL[24]
          BIT(partlyDecrypted.block[0], 0) ^ //L3[0]
          BIT(partlyDecrypted.block[1], 0) ^ //L3[8]
          BIT(partlyDecrypted.block[2], 0) ^ //L3[16]
          BIT(partlyDecrypted.block[3], 0) ^ //L3[24]
          BIT(partlyDecrypted.block[5], 2)   //R3[10]
  );
}

int f18 (struct MSG plaintext, struct MSG partlyDecrypted)
{
  return (
  BIT (plaintext.block[1], 0) ^ //mL[8]
  BIT (plaintext.block[2], 0) ^ //mL[16]
  BIT (plaintext.block[2], 2) ^ //mL[18]
  BIT (plaintext.block[3], 0) ^ //mL[24]
  BIT (plaintext.block[6], 0) ^ //mR[16]
  BIT (plaintext.block[7], 0) ^ //mR[24]
  BIT (partlyDecrypted.block[5], 0) ^  //R3[8]
  BIT (partlyDecrypted.block[6], 2) ^  //R3[18]
  BIT (partlyDecrypted.block[2], 0) ^  //L3[16]
  BIT (partlyDecrypted.block[3], 0)    //L3[24]
  );
}

int f26(struct MSG plaintext, struct MSG partlyDecrypted)
{
  return (BIT(plaintext.block[7], 0) ^       //mR[24]
          BIT(plaintext.block[2], 0) ^       //mL[16]
          BIT(plaintext.block[3], 0) ^       //mL[24]
          BIT(plaintext.block[3], 2) ^       //mL[26]
          BIT(partlyDecrypted.block[3], 0) ^ //L3[24]
          BIT(partlyDecrypted.block[6], 0) ^ //R3[16]
          BIT(partlyDecrypted.block[7], 2)   //R3[26]
  );
}

int Eq1(ByteType plaintext, ByteType Round3)
{
  union {
    ByteType bytes;
    uint32_t ints;
  } toInt;

  toInt.bytes = plaintext;      //byte 0
  int mR0 = BIT(toInt.ints, 0); //bit 0

  toInt.bytes = plaintext + 4;  //byte 4
  int mL0 = BIT(toInt.ints, 0); //bit 0

  toInt.bytes = plaintext + 4;  //byte 4
  int mL2 = BIT(toInt.ints, 2); //bit 2

  toInt.bytes = plaintext + 5;  //byte 5
  int mL8 = BIT(toInt.ints, 0); //bit 0

  toInt.bytes = Round3;        //byte 0
  int R2 = BIT(toInt.ints, 2); //bit 0

  toInt.bytes = Round3 + 1;    //byte 1
  int R8 = BIT(toInt.ints, 0); //bit 0

  toInt.bytes = Round3 + 4;    //byte 4
  int L0 = BIT(toInt.ints, 0); //bit 0

  printf("bits are mR0 %i, mL0 %i, mL2%i, mL8 %i, R2 %i, R8 %i, L0 %i\n",
         mR0, mL0, mL2, mL8, R2, R8, L0);

  return mR0 ^ mL0 ^ mL2 ^ mL8 ^ R2 ^ R8 ^ L0;
}


void attackK3(void){
  //attack K3

  struct MSG currentMsg;

  int parityf10 = 0;
  int parityf18 = 0;

  for (int j = 0; j < (1 << 16); j++) //from 0 to 2^16
  {

    for (int i = 0; i < SAMPLES; i++)
    {
      currentMsg.block[0] = ciphertexts[i].block[0];
      currentMsg.block[1] = ciphertexts[i].block[1];
      currentMsg.block[2] = ciphertexts[i].block[2];
      currentMsg.block[3] = ciphertexts[i].block[3];
      currentMsg.block[4] = ciphertexts[i].block[4] ^ ciphertexts[i].block[0];
      currentMsg.block[5] = ciphertexts[i].block[5] ^ ciphertexts[i].block[1];
      currentMsg.block[6] = ciphertexts[i].block[6] ^ ciphertexts[i].block[2];
      currentMsg.block[7] = ciphertexts[i].block[7] ^ ciphertexts[i].block[3];

      DecryptRound(&currentMsg.block[0], &partlyDecrypted[i].block[0], j);

      if (i == 0){
        parityf10 = f10(plaintexts[i], partlyDecrypted[i]);
        parityf18 = f18(plaintexts[i], partlyDecrypted[i]);
      }
      else
      {
        if ((f10(plaintexts[i], partlyDecrypted[i]) != parityf10) || (f18(plaintexts[i], partlyDecrypted[i]) != parityf18))
        {
          carrayk3[j] = 0;
          break;
        }
      }

      if (f2(plaintexts[i], partlyDecrypted[i]) || f26(plaintexts[i], partlyDecrypted[i]))
      {
        carrayk3[j] = 0;
        break;
      }


      #ifdef DEBUG_VERBOSE
        printf("Pair %i:\nplaintext\t\t", i);
        MSGToString(plaintexts[i]);
        printf("\n");

        printf("ciphertext\t\t");
        MSGToString(ciphertexts[i]);
        printf("\n");

        printf("partlyDecrypted\t\t");
        MSGToString(partlyDecrypted[i]);  
        printf("\n");
      #endif
      }
    }

  for (int i = 0; i < 1 << 16; i++)
  {
    if (carrayk3[i])
    {
      printf("%02x\n", i);
      numCandidatesK3++;
      u_int16_2ByteType(i, key[3]);
    }
  }
  printf("num candidates for K3: %i\n", numCandidatesK3);
}


void attackK0(void){
  //attack K0

  struct MSG currentMsg;

  int parityf10 = 0;
  int parityf18 = 0;

  for (int j = 0; j < (1 << 16); j++) //from 0 to 2^16
  {

    for (int i = 0; i < SAMPLES; i++)
    {
      currentMsg.block[0] = plaintexts[i].block[0];
      currentMsg.block[1] = plaintexts[i].block[1];
      currentMsg.block[2] = plaintexts[i].block[2];
      currentMsg.block[3] = plaintexts[i].block[3];
      currentMsg.block[4] = plaintexts[i].block[4] ^ plaintexts[i].block[0];
      currentMsg.block[5] = plaintexts[i].block[5] ^ plaintexts[i].block[1];
      currentMsg.block[6] = plaintexts[i].block[6] ^ plaintexts[i].block[2];
      currentMsg.block[7] = plaintexts[i].block[7] ^ plaintexts[i].block[3];

      DecryptRound(&currentMsg.block[0], &partlyEncrypted[i].block[0], j);

      if (i == 0){
        parityf10 = f10(ciphertexts[i], partlyEncrypted[i]);
        parityf18 = f18(ciphertexts[i], partlyEncrypted[i]);
      }
      else
      {
        if ((f10(ciphertexts[i], partlyEncrypted[i]) != parityf10) || (f18(ciphertexts[i], partlyEncrypted[i]) != parityf18))
        {
          carrayk0[j] = 0;
          break;
        }
      }

      if (f2(ciphertexts[i], partlyEncrypted[i]) || f26(ciphertexts[i], partlyEncrypted[i]))
      {
        carrayk0[j] = 0;
        break;
      }

 
         #ifdef DEBUG_VERBOSE
        printf("Pair %i:\nplaintext\t\t", i);
        MSGToString(plaintexts[i]);
        printf("\n");

        printf("ciphertext\t\t");
        MSGToString(ciphertexts[i]);
        printf("\n");

        printf("partlyDecrypted\t\t");
        MSGToString(partlyDecrypted[i]);  
        printf("\n");
      #endif
      }
    }
  for (int i = 0; i < 1 << 16; i++)
  {
    if (carrayk0[i])
    {
      printf("%02x\n", i);
      numCandidatesK0++;
      u_int16_2ByteType(i, key[0]);
    }
  }
  printf("num candidates for K0: %i\n", numCandidatesK0);
}



void attackK1(void){
  //attack K1

  struct MSG currentMsg;

  //int parityf10 = 0;
  //int parityf18 = 0;

  for (int j = 0; j < (1 << 16); j++) //from 0 to 2^16
  {

    for (int i = 0; i < SAMPLES; i++)
    {
      currentMsg.block[0] = plaintexts[i].block[0];
      currentMsg.block[1] = plaintexts[i].block[1];
      currentMsg.block[2] = plaintexts[i].block[2];
      currentMsg.block[3] = plaintexts[i].block[3];
      currentMsg.block[4] = plaintexts[i].block[4] ^ plaintexts[i].block[0];
      currentMsg.block[5] = plaintexts[i].block[5] ^ plaintexts[i].block[1];
      currentMsg.block[6] = plaintexts[i].block[6] ^ plaintexts[i].block[2];
      currentMsg.block[7] = plaintexts[i].block[7] ^ plaintexts[i].block[3];

      DecryptRound(&currentMsg.block[0], &partlyEncrypted[i].block[0], RoundKeyToShort(&key[0][0]));
      swap(&partlyEncrypted[i]);
      currentMsg.block[0] = ciphertexts[i].block[0];
      currentMsg.block[1] = ciphertexts[i].block[1];
      currentMsg.block[2] = ciphertexts[i].block[2];
      currentMsg.block[3] = ciphertexts[i].block[3];
      currentMsg.block[4] = ciphertexts[i].block[4] ^ ciphertexts[i].block[0];
      currentMsg.block[5] = ciphertexts[i].block[5] ^ ciphertexts[i].block[1];
      currentMsg.block[6] = ciphertexts[i].block[6] ^ ciphertexts[i].block[2];
      currentMsg.block[7] = ciphertexts[i].block[7] ^ ciphertexts[i].block[3];

      DecryptRound(&currentMsg.block[0], &partlyDecrypted[i].block[0], RoundKeyToShort(&key[3][0]));
      swap(&partlyDecrypted[i]);
      
      DecryptRound(&partlyEncrypted[i].block[0], &currentMsg.block[0], j);
      swap(&currentMsg);
      if( !(
        (currentMsg.block[4] == partlyDecrypted[i].block[4]) &&
        (currentMsg.block[5] == partlyDecrypted[i].block[5]) &&
        (currentMsg.block[6] == partlyDecrypted[i].block[6]) &&
        (currentMsg.block[7] == partlyDecrypted[i].block[7])
        ))
      {
          carrayk1[j] = 0;
          continue;
        }
      //}

      #ifdef DEBUG_VERBOSE
        printf("Pair %i:\nplaintext\t\t", i);
        MSGToString(plaintexts[i]);
        printf("\n");

        printf("ciphertext\t\t");
        MSGToString(ciphertexts[i]);
        printf("\n");

        printf("partlyDecrypted\t\t");
        MSGToString(partlyDecrypted[i]);  
        printf("\n");
      #endif
      }
    }
  for (int i = 0; i < 1 << 16; i++)
  {
    if (carrayk1[i])
    {
      printf("%02x\n", i);
      numCandidatesK1++;
      u_int16_2ByteType(i, key[1]);
    }
  }
  printf("num candidates for K1: %i\n", numCandidatesK1);
}




void attackK2(void){
  //attack K2

  struct MSG currentMsg;

  //int parityf10 = 0;
  //int parityf18 = 0;

  for (int j = 0; j < (1 << 16); j++) //from 0 to 2^16
  {

    for (int i = 0; i < SAMPLES; i++)
    {
      currentMsg.block[0] = plaintexts[i].block[0];
      currentMsg.block[1] = plaintexts[i].block[1];
      currentMsg.block[2] = plaintexts[i].block[2];
      currentMsg.block[3] = plaintexts[i].block[3];
      currentMsg.block[4] = plaintexts[i].block[4] ^ plaintexts[i].block[0];
      currentMsg.block[5] = plaintexts[i].block[5] ^ plaintexts[i].block[1];
      currentMsg.block[6] = plaintexts[i].block[6] ^ plaintexts[i].block[2];
      currentMsg.block[7] = plaintexts[i].block[7] ^ plaintexts[i].block[3];

      DecryptRound(&currentMsg.block[0], &partlyEncrypted[i].block[0], RoundKeyToShort(&key[0][0]));
      swap(&partlyEncrypted[i]);
      currentMsg.block[0] = ciphertexts[i].block[0];
      currentMsg.block[1] = ciphertexts[i].block[1];
      currentMsg.block[2] = ciphertexts[i].block[2];
      currentMsg.block[3] = ciphertexts[i].block[3];
      currentMsg.block[4] = ciphertexts[i].block[4] ^ ciphertexts[i].block[0];
      currentMsg.block[5] = ciphertexts[i].block[5] ^ ciphertexts[i].block[1];
      currentMsg.block[6] = ciphertexts[i].block[6] ^ ciphertexts[i].block[2];
      currentMsg.block[7] = ciphertexts[i].block[7] ^ ciphertexts[i].block[3];

      DecryptRound(&currentMsg.block[0], &partlyDecrypted[i].block[0], RoundKeyToShort(&key[3][0]));
      swap(&partlyDecrypted[i]);
      
      DecryptRound(&partlyDecrypted[i].block[0], &currentMsg.block[0], j);
      swap(&currentMsg);
      if( !(
        (currentMsg.block[4] == partlyEncrypted[i].block[4]) &&
        (currentMsg.block[5] == partlyEncrypted[i].block[5]) &&
        (currentMsg.block[6] == partlyEncrypted[i].block[6]) &&
        (currentMsg.block[7] == partlyEncrypted[i].block[7])
        ))
      {
          carrayk2[j] = 0;
          continue;
        }
      //}

      #ifdef DEBUG_VERBOSE
        printf("Pair %i:\nplaintext\t\t", i);
        MSGToString(plaintexts[i]);
        printf("\n");

        printf("ciphertext\t\t");
        MSGToString(ciphertexts[i]);
        printf("\n");

        printf("partlyDecrypted\t\t");
        MSGToString(partlyDecrypted[i]);  
        printf("\n");
      #endif
      }
    }
  for (int i = 0; i < 1 << 16; i++)
  {
    if (carrayk2[i])
    {
      printf("%02x\n", i);
      numCandidatesK2++;
      u_int16_2ByteType(i, key[2]);
    }
  }
  printf("num candidates for K2: %i\n", numCandidatesK2);
}



void attacke(void)
{
  /* Aufgabe */
  for (int i = 0; i < 1 << 16; i++)
  { //init potential candidates
    carrayk0[i] = 255;
    carrayk3[i] = 255;
    carrayk1[i] = 255;
    carrayk2[i] = 255;
  }

  srand(time(NULL));
  for (int i = 0; i < SAMPLES; i++)
  {

    for (int j = 0; j < 8; j++) //generate random plaintexts
    {
      plaintexts[i].block[j] = rand() % 256;
    }
    feal_encrypt(&plaintexts[i].block[0], &ciphertexts[i].block[0]); //encrypt them by the demon
  }

  attackK3();
  attackK0();

  if (numCandidatesK0 != 1){
    system("./attack");
    exit(1);
  }
  if (numCandidatesK3 != 1){
    system("./attack");
    exit(1);
  }

  attackK1();
    if (numCandidatesK1 != 1){
    system("./attack");
    exit(1);
  }
  attackK2();
    if (numCandidatesK2 != 1){
    system("./attack");
    exit(1);
  }
  return;
  printf("Starting brute force attack against K1 and K2...\n");
  struct MSG temp;

  for (int key1_it = 0; key1_it < (1<<16); key1_it++){
    printf("checked %f%% of possible key combinations...\r", ((double)key1_it / (double)(1<<16)) * (double)100);
    for (int key2_it = 0; key2_it < (1<<16); key2_it ++){
      u_int16_2ByteType(key1_it, key[1]);
      u_int16_2ByteType(key2_it, key[2]);
      SetKey(&key[0][0]);
      Encrypt(&plaintexts[0].block[0], &temp.block[0]);
      if (temp.block[0] == ciphertexts[0].block[0] &&
          temp.block[1] == ciphertexts[0].block[1] &&
          temp.block[2] == ciphertexts[0].block[2] &&
          temp.block[3] == ciphertexts[0].block[3] &&
          temp.block[4] == ciphertexts[0].block[4] &&
          temp.block[5] == ciphertexts[0].block[5] &&
          temp.block[6] == ciphertexts[0].block[6] && 
          temp.block[7] == ciphertexts[0].block[7]){
        printf("\n");
        return;
      }
    }
  }


  
}

int main(void)
{
  int t; /* temporaere Variable */

  initRot2();
  feal_connect();
  if ((t = feal_new_key()) < 0)
  {
    fprintf(stderr, "Fehler in feal_new_key: %d\n", t);
    exit(1);
  }
  attacke();
  memset(key[4], 0, 8 * 2);
  memset(key_real, 0, 12 * 2);
  t = feal_check_sub(key, key_real, key_ges);
  if (t > 0)
  {
    printf("Der Schluessel war richtig: %02x%02x %02x%02x %02x%02x %02x%02x\n",
           key[0][0], key[0][1], key[1][0], key[1][1], key[2][0], key[2][1],
           key[3][0], key[3][1]);
    printf("Der Gesamtschluessel, aus dem diese Rundenschluessel entstanden,\n");
    printf("war: %02x%02x%02x%02x%02x%02x%02x%02x\n", key_ges[0], key_ges[1],
           key_ges[2], key_ges[3], key_ges[4], key_ges[5], key_ges[6], key_ges[7]);
  }
  else if (t < 0)
  {
    fprintf(stderr, "Fehler in feal_check_sub: %d\n", t);
    exit(1);
  }
  else
  {
    printf("Der Schluessel war falsch.\n\n");
    printf("Berechneter Schluessel:    %02x%02x %02x%02x %02x%02x %02x%02x\n",
           key[3][1], key[3][0], key[2][1], key[2][0], key[1][1], key[1][0],
           key[0][1], key[0][0]);
    printf("Tatsaechlicher Schluessel: %02x%02x %02x%02x %02x%02x %02x%02x\n",
           key_real[3][1], key_real[3][0], key_real[2][1], key_real[2][0],
           key_real[1][1], key_real[1][0], key_real[0][1], key_real[0][0]);
    printf("Der Gesamtschluessel, aus dem diese Rundenschluessel entstanden,\n");
    printf("war: %02x%02x%02x%02x%02x%02x%02x%02x\n", key_ges[0], key_ges[1],
           key_ges[2], key_ges[3], key_ges[4], key_ges[5], key_ges[6], key_ges[7]);
  }

#ifdef DEBUG_DOUBLECHECK
  SetKey(&key_real[0][0]);

  struct MSG r3;
  struct MSG r2;
  struct MSG r1;
  struct MSG r0;

  struct MSG testmessage;

  /*for (int i = 0; i < SAMPLES; i++)
  {*/
  //printf("Pair %i:\n", i);

  printf("plaintext\t\t");
  MSGToString(plaintexts[0]);
  printf("\n");

  printf("plaintext encrypted\t");
  Encrypt(&plaintexts[0].block[0], &testmessage.block[0]);
  MSGToString(testmessage);
  printf("\n");

  printf("ciphertext\t\t");
  MSGToString(ciphertexts[0]);
  printf("\n");

  printf("ciphertext decrypted\t");
  Decrypt(&ciphertexts[0].block[0], &testmessage.block[0]);
  MSGToString(testmessage);
  printf("\n");

  plaintexts[0].block[4] ^= plaintexts[0].block[0];
  plaintexts[0].block[5] ^= plaintexts[0].block[1];
  plaintexts[0].block[6] ^= plaintexts[0].block[2];
  plaintexts[0].block[7] ^= plaintexts[0].block[3];

  printf("round 0 encrypted\t");
  uint16_t roundkey = RoundKeyToShort(&key_real[0][0]);
  DecryptRound(&plaintexts[0].block[0], &r3.block[0], roundkey);
  MSGToString(r3);
  printf("\n");

  swap(&r3);

  /*
  printf("partly: ");
  MSGToString(partlyDecrypted[roundkey]);
  printf("\n");
*/
  printf("round 1 encrypted\t");
  roundkey = RoundKeyToShort(&key_real[1][0]);
  DecryptRound(&r3.block[0], &r2.block[0], roundkey);
  MSGToString(r2);
  printf("\n");

  swap(&r2);

  printf("round 2 encrypted\t");
  roundkey = RoundKeyToShort(&key_real[2][0]);
  DecryptRound(&r2.block[0], &r1.block[0], roundkey);
  MSGToString(r1);
  printf("\n");

  swap(&r1);

  printf("round 3 decrypted\t");
  roundkey = RoundKeyToShort(&key_real[3][0]);
  DecryptRound(&r1.block[0], &r0.block[0], roundkey);

  r0.block[4] ^= r0.block[0];
  r0.block[5] ^= r0.block[1];
  r0.block[6] ^= r0.block[2];
  r0.block[7] ^= r0.block[3];

  MSGToString(r0);
  printf("\n");

  printf("\n");
  ciphertexts[0].block[4] ^= ciphertexts[0].block[0];
  ciphertexts[0].block[5] ^= ciphertexts[0].block[1];
  ciphertexts[0].block[6] ^= ciphertexts[0].block[2];
  ciphertexts[0].block[7] ^= ciphertexts[0].block[3];


  printf("round 3 decrypted\t");
  DecryptRound(&ciphertexts[0].block[0], &r3.block[0], roundkey);
  MSGToString(r3);
  printf("\n");

  swap(&r3);

  printf("round 2 decrypted\t");
  roundkey = RoundKeyToShort(&key_real[2][0]);
  DecryptRound(&r3.block[0], &r2.block[0], roundkey);
  MSGToString(r2);
  printf("\n");

  swap(&r2);

  printf("round 1 decrypted\t");
  roundkey = RoundKeyToShort(&key_real[1][0]);
  DecryptRound(&r2.block[0], &r1.block[0], roundkey);
  MSGToString(r1);
  printf("\n");

  swap(&r1);

  printf("round 0 decrypted\t");
  roundkey = RoundKeyToShort(&key_real[0][0]);
  DecryptRound(&r1.block[0], &r0.block[0], roundkey);

  r0.block[4] ^= r0.block[0];
  r0.block[5] ^= r0.block[1];
  r0.block[6] ^= r0.block[2];
  r0.block[7] ^= r0.block[3];

  MSGToString(r0);
  printf("\n");
  //printf("result of parity equation 1 (should be 0): %i\n", Eq1(plaintexts[i].block[0], testmessage.block[0]));

  printf("\n");
  //}
#endif

  exit(0);
}
