#include "mir1.h"


/* ------------------------------------------------------------------------- */
/* Functions Implementation */
/* ------------------------------------------------------------------------- */
void ECRYPT_init()
{
}


/* ------------------------------------------------------------------------- */
void ECRYPT_keysetup(
           ECRYPT_ctx* ctx, 
           const u8* key, 
           u32 keysize,                /* Key size in bits. */ 
           u32 ivsize)                 /* IV size in bits. */ 
{ ECRYPT_ctx &p = *ctx;
  int i,j;
  for(i=0; i<256; ++i)
    for(p.S[i]=i, j=0; j<16; ++j)
      p.S[i]=SR[p.S[i]^key[j]];
  p.a.v  = p.x1.v = ((ull*)key)[0];
  p.b.v  = p.x3.v = ((ull*)key)[1];
  p.x0.v = C0;
  p.x2.v = C1;
  for(i=0; i<8; ++i) { Mir1_STATE_UPDATE }
}


/* ------------------------------------------------------------------------- */
void ECRYPT_ivsetup(
           ECRYPT_ctx* ctx, 
           const u8* IV)
{ ECRYPT_ctx &p = *ctx;
  p.x0.b.b4 ^= p.S[IV[0]] ^ p.S[IV[1]] ^ p.S[IV[2]];
  p.x1.b.b4 ^= p.S[IV[0]] ^ p.S[IV[3]] ^ p.S[IV[4]];
  p.x2.b.b4 ^= p.S[IV[2]] ^ p.S[IV[5]] ^ p.S[IV[7]];
  p.x3.b.b4 ^= p.S[IV[3]] ^ p.S[IV[6]] ^ p.S[IV[7]];
  p.x0.b.b0 ^= p.S[IV[3]] ^ p.S[IV[5]];
  p.x1.b.b0 ^= p.S[IV[7]] ^ p.S[IV[6]];
  p.x2.b.b0 ^= p.S[IV[0]] ^ p.S[IV[1]];
  p.x3.b.b0 ^= p.S[IV[2]] ^ p.S[IV[4]];
  p.a.b.b0  ^= p.S[IV[0]] ^ p.S[IV[5]] ^ p.S[IV[6]];
  p.a.b.b4  ^= p.S[IV[1]] ^ p.S[IV[3]] ^ p.S[IV[5]];
  p.b.b.b0  ^= p.S[IV[1]] ^ p.S[IV[4]] ^ p.S[IV[7]];
  p.b.b.b4  ^= p.S[IV[2]] ^ p.S[IV[4]] ^ p.S[IV[6]];
  { Mir1_STATE_UPDATE }
  { Mir1_STATE_UPDATE }
}


/* ------------------------------------------------------------------------- */
// NOTE: msglen MUST BE divisible by 8
void ECRYPT_encrypt_bytes(
           ECRYPT_ctx* ctx, 
           const u8* plaintext, 
           u8* ciphertext, 
           u32 msglen)                /* Message length in bytes. */ 
{ ECRYPT_ctx &p = *ctx;
  int i, k=msglen>>3; /* divide by 8 */
  
  for(i=0; i<k; ++i)
    { Mir1_STATE_UPDATE
      ((ull*)ciphertext)[i] = ((ull*)plaintext)[i] ^ p.b.v; 
    }
}


/* ------------------------------------------------------------------------- */
void ECRYPT_decrypt_bytes(
           ECRYPT_ctx* ctx, 
           const u8* ciphertext, 
           u8* plaintext, 
           u32 msglen)                /* Message length in bytes. */ 

{ ECRYPT_ctx &p = *ctx;
  int i, k=msglen>>3; /* divide by 8 */
  
  for(i=0; i<k; ++i)
    { Mir1_STATE_UPDATE
      ((ull*)plaintext)[i] = ((ull*)ciphertext)[i] ^ p.b.v; 
    }
}

/* ------------------------------------------------------------------------- */
void ECRYPT_keystream_bytes(
           ECRYPT_ctx* ctx,
           u8* keystream,
           u32 length)                /* Length of keystream in bytes. */
{ ECRYPT_ctx &p = *ctx;
  int i, k=length>>3;  /* divide by 8 */

  for(i=0; i<k; ++i)
    { Mir1_STATE_UPDATE
      ((ull*)keystream)[i] = p.b.v; 
    }
}

/* ------------------------------------------------------------------------- */

