text: /*
  * Noekeon
  * (C) 1999-2008 Jack Lloyd
  *
  * Distributed under the terms of the Botan license
  */
  
  #include <botan/noekeon.h>
  #include <botan/loadstor.h>
  #include <botan/rotate.h>
  
  namespace Botan {
  
  namespace {
  
  /*
  * Noekeon's Theta Operation
  */
  inline void theta(u32bit& A0, u32bit& A1,
                    u32bit& A2, u32bit& A3,
                    const u32bit EK[4])
     {
     u32bit T = A0 ^ A2;
     T ^= rotate_left(T, 8) ^ rotate_right(T, 8);
     A1 ^= T;
     A3 ^= T;
  
     A0 ^= EK[0];
     A1 ^= EK[1];
     A2 ^= EK[2];
     A3 ^= EK[3];
  
     T = A1 ^ A3;
     T ^= rotate_left(T, 8) ^ rotate_right(T, 8);
     A0 ^= T;
     A2 ^= T;
     }
  
  /*
  * Theta With Null Key
  */
  inline void theta(u32bit& A0, u32bit& A1,
                    u32bit& A2, u32bit& A3)
     {
     u32bit T = A0 ^ A2;
     T ^= rotate_left(T, 8) ^ rotate_right(T, 8);
     A1 ^= T;
     A3 ^= T;
  
     T = A1 ^ A3;
     T ^= rotate_left(T, 8) ^ rotate_right(T, 8);
     A0 ^= T;
     A2 ^= T;
     }
  
  /*
  * Noekeon's Gamma S-Box Layer
  */
  inline void gamma(u32bit& A0, u32bit& A1, u32bit& A2, u32bit& A3)
     {
     A1 ^= ~A3 & ~A2;
     A0 ^= A2 & A1;
  
     u32bit T = A3;
     A3 = A0;
     A0 = T;
  
     A2 ^= A0 ^ A1 ^ A3;
  
     A1 ^= ~A3 & ~A2;
     A0 ^= A2 & A1;
     }
  
  }
  
  /*
  * Noekeon Round Constants
  */
  const byte Noekeon::RC[] = {
     0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,
     0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A,
     0xD4 };
  
  /*
  * Noekeon Encryption
  */
  void Noekeon::encrypt_n(const byte in[], byte out[], size_t blocks) const
     {
     for(size_t i = 0; i != blocks; ++i)
        {
        u32bit A0 = load_be<u32bit>(in, 0);
        u32bit A1 = load_be<u32bit>(in, 1);
        u32bit A2 = load_be<u32bit>(in, 2);
        u32bit A3 = load_be<u32bit>(in, 3);
  
        for(size_t j = 0; j != 16; ++j)
           {
           A0 ^= RC[j];
           theta(A0, A1, A2, A3, &EK[0]);
  
           A1 = rotate_left(A1, 1);
           A2 = rotate_left(A2, 5);
           A3 = rotate_left(A3, 2);
  
           gamma(A0, A1, A2, A3);
  
           A1 = rotate_right(A1, 1);
           A2 = rotate_right(A2, 5);
           A3 = rotate_right(A3, 2);
           }
  
        A0 ^= RC[16];
        theta(A0, A1, A2, A3, &EK[0]);
  
        store_be(out, A0, A1, A2, A3);
  
        in += BLOCK_SIZE;
        out += BLOCK_SIZE;
        }
     }
  
  /*
  * Noekeon Encryption
  */
  void Noekeon::decrypt_n(const byte in[], byte out[], size_t blocks) const
     {
     for(size_t i = 0; i != blocks; ++i)
        {
        u32bit A0 = load_be<u32bit>(in, 0);
        u32bit A1 = load_be<u32bit>(in, 1);
        u32bit A2 = load_be<u32bit>(in, 2);
        u32bit A3 = load_be<u32bit>(in, 3);
  
        for(size_t j = 16; j != 0; --j)
           {
           theta(A0, A1, A2, A3, &DK[0]);
           A0 ^= RC[j];
  
           A1 = rotate_left(A1, 1);
           A2 = rotate_left(A2, 5);
           A3 = rotate_left(A3, 2);
  
           gamma(A0, A1, A2, A3);
  
           A1 = rotate_right(A1, 1);
           A2 = rotate_right(A2, 5);
           A3 = rotate_right(A3, 2);
           }
  
        theta(A0, A1, A2, A3, &DK[0]);
        A0 ^= RC[0];
  
        store_be(out, A0, A1, A2, A3);
  
        in += BLOCK_SIZE;
        out += BLOCK_SIZE;
        }
     }
  
  /*
  * Noekeon Key Schedule
  */
  void Noekeon::key_schedule(const byte key[], size_t)
     {
     u32bit A0 = load_be<u32bit>(key, 0);
     u32bit A1 = load_be<u32bit>(key, 1);
     u32bit A2 = load_be<u32bit>(key, 2);
     u32bit A3 = load_be<u32bit>(key, 3);
  
     for(size_t i = 0; i != 16; ++i)
        {
        A0 ^= RC[i];
        theta(A0, A1, A2, A3);
  
        A1 = rotate_left(A1, 1);
        A2 = rotate_left(A2, 5);
        A3 = rotate_left(A3, 2);
  
        gamma(A0, A1, A2, A3);
  
        A1 = rotate_right(A1, 1);
        A2 = rotate_right(A2, 5);
        A3 = rotate_right(A3, 2);
        }
  
     A0 ^= RC[16];
  
     DK[0] = A0;
     DK[1] = A1;
     DK[2] = A2;
     DK[3] = A3;
  
     theta(A0, A1, A2, A3);
  
     EK[0] = A0;
     EK[1] = A1;
     EK[2] = A2;
     EK[3] = A3;
     }
  
  /*
  * Clear memory of sensitive data
  */
  void Noekeon::clear()
     {
     zeroise(EK);
     zeroise(DK);
     }
  
  }
  