/******************************************************************************
 * Copyright 2010 Sony Corporation
 *
 * clefia_test.c
 *
 * "The 128-bit Blockcipher CLEFIA"
 * Test Vector Generator
 *
 * Version  1.0.0 (January 29 2010)
 *
 *****************************************************************************/

#include "clefia_ref.h"

#include <stdio.h>
#include <string.h>

void BytePut(const unsigned char *data, int bytelen)
{
  while(bytelen-- > 0){
    printf("%02x", *data++);
  }
  printf("\n");
}

void ClefiaSample(const int key_bitlen)
{
  const unsigned char pt[16] = {
    0x00U,0x01U,0x02U,0x03U,0x04U,0x05U,0x06U,0x07U,
    0x08U,0x09U,0x0aU,0x0bU,0x0cU,0x0dU,0x0eU,0x0fU
  };
  const unsigned char skey[32] = {
    0xffU,0xeeU,0xddU,0xccU,0xbbU,0xaaU,0x99U,0x88U,
    0x77U,0x66U,0x55U,0x44U,0x33U,0x22U,0x11U,0x00U,
    0xf0U,0xe0U,0xd0U,0xc0U,0xb0U,0xa0U,0x90U,0x80U,
    0x70U,0x60U,0x50U,0x40U,0x30U,0x20U,0x10U,0x00U
  };
  unsigned char ct[CLEFIA_BLK_SIZE];
  unsigned char recovered[CLEFIA_BLK_SIZE];
  unsigned char rk[CLEFIA_RK_MAX];
  int r;

  /* CLEFIA ECB mode */
  printf("\n--- ClefiaSample(): CLEFIA-%d\n", key_bitlen);
  printf("pt            = "); BytePut(pt, sizeof pt);
  printf("key (%d-bit) = ", key_bitlen); BytePut(skey, key_bitlen / 8);
  if(0 == (r = ClefiaKeySet(rk, skey, key_bitlen))){
    printf("invalid key_bitlen");
    return ;
  }
  ClefiaEncrypt(ct, pt, rk, r);
  printf("ct            = "); BytePut(ct, sizeof pt);

  ClefiaDecrypt(recovered, ct, rk, r);
  if(memcmp(pt, recovered, sizeof pt)) printf("test failed");
}

void ClefiaOfbSample(const int key_bitlen)
{
  unsigned char pt[CLEFIA_BLK_SIZE];
  unsigned char ct[CLEFIA_BLK_SIZE];
  unsigned char skey[32];
  unsigned char rk[CLEFIA_RK_MAX];
  int r;
  int i, j;

  printf("\n--- ClefiaOfbSample(): CLEFIA-%d\n\n", key_bitlen);
  printf("ct[i] = E(ct[i-1]), ct[0] = E(IV), IV = 0x00...0\n");
  memset(pt, 0, sizeof pt);
  memset(ct, 0, sizeof ct);
  memset(skey, 0, sizeof skey);

  for(i = 0; i < 10; i++){
    memcpy(skey, pt, 16);
    memcpy(skey + 16, ct, 16);
    memset(ct, 0, sizeof ct);
    printf("\n--- CLEFIA-%d,     key%d = ", key_bitlen, i); BytePut(skey, key_bitlen / 8);
    printf("                      IV = "); BytePut(ct, sizeof ct);

    if(0 == (r = ClefiaKeySet(rk, skey, key_bitlen))){
      printf("invalid key_bitlen");
      return ;
    }
    for(j = 0; j < 128; j++){
      memcpy(pt, ct, sizeof pt);
      ClefiaEncrypt(ct, pt, rk, r);
      printf("CLEFIA-%d, key%d ct[%03d] = ", key_bitlen, i, j); BytePut(ct, sizeof ct);
    }
  }
}

void ClefiaVarTxtKAT(int key_bitlen)
{
  const unsigned char skey[] = {
    0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,
    0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,
    0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,
    0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U
  };
  unsigned char rk[CLEFIA_RK_MAX];
  unsigned char pt[CLEFIA_BLK_SIZE];
  unsigned char ct[CLEFIA_BLK_SIZE];
  int r;
  int i, j;
  
  printf("\n--- CLEFIA-%d VarTxtKAT\n", key_bitlen);
  printf("key = 0x00..0, pt[0] = 0x80..0, pt[1] = 0xc0..0, ...\n");
  memset(pt, 0U, sizeof pt);
  if(0 == (r = ClefiaKeySet(rk, skey, key_bitlen))){
    printf("invalid key_bitlen");
    return ;
  }
  for(i = 0; i < CLEFIA_BLK_SIZE; i++){
    for(j = 0; j < 8; j++){
      pt[i] |= (0x80U >> j);
      ClefiaEncrypt(ct, pt, rk, r);
      printf("[%3d] : ", i * 8 + j); BytePut(ct, sizeof ct);
    }
  }
}

void ClefiaVarKeyKAT(int key_bitlen)
{
  const unsigned char pt[] = {
    0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,
    0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U
  };
  unsigned char rk[CLEFIA_RK_MAX];
  unsigned char skey[256 / 8];
  unsigned char ct[CLEFIA_BLK_SIZE];
  int r;
  int i, j;
  
  printf("\n--- CLEFIA-%d VarKeyKAT\n", key_bitlen);
  printf("pt = 0x00..0, key[0] = 0x80..0, key[1] = 0xc0..0, ...\n");
  memset(skey, 0U, sizeof skey);
  for(i = 0; i < key_bitlen / 8; i++){
    for(j = 0; j < 8; j++){
      skey[i] |= (0x80U >> j);
      if(0 == (r = ClefiaKeySet(rk, skey, key_bitlen))){
	printf("invalid key_bitlen");
	return ;
      }
      ClefiaEncrypt(ct, pt, rk, r);
      printf("[%3d] : ", i * 8 + j); BytePut(ct, sizeof ct);
    }
  }
}

#define MCT_ITERATE_OUT 400
#define MCT_ITERATE_IN 10000

/* encflg != 0: encryption
 * encflg == 0: decryption */
void ClefiaEcbMct(const int key_bitlen, const int encflg)
{
  unsigned char key[256 / 8];
  unsigned char txt[CLEFIA_BLK_SIZE * 2];
  unsigned char rk[CLEFIA_RK_MAX];
  int r;
  int i, j;

  memset(key, 0U, sizeof key);
  memset(txt, 0U, sizeof txt);
  
  printf("\n--- CLEFIA-%d ECB-%s-MCT", key_bitlen, encflg ? "enc" : "dec");

  for(i = 0; i < MCT_ITERATE_OUT; i++){
    for(j = 0; j < key_bitlen / 8; j++){
      key[j] ^= txt[((256 - key_bitlen) / 8) + j];
    }
    printf("[%3d] : \n", i);
    printf("key = "); BytePut(key, key_bitlen / 8);
    printf("%s  = ", encflg ? "pt" : "ct");
    BytePut(txt + CLEFIA_BLK_SIZE, CLEFIA_BLK_SIZE);

    if(0 == (r = ClefiaKeySet(rk, key, key_bitlen))){
      printf("invalid key_bitlen");
      return ;
    }

    for(j = 0; j < MCT_ITERATE_IN; j++){
      memcpy(txt, txt + CLEFIA_BLK_SIZE, CLEFIA_BLK_SIZE);
      if(encflg){
	ClefiaEncrypt(txt + CLEFIA_BLK_SIZE, txt, rk, r);
      }else{
	ClefiaDecrypt(txt + CLEFIA_BLK_SIZE, txt, rk, r);
      }
    }
    printf("%s  = ", encflg ? "ct" : "pt");
    BytePut(txt + CLEFIA_BLK_SIZE, CLEFIA_BLK_SIZE);
  }
}

/* encflg != 0: encryption
 * encflg == 0: decryption */
void ClefiaCbcMct(const int key_bitlen, const int encflg)
{
  unsigned char key[256 / 8];
  unsigned char txt[CLEFIA_BLK_SIZE * 2];
  unsigned char iv[CLEFIA_BLK_SIZE];
  unsigned char rk[CLEFIA_RK_MAX];
  int r;
  int i, j, k;

  memset(key, 0U, sizeof key);
  memset(txt, 0U, sizeof txt);
  memset(iv, 0U, sizeof iv);
  
  printf("\n--- CLEFIA-%d CBC-%s-MCT", key_bitlen, encflg ? "enc" : "dec");

  for(i = 0; i < MCT_ITERATE_OUT; i++){
    for(j = 0; j < key_bitlen / 8; j++){
      key[j] ^= txt[((256 - key_bitlen) / 8) + j];
    }
    printf("[%3d] : \n", i);
    printf("key = "); BytePut(key, key_bitlen / 8);
    printf("iv  = "); BytePut(iv, CLEFIA_BLK_SIZE);
    if(encflg){
      printf("pt  = "); BytePut(txt, CLEFIA_BLK_SIZE);
    }else{
      printf("ct  = "); BytePut(txt + CLEFIA_BLK_SIZE, CLEFIA_BLK_SIZE);
    }

    if(0 == (r = ClefiaKeySet(rk, key, key_bitlen))){
      printf("invalid key_bitlen");
      return ;
    }

    for(j = 0; j < MCT_ITERATE_IN; j++){
      if(encflg){
	for(k = 0; k < CLEFIA_BLK_SIZE; k++){
	  txt[k] ^= iv[k];
	}
	ClefiaEncrypt(txt + CLEFIA_BLK_SIZE, txt, rk, r);
	memcpy(txt, iv, CLEFIA_BLK_SIZE);
	memcpy(iv, txt + CLEFIA_BLK_SIZE, CLEFIA_BLK_SIZE);
      }else{
	memcpy(txt, txt + CLEFIA_BLK_SIZE, CLEFIA_BLK_SIZE);
	ClefiaDecrypt(txt + CLEFIA_BLK_SIZE, txt, rk, r);
	for(k = 0; k < CLEFIA_BLK_SIZE; k++){
	  txt[k + CLEFIA_BLK_SIZE] ^= iv[k];
	}
	memcpy(iv, txt, CLEFIA_BLK_SIZE);
      }
    }
    printf("%s  = ", encflg ? "ct" : "pt");
    BytePut(txt + CLEFIA_BLK_SIZE, CLEFIA_BLK_SIZE);
  }
}


int main(void)
{
  ClefiaSample(128);
  ClefiaSample(192);
  ClefiaSample(256);

  ClefiaOfbSample(128);
  ClefiaOfbSample(192);
  ClefiaOfbSample(256);

  ClefiaVarTxtKAT(128);
  ClefiaVarTxtKAT(192);
  ClefiaVarTxtKAT(256);

  ClefiaVarKeyKAT(128);
  ClefiaVarKeyKAT(192);
  ClefiaVarKeyKAT(256);

  ClefiaEcbMct(128, 1);
  ClefiaEcbMct(128, 0);
  ClefiaEcbMct(192, 1);
  ClefiaEcbMct(192, 0);
  ClefiaEcbMct(256, 1);
  ClefiaEcbMct(256, 0);

  ClefiaCbcMct(128, 1);
  ClefiaCbcMct(128, 0);
  ClefiaCbcMct(192, 1);
  ClefiaCbcMct(192, 0);
  ClefiaCbcMct(256, 1);
  ClefiaCbcMct(256, 0);

  return 0;
}



/* end of file */

